JSON 을 받아오지 못하는 오류 + FSM 대쉬 구현중 쿨타임 오류
1. JSON을 받아오지 못하는 오류
1. 문제점
역직렬화 해서 FromJson으로 JSON파일을 파싱하는 것까지는 했으나, 이를 받아오지 못하는 버그가 있었다.
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class JsonReader : MonoBehaviour
{
public PlayerSO PlayerSO;
private void Awake()
{
// JSON 파일 경로 설정
string jsonFilePath = "Assets/Resources/JSON/PlayerData.json";
// JSON 파일에서 데이터 읽기
string jsonText = File.ReadAllText(jsonFilePath);
PlayerJsonData playerJsonData = JsonUtility.FromJson<PlayerJsonData>(jsonText);
PlayerSO.SetPlayerData(playerJsonData.PlayerData);
}
}
{
"PlayerData": {
"PlayerName": "플레이어 이름",
"PlayerLevel": 1,
"PlayerMaxHealth": 100,
"PlayerMaxStamina": 100,
"PlayerAttack": 10,
"PlayerDef": 5,
"PlayerExp": 0,
"PlayerGold": 100
}
}
playerJsonData 변수에 값까지는 들어오는데 그 다음에 null로 값을 받아오지 못했다.
2. 시도했던 것
1) NewtonSoft.Json 활용
JSON 파일과 Key값이 일치하지 않는것에 대한 문제가 있지 않았을 까 하는 생각이 들어 찾아보니 NewtonSoft.Json으로 따로 JSON 에서 받을 때 변수명을 정해줄 수 있는 기능이 있다고 하여 사용해봤다.
//[SerializeField]
//[JsonProperty("PlayerName")]
//private string _playerName;
//[SerializeField]
//[JsonProperty("PlayerLevel")]
//private int _playerLevel;
//[SerializeField]
//[JsonProperty("PlayerMaxHealth")]
//private float _playerMaxHealth;
//[SerializeField]
//[JsonProperty("PlayerMaxStamina")]
//private float _playerMaxStamina;
//[SerializeField]
//[JsonProperty("PlayerAttack")]
//private float _playerAttack;
//[SerializeField]
//[JsonProperty("PlayerDef")]
//private float _playerDef;
//[SerializeField]
//[JsonProperty("PlayerExp")]
//private float _playerExp;
//[SerializeField]
//[JsonProperty("PlayerGold")]
//private float _playerGold;
결과는 이렇게 해도 키값이 맞지 않는지 되지 않았다.
2) 프로퍼티 활용
[SerializeField] private string playerName;
[SerializeField] private int playerLevel;
[SerializeField] private int playerMaxHealth;
[SerializeField] private int playerMaxStamina;
[SerializeField] private int playerAttack;
[SerializeField] private int playerDef;
[SerializeField] private int playerExp;
[SerializeField] private int playerGold;
// Properties
public string PlayerName
{
get { return playerName; }
set { playerName = value; }
}
public int PlayerLevel
{
get { return playerLevel; }
set { playerLevel = value; }
}
public int PlayerMaxHealth
{
get { return playerMaxHealth; }
set { playerMaxHealth = value; }
}
public int PlayerMaxStamina
{
get { return playerMaxStamina; }
set { playerMaxStamina = value; }
}
public int PlayerAttack
{
get { return playerAttack; }
set { playerAttack = value; }
}
public int PlayerDef
{
get { return playerDef; }
set { playerDef = value; }
}
public int PlayerExp
{
get { return playerExp; }
set { playerExp = value; }
}
public int PlayerGold
{
get { return playerGold; }
set { playerGold = value; }
}
결과는 동일하게 null 이 떴다.
3. 해결
1. 시트 이름을 삭제
JSON의 시트 이름을 삭제하니 잘 들어온 경우이다.
{
"PlayerName": "플레이어 이름",
"PlayerLevel": 1,
"PlayerMaxHealth": 100,
"PlayerMaxStamina": 100,
"PlayerAttack": 10,
"PlayerDef": 5,
"PlayerExp": 0,
"PlayerGold": 100
}
이렇게 시트의 이름을 삭제하니 문제없이 잘 들어온다.
2. 시트이름이 있는 경우
그렇다면 시트 이름이 있는 경우에는 어떤식으로 할 수 있을까?
JSON 파일을 C# 으로 변환해주는 사이트가 있다.
Convert JSON to C# Classes Online - Json2CSharp Toolkit
json2csharp.com
이렇게 형식을 변환하니 Root 클래스가 따로 나와주는데 안에 있는 PlayerData 변수명과 시트이름의 변수명을 맞춰주면 해결된다.
4. 알게된 점
JSON 을 C#으로 바꿔주는 사이트 덕에 해결된것도 있지만, 시트명으로 문제가 될 수도 있다는 것을 알았고, Key값과 변수명이 같아야한다는 점도 알게되었다.
2. 대쉬 구현 중 쿨타임 오류
1. 문제점
대쉬가 쿨타임이 없이 무한으로 하게 되는 버그가 생겼다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DashForceReceiver : MonoBehaviour
{
private Player _player;
[SerializeField] private float _dashDuration = 0.5f;
[SerializeField] private float _dashCoolTime = 5f;
private float _dashTime = 0f; // 대쉬를 하기위한 시간
private bool _isDash;
public bool IsCoolTime { get; private set; } // true => 쿨타임 중
//private Vector3 _dashStartPosition;
//private Vector3 _dashTargetPosition;
private void Start()
{
_player = GetComponent<Player>();
IsCoolTime = false;
_isDash = false;
}
void FixedUpdate()
{
if(_isDash)
{
_dashTime += Time.fixedDeltaTime;
if(_dashTime >= _dashDuration )
{
_isDash = false;
if (!IsCoolTime)
StartCoroutine(CoolDown());
}
}
}
public void Dash(float dashForce)
{
if (_player.GroundCheck.IsGrounded() && !_isDash && !IsCoolTime)
{
_isDash = true;
_dashTime = 0f;
StartCoroutine(DashCoroutine(dashForce));
}
}
IEnumerator DashCoroutine(float dashForce)
{
Vector3 dashDirection = transform.forward;
Vector3 dashPower = dashDirection;
while (_dashTime <= _dashDuration)
{
dashPower += dashDirection * dashForce;
//* -Mathf.Log(1 / Player.Rigidbody.drag)
//_player.Rigidbody.velocity += dashPower;
_player.Rigidbody.AddForce(dashPower, ForceMode.VelocityChange);
yield return new WaitForSeconds(0.01f);
}
yield return null;
}
IEnumerator CoolDown()
{
IsCoolTime = true;
yield return new WaitForSeconds(_dashCoolTime);
IsCoolTime = false;
}
}
2. 시도했던 것 및 해결
coolTime이 필요한데 coolTime을 따로 처리해주는 시간이 없었다. 그래서 IsCoolTime을 활용해서 true일 때 쿨타임 시간을 돌려서 정해준 쿨타임 시간만큰 갔다면 초기화 시켜주는 식으로 대쉬를 처리했다.
바뀐코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DashForceReceiver : MonoBehaviour
{
private Player _player;
[SerializeField] private float _dashDuration = 0.5f;
[SerializeField] private float _dashCoolTime = 5f;
private float _dashTime = 0f; // 대쉬를 하기위한 시간
private float _coolTime= 0f; // 쿨타임을 계산하기위한 시간
private bool _isDash;
public bool IsCoolTime { get; private set; } // true => 쿨타임 중
//private Vector3 _dashStartPosition;
//private Vector3 _dashTargetPosition;
private void Start()
{
_player = GetComponent<Player>();
IsCoolTime = false;
_isDash = false;
}
void FixedUpdate()
{
if(_isDash)
{
_dashTime += Time.fixedDeltaTime;
if(_dashTime >= _dashDuration )
{
_isDash = false;
if (!IsCoolTime)
StartCoroutine(CoolDown());
}
// 쿨타임을 위한 계산
else if (IsCoolTime)
{
_coolTime += Time.fixedDeltaTime;
if(_coolTime >= _dashCoolTime)
{
IsCoolTime = false;
_coolTime = 0f;
}
}
}
}
public void Dash(float dashForce)
{
if (_player.GroundCheck.IsGrounded() && !_isDash && !IsCoolTime)
{
_isDash = true;
_dashTime = 0f;
StartCoroutine(DashCoroutine(dashForce));
}
}
IEnumerator DashCoroutine(float dashForce)
{
Vector3 dashDirection = transform.forward;
Vector3 dashPower = dashDirection;
while (_dashTime <= _dashDuration)
{
dashPower += dashDirection * dashForce;
//* -Mathf.Log(1 / Player.Rigidbody.drag)
//_player.Rigidbody.velocity += dashPower;
_player.Rigidbody.AddForce(dashPower, ForceMode.VelocityChange);
yield return new WaitForSeconds(0.01f);
}
yield return null;
}
IEnumerator CoolDown()
{
IsCoolTime = true;
yield return new WaitForSeconds(_dashCoolTime);
IsCoolTime = false;
}
}
3. 알게된 것
인스펙터의 디버그 창으로 IscoolTime을 처리해주는 bool 체크가 이상하다는 것을 보고 따로 처리해주는 것이 필요하다고 깨닫고 이를 처리해줬다.
그리고 대쉬 뿐만아니라 쿨타임도 함께 체크해야한다는 점을 간과했는데 모종의 변수를 어느정도 생각하고 코드를 짜야겠다는 생각이 들었다.