[25.04.16] TIL( 개인 프로젝트 )

설민우·2025년 4월 16일

내일배움캠프 - Unity

목록 보기
23/85
post-thumbnail

[ 개인 프로젝트 ]

도전 기능 거~의 완성

도전 기능의 상점 판매하기, 저장하기 기능을 제외한 모든 기능을 제작 완료하였습니다.

< 구현 내역 >

던전 입장 및 클리어 보상 획득. 휴식, 레벨업, 장착 개선 기능을 추가 완료했습니다.

1. 던전

 {
   "Idx": 1,
   "Name": "쉬운 던전",
   "Defense": 5,
   "Gold": 1000,
   "DefenseProbability": 0.4,
   "FailHealthDivied": 2,
   "MinUseHp": 20,
   "MaxUseHp": 35,
   "GoldRatio": 2
 },
  • 구체적인 내요은 그다지 볼 게 없고, 던전 또한 Json 파일을 읽어와 정보를 반영하도록 했습니다.
  • 이를 통해 추후에 원하는 던전을 추가하거나, 설정값을 변경하기 용이합니다.

2. 장착 개선

        public static void EquipItem(int index)
        {
            Item item = inventory[index - 1];
            //토글
            item.TogleEquipState();

            // 장착 해제에 따른 효과 반영
            if (equipDict.ContainsKey(item._itemType)) // 해당하는 타입이 있다면 장착해제 후 장착
            {
                var ChangeItem = equipDict[item._itemType];
                ChangeItem.TogleEquipState();
                ActiveItemEffect(ChangeItem);
                equipDict[item._itemType] = item;
            }
            else
            {
                equipDict.Add(item._itemType, item);
            }
            ActiveItemEffect(item);
        }
  • 장착 개선은 이전에 그래도 코드를 잘 작성해두어서 그런지 간단하게 적용이 가능했습니다. 장착 Dict 를 별도로 선언하고, Type을 Key로 받아서 이미 해당 Key에 Value가 존재한다면 그 Value를 토글시키고, 새로 들어온 Item 으로 변경해주는 방식으로 구현했습니다.

    < 변경 내역 >

1. Json 을 이용한 방식으로 UI 표현

  "Intro": {
    "intro_welcome": "스파르타 던전에 오신 여러분 환영합니다\n원하시는 닉네임을 설정해 주세요\n>>",
    "choose_job": "원하시는 직업을 설정해 주세요 :\n1. 전사  2. 마법사  3. 도적\n>>"
  },
  "Town": {
    "town_welcome": "스파르타 마을에 오신 여러분 환영합니다\n이곳에서 던전으로 들어가기 전 활동을 할 수 있습니다\n>>",
    "town_select": "1. 상태보기\n2. 인벤토리\n3. 상점\n4. 던전입장\n5. 휴식하기\n원하시는 행동을 입력해 주세요\n>>"
  },
    public class SceneTextData
    {
        public IntroText Intro { get; set; }
        public TownText Town { get; set; }
        public StatText Stat { get; set; }
        public InventoryText Inventory { get; set; }
        public ShopText Shop { get; set; }
        public DungeonText Dungeon { get; set; }
        public RestoreText Restore { get; set; }
        public ETCText ETC { get; set; }
        public ErrorText Error { get; set; }
    }
    public class IntroText
    {
        public string intro_welcome { get; set; }
        public string choose_job { get; set; }
    }
  • 위와 같은 방식으로 Json에서 UI 에 해당하는 스크립트를 읽어와서 간단하게 배정 할 수 있게 함으로써, string 값들이 덕지덕지 붙어있는 것을 피할 수 있었습니다
  • 하지만 위의 방법의 경우 문제가 하나 있었는데, 바로 ${} 포멧팅을 사용할 수 없다는 점입니다. 이를 해결하기 위해서 별도의 포맷 함수를 작성해주었습니다.
        public static string FormatText(string template, Dictionary<string, string> dict)
        {
            foreach (var pair in dict)
            {
                template = template.Replace("{" + pair.Key + "}", pair.Value);
            }
            return template;
        }
           dungeonFormat.Add( new Dictionary<string, string>()
           {
                {"idx", value.Idx.ToString()},
               {"name", value.Name},
               {"defense", value.Defense.ToString()}
           });
  • 위와 같이 사전에 등록해 두면 FormatText 함수를 통해 해당 string 값을 원하는 값으로 변경해줍니다.

2. Stat 클래스 생성

using System;
using System.Collections.Generic;
using System.Text;
using System.Numerics;

namespace TextRpg
{
    interface IAddable<T>
    {
        T Add(T other);
    }
    class StatFloat : IAddable<StatFloat>
    {
        public float Value { get; }

        public StatFloat()
        {
            Value = 0f;
        }
        public StatFloat(float value)
        {
            Value = value;
        }

        public StatFloat Add(StatFloat other)
        {
            return new StatFloat(this.Value + other.Value);
        }
    }

    abstract class Stat<T> where T : IAddable<T>, new()
    {
        public T _baseValue { get; protected set; }
        public T _addValue { get; protected set; }

        // 생성자에서 기본값을 설정
        public Stat(T value)
        {
            _baseValue = value;
            _addValue = new T(); 
        }

        // 최종 값을 구하는 프로퍼티
        public T FinalValue => _baseValue.Add(_addValue);

        // 기본값과 추가값을 반환하는 메서드
        public T GetBaseValue() => _baseValue;
        public T GetAddValue() => _addValue;
        public T GetFinalValue() => FinalValue;

        // 기본값 설정
        public void SetBaseValue(T value)
        {
            _baseValue = value;
        }

        // 추가값 설정
        public void SetAddValue(T value)
        {
            _addValue = _addValue.Add(value); // Add 연산을 호출
        }

    }
}
  • 단순히 Stat 클래스의 생성 뿐만 아니라, Stat 제네릭 타입으로 생성하고 싶었는데, 이 방식에서는 문제점이 다수 있었습니다. 이에 대한 내용을 정리해 보자면 아래와 같습니다.
  • 문제점 : 제네릭 T 타입에서는 이 타입이 연산이 가능한지 알 수 없기 때문에, + -등을 사용할 수 없었습니다
  • 시도해본것 : 우선은 별도의 StatFloat 함수를 만들까 고민했지만 코드 반복이 계속될 것 같아 다른 방법을 찾아보려고 검색을 돌렸습니다
  • 해결 방법 : 여러가지 해결 방법이 있었는데, 총 3가지가 있었고, 각각의 대표적인 문제는 아래와 같았습니다.
    - INumber : .NET 7 이상에서만 사용 가능
    - object 캐스팅 : 박싱 문제 발생
    - 별도의 인터페이스 제작 : 별도의 포장이 필요함
  • 알게된 것 : 만능처럼 보이는 제네릭 타입을 다루는 것도 생각보다 많은 주의가 필요하다는 것을 알게 되었습니다. 또, 이를 해결하기 위한 인터페이스 구현도 마냥 단순하지만은 않아 앞으로도 해당 파트에 대한 더 많은 공부가 필요 할 것이라고 생각합니다.
  • 기본의 .NET 버전을 바꾸고 싶지는 않고 박싱 문제도 싫어서 다소 코드가 장황해질 수 있지만 인터페이스를 제작해 주는것으로 작업했습니다.

3. DataLoader 수정

      public static T LoadData<T>(string path)
      {
          string json = File.ReadAllText(path);
          return JsonConvert.DeserializeObject<T>(json);
      }
  • 데이터 로더의 변경사항은 더욱 단순합니다. 기존에는 각 데이터 타입에 따른 로더를 개별로 만들어주었는데 제네릭 타입으로 뭉쳐 하나로 제작했습니다.

    추가 +)

    오늘도 개인 프로젝트를 진행하다 보니 별도의 CS 공부는 못했는데 내일은 정말로 개인프로젝트를 마무리 짓고 강의 및 CS 공부를 다시해야겠습니다...
profile
클라이언트 개발자를 지망하고 있습니다.

0개의 댓글