[Unity]TIL (42) | 2023.09.20 | 유니티 스탯 만들기

kjg5370·2023년 9월 20일
0

TIL

목록 보기
42/91
post-thumbnail

들어가기 앞서

오늘부터 개인 과제를 해보았습니다. 일단 강의는 다 듣지는 못했지만
2D부분은 다 들었기 때문에 강의에서 배운 스크립터블 오브젝트를 이용하여
캐릭터의 스탯을 보여주는 기능을 만들어보았습니다.

오늘 배운 것

  • 스크립터블 오브젝트 활용
    일단 캐릭터에 공통적으로 들어가는 스탯을 StatSo라는 스크립터블 오브젝트로 만들어보았습니다.

  • StatSO.cs

    [CreateAssetMenu(fileName = "DefaultStatData", menuName = "SpartaDungeonUnity/Stats/Default", order = 0)]
     public class StatSO : ScriptableObject
     {
         [Header("Stat Info")]
         public float Atk;
         public float Def;
         public float Health;
         public float Critical;
     }

    그리고 직업마다 스탯을 다르게 하고 싶어서 이 StatSO를 상속 받는 JobStatData를 만들었습니다.

  • JobStatData.cs

    [CreateAssetMenu(fileName = "JobStatData", menuName = "SpartaDungeonUnity/Stats/Job", order = 1)]
     public class JobStatData : StatSO
     {
         [Header("Job Stat Data")]
         public string JobName;
         public string Descript;
     }

    일단 JobStatData로 스크립터블 오브젝트를 하나 만들었습니다.

    그리고 캐릭터의 스탯을 가지고 있는 CharacterStats스크립트를 만듭니다.

  • CharacterStats.cs

        public enum StatsChangeType
       {
           Add,
           Multiple,
           Override,
       }
    
       [Serializable]
       public class CharacterStats
       {
           public StatsChangeType statsChangeType;
           public string characterName;
           public int level;
           public int exp;
           public int gold;
           public StatSO statSO;
       }

    캐릭터는 고유의 이름, 레벨, 경험치, 골드, 그리고 스탯 데이터를 가지고 있고 이 스탯들을 더하거나 곱하거나 덮어씌울 수 있습니다.
    그리고 이 데이터를 관리하는 CharacterStatsHandler를 만들고 플레이어에게 부여해줍니다.

  • CharacterStatsHandler.cs

      public class CharacterStatsHandler : MonoBehaviour
      {
         [SerializeField] private CharacterStats baseStats;
         public CharacterStats CurrentStats { get; private set; }
    
         public event Action OnLevelUP;
    
         public List<CharacterStats> statsModifiers = new List<CharacterStats>();
    
    
         private void Awake()
         {
             UpdateCharacterStats();
         }
    
         private void UpdateCharacterStats()
         {
             StatSO statSO = null;
             if (baseStats.statSO != null)
             {
                 statSO = Instantiate(baseStats.statSO);
             }
    
             CurrentStats = new CharacterStats { statSO = statSO };
             // TODO
             CurrentStats.statsChangeType = baseStats.statsChangeType;
             CurrentStats.characterName = baseStats.characterName;
             CurrentStats.level = baseStats.level;
             CurrentStats.exp = baseStats.exp;
             CurrentStats.gold = baseStats.gold;
    
             while (true)
             {
                 if(CurrentStats.exp < CurrentStats.level +2)
                 {
                     break;
                 }
                 CurrentStats.exp -= CurrentStats.level + 2;
                 CurrentStats.level++;
                 OnLevelUP?.Invoke();
             }
         }
    }

    이것을 플레이어에게 붙혀주면 이름, 레벨 가지고있는 경험치, 골드 등을 초기화할 수 있습니다.
    그리고 게임 매니저를 만들어서 화면에 있는 UI들에게 스탯이나 이름 등의 값을 전달해 주었습니다.

  • GameManager.cs

    public class GameManager : MonoBehaviour
    {
        public static GameManager instance;
    
        public GameObject Player { get; private set; }
        [SerializeField] private string playerTag = "Player";
    
        private CharacterStatsHandler _statsHandler;
    
        [SerializeField] private TextMeshProUGUI jobText;
        [SerializeField] private TextMeshProUGUI nameText;
        [SerializeField] private TextMeshProUGUI levelText;
        [SerializeField] private TextMeshProUGUI expText;
        [SerializeField] private TextMeshProUGUI descriptText;
        [SerializeField] private TextMeshProUGUI goldText;
        [SerializeField] private Slider expGaugeSlider;
    
        private void Awake()
        {
            instance = this;
    
            Player = GameObject.FindGameObjectWithTag(playerTag);
            _statsHandler = Player.GetComponent<CharacterStatsHandler>();
            _statsHandler.OnLevelUP += UpdateExpUI;
        }
    
        void Start()
        {
            JobStatData jobStatData = _statsHandler.CurrentStats.statSO as JobStatData;
            jobText.text = jobStatData.JobName;
            nameText.text = _statsHandler.CurrentStats.characterName;
            levelText.text = _statsHandler.CurrentStats.level.ToString();
            expText.text = $"{_statsHandler.CurrentStats.exp} / {_statsHandler.CurrentStats.level + 2}";
            descriptText.text = jobStatData.Descript;
            goldText.text = _statsHandler.CurrentStats.gold.ToString();
        }
    
        private void UpdateExpUI()
        {
            float gauge =_statsHandler.CurrentStats.exp / (float)(_statsHandler.CurrentStats.level + 2);
            expGaugeSlider.value = gauge;
        }
    }

    게임 매니저에 이렇게 데이터를 많이 연결 시켜놓는게 좋아보이지는 않지만 일단 보이는데는 문제 없으므로 이렇게 해놓게 되었습니다.
    결과창입니다.

    원하는 값들이 잘 출력이 되는 모습니다. UI에 값을 전달하는 방법이 더 효율적인 것이 있는지 좀 더 찾아보겠습니다.

기억 할 것 & 진행 사항

  • 스크립터블 오브젝트

    유니티에서 제공하는 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너.
    프로젝트의 메모리 사용을 줄일 수 있음.
    모노비헤이비어(MonoBehaviour) 스크립트에 변경되지 않는 데이터를 저장하는 프리팹을 사용하는 프로젝트에서 유용.

  • 작동 방식
    변경되지 않는 데이터를 사용하는 프리팹의 데이터를 일반 변수로 구현할 경우, 인스턴스화 할때마다 프리팹에 이 데이터에 대한 자체 사본이 생성됨.
    스크립터블 오브젝트를 사용하면 메모리에 스크립터블 오브젝트의 데이터 사본만을 저장하고 이를 참조하는 방식으로 작동.
    모노비헤이비어와 달리, 게임 오브젝트에 컴포넌트로 부착할 수 없고, 프로젝트에 에셋으로 저장.

내일 할 일

  • 하루 계획
    • 오전
      • 09:00 ~ 10:00 : 알고리즘 코드카타
      • 10:00 ~ 10:30 : 팀 회의
      • 10:30 ~ 14:00 :
        • 오늘 계획 (Task)
          • 개인 과제 완성
      • 12시-1시: 점심식사
    • 집중 코딩
      • 14:00 ~ 18:00
    • 저녁
      • 6시-7시: 저녁식사
      • 19:00 ~ 20:00 : 집중 코딩 시간 부족한 부분 해결해보기
      • 20:00 ~ 21:00: TIL 작성, 마무리 회고 진행
      • 21:00 : 내일은 위한 휴식!
profile
학생입니다

0개의 댓글