본문 바로가기

Unity/3D Project

3D RPG - 플레이어 정보(Player Status)

캐릭터 구현하기

- 데이터와 관련된 내용들은 PlayerStatus

- 입력 기능들은 Input Manager

- 플레이어의 컨트롤에 관한 내용들은 PlayerController

- 플레이어의 스탯들을 관리하는 내용들은 PlayerEntity

- 플레이어의 스탯들의 종류들은 PlayerOwnedStates

이렇게 각각 분리하여 작성했습니다.

 

- PlayerStatus

플레이어의 정보는 게임 내에서 존재하는 Entity들과 겹치는 정보들을 가지고 있는 abstract(가상 함수)인 BaseEntityStatus 스크립트를 상속받고, PlayerStatus에는 플레이어만 존재하는 정보들을 추가했습니다.

BaseEntityStatus.cs

public abstract class BaseEntityStatus : MonoBehaviour
{
    private string _name;
    private float _walkSpeed;

    private float _currentHp;
    private float _maxHp;

    private float _attackDamage;
    private float _criticalDamage;
    private float _criticalChance;

    private float _defense;

    private uint _level;
}

BaseEntitystatus 스크립트 중 기본적으로 가지고 있는 엔티티들의 스탯들입니다.

이름, 걷는 속도, 현재 체력, 최대 체력, 공격력, 크리티컬 공격력, 크리티컬 확률, 방어력, 레벨 데이터들을 가집니다.

 

전체 코드

https://github.com/HerFS/Unity-RPG/blob/main/Assets/_Scripts/Status/BaseEntityStatus.cs

 

InitialStatusSetup.cs

public class InitialStatusSetup : ScriptableObject
{
    private string _name;
    private uint _level;
    private float _walkSpeed;
    private float _initialHp;
    private float _attackDamage;
    private float _criticalChance;
    private float _defense;
}

InitialStatus_Player를 PlayerStatus에 추가해서 적용

플레이어의 초기 정보들은 InitialStatusSetup.cs에 기본 정보들을 Scriptabl Object로 초기화를 해줬습니다.

 

전체 코드

https://github.com/HerFS/Unity-RPG/blob/main/Assets/_Scripts/Status/InitialStatusSetup.cs

 

PlayerStatus.cs

public class PlayerStatus : BaseEntityStatus
{
    private string _currentScene;
    private uint _money;

    private float _maxMp;
    private float _currentStamina;
    private float _currentExp;
    private float _currentMp;
    private float _requiredExp;
}

BaseEntityStatus를 상속받은 Playerstatus 스크립트입니다. BaseEntityStatus 기본 정보들을 빼고 추가로 플레이어에게 필요한 스탯들을 추가해줬습니다.

현재 장소, 돈, 현재 마나, 최대 마나, 스테미나(기력), 경험치 데이터들을 가집니다.

 

public class PlayerStatus : BaseEntityStatus
{
    #region Events
    private delegate void StaminaChangedHandler(PlayerStatus playerStatus, float currentStamina, float prevStamina);
    ...
    #endregion
    
    private event StaminaChangedHandler onStaminaChanged;
    ...

    public float CurrentStamina
    {
        get { return _currentStamina; }
        set
        {
            float prevStamina = _currentStamina;
            _currentStamina = Mathf.Clamp(value, 0f, MaxStaminaValue);

            if (_currentStamina != prevStamina)
            {
                onStaminaChanged?.Invoke(this, _currentStamina, prevStamina);
            }
        }
    }
    
    ...
    
    protected override void Awake()
    {
        onStaminaChanged += (playerStatus, currentStamina, prevStamina) =>
        {
            UIManager.Instance.PlayerInfoPanel.StaminaSlider.value = currentStamina;
            DataManager.Instance.PlayerData.CurrentStamina = currentStamina;
            DataManager.Instance.SaveStausData();
        };
        ...
    }
}

 

 

위 코드는 플레이어 스탯 중 하나인 Stamina의 변동을 감지하고 업데이트하는 이벤트 기반 프로그래밍 방식입니다.

 

스태미나 값이 변경될 때마다 직접 추적하지 않고 이벤트 기반으로 업데이트를 처리합니다.

이벤트가 발생하면 UI 업데이트 및 데이터 저장 등의 작업이 수행됩니다.

 

이런 식으로 플레이어 스탯들을 이벤트 기반으로 관리하여 불필요한 업데이트 호출을 최소화했습니다.

이러한 접근 방식은 성능을 최적화하고, 코드의 가독성을 높이는 데 도움을 줬습니다.

 

 

마지막으로, 스탯 중 레벨 업을 했을 때 필요한 경험치를 계산해야하는 작업이 필요합니다.

그런 계산을 하기 위해 다른 게임의 경험치 지표를 참고하여 구현했습니다.

참고 : https://oldschool.runescape.wiki/w/Experience

 

Experience

Experience, commonly abbreviated as EXP or XP, is a measure of progress for skills. It is obtained by performing tasks related to that skill. Experience can also be gained through other means, such as quests, the book of knowledge from the Surprise Exam ra

oldschool.runescape.wiki

 

CalculateRequiredExp.cs

public class CalculateRequiredExp : ScriptableObject
{
    [Header("Multipliers Exp")]
    [Range(1f, 300f)]
    private float _additionMultiplier = 300f;
    [Range(1f, 300f)]
    private float _powerMultiplier = 2f;
    [Range(1f, 300f)]
    private float _divisionMultiplier = 7f;

    public float AdditionMultiplier
    {
        get { return _additionMultiplier; }
        private set { _additionMultiplier = value; }
    }
    public float PowerMultiplier
    {
        get { return _powerMultiplier; }
        private set { _powerMultiplier = value; }
    }
    public float DivisionMultiplier
    {
        get { return _divisionMultiplier; }
        private set { _divisionMultiplier = value; }
    }
}

 

 

PlayerStatus.cs

public class PlayerStatus : BaseEntityStatus
{
    ...
    
    private float CalculationExp()
    {
        int solveForRequiredExp = 0;
        for (int levelCycle = 1; levelCycle <= Level; ++levelCycle)
        {
            solveForRequiredExp += (int)Mathf.Floor(levelCycle + _calculatersExp.AdditionMultiplier * Mathf.Pow(_calculatersExp.PowerMultiplier, levelCycle / _calculatersExp.DivisionMultiplier));
        }

        return (solveForRequiredExp / 4);
    }
    
    ...
}

 

플레이어의 정보들은 Json 파일로 직렬화해서 저장했습니다.

- https://herfs.tistory.com/12

 

전체 코드

https://github.com/HerFS/Unity-RPG/blob/main/Assets/_Scripts/Status/Player/PlayerStatus.cs