내일배움캠프 Unity 15일차 TIL - 팀 조랑말 - 상점 씬 구현

Wooooo·2023년 11월 17일
0

내일배움캠프Unity

목록 보기
17/94

오늘의 키워드

오늘은 팀 과제에 상점 기능과 상점 씬을 추가하는 역할을 맡았다.
Inevntory 작업을 내가 했었어서, 뭔가 내가 상점까지 해야할 것 같아서 회의 때 내가 상점을 맡겠다고 했다.
상점 씬 구현은 다른 분들이 작업하신 코드를 이용해서 작업해야했기에, 내가 짠 코드가 아니라 다른 분들이 짠 코드를 읽고, 해석하는데 집중했다.


다른 사람의 코드 구조 파악하기

1. Scene / SceneManager

Scene과 Scene을 관리하는 SceneManager를 작업해주신 분이 워낙 구조를 잘 설계해 주셨다.
잘 만들어진 엔진을 쓰는 기분..

Scene Class

씬 클래스는 다음과 같은 구조를 가졌다.

    public class Scene {
        public virtual string Title { get; protected set; }

        protected List<ActionOption> Options { get; set; } = new();
        /// <summary>
        /// 씬 진입 시 액션.
        /// </summary>
        public virtual void EnterScene() {

        }
        /// <summary>
        /// 다음 씬으로 넘어가기 위한 조건.
        /// </summary>
        public virtual void NextScene() {

        }
        /// <summary>
        /// 씬 보여주기.
        /// </summary>
        protected virtual void DrawScene() {

        }
    }

화면에 보여줄 선택지의 리스트인 Options와 각 상황별로 실행될 메서드 3개가 간단명료하게 정의돼 있었다.
특히 선택지를 Action<>으로 구현하신 부분이 인상깊었다.

public class ActionOption {
    public string Key { get; private set; }
    public string Description { get; private set; }
    public Action Action { get; private set; }
    public ActionOption(string key, string description, Action action) {
        Key = key;
        Description = description;
        Action = action;
    }

    public void Execute() => Action?.Invoke();
}

선택지를 구분할 Key와 콘솔에 그려질 때 보여질 Description, 그리고 선택지가 선택 됐을 때 실행될 Action의 구조를 가졌다.
이 클래스를 이용해서 어느 씬에서나 범용적으로 사용될 뒤로가기, 특정 씬으로 이동하기 등을 SceneManager를 이용해서 호출할 수도 있고, Scene 클래스를 상속받아 구현한 특정 씬에서만 작동될 특별한 선택지도 만들어서 호출할 수 있었다.
나는 상점 씬을 구현하면서, 상점에서 구매할 수 있는 아이템 리스트를 이 ActionOption 클래스를 이용해서 아이템을 구매하면 캐릭터 인벤토리로 들어가는 ActionOption을 만들어봤다.

for (int i = 0; i < saleItems.Count; i++)
{
	var sales = saleItems[i];
    Options.Add(new("", $"| {i + 1}|", () => { Game.Player.Inventory.Add(sales.DeepCopy()); }));
}

상점의 판매 목록을 받아와서, 실행 시 판매품의 복제품을 캐릭터 인벤토리에 넣어주는 Action을 가진 선택지를 만든다.

SceneManager Class

public class SceneManager {
	...
    
    /// <summary>
    /// 씬을 불러옵니다.
    /// </summary>
    /// <typeparam name="T">씬 타입을 결정합니다.</typeparam>
    /// <param name="sceneKey"></param>
    /// <returns></returns>
    public Scene GetScene<T>(string? sceneKey = null) where T : Scene {
    	...
    }

    /// <summary>
    /// 씬에 진입합니다.
    /// </summary>
    /// <typeparam name="T">씬 타입을 결정합니다.</typeparam>
    /// <param name="sceneKey"></param>
    public void EnterScene<T>(string? sceneKey = null) where T : Scene {
        // #1. Scene 불러오기.
		...
        // #2. 이전 씬 설정.
		...
        // #3. 현재 씬 진입.
        ...
    }
}

Generic을 사용해서 작성하신 모습이다. Generic은 C++의 템플릿과 비슷한 느낌인 것 같다.
EnterScene<T>()과 같은 경우, 내가 구현한 ShopScene으로 씬 전환을 하려면 다음과 같이 작성하면 됐다. >> EnterScene<ShopScene>()

특히, where T : Scene이 부분은, EnterScene을 호출 할 때 지정한 타입이 Scene 클래스를 상속받지 않는다면 안된다는 제약 조건이라고 한다.

이 where 제약조건에 대해서 조금 찾아봤다.

제약조건설명
where T : structT는 값형이어야 함
where T : classT는 참조형이어야 함
where T : new()T는 디폴트 생성자를 가져야 함
where T : MyBaseT는 MyBase를 상속받아야 함
where T : ICompareableT는 ICompareable 인터페이스를 상속받아야 함

마치며

다들 설계를 정말 잘하시는 것 같다.
나는 그저 구조를 파악하고 가져다 쓰면서 감탄만 했다.
정말 많이 배우는 것 같다.

profile
game developer

0개의 댓글