ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스파르타 3D 서바이벌 게임 / 아이템 만들기 / 유니티 숙련주차
    스파르타 게임 개발 2024. 6. 4. 01:11

    아이템 스크립트를 만들고 아이템을 레이캐스트를 이용하여 상호작용 하게끔 만들자. 

     

    먼저 아이템은 데이터들을 갖고 있다. 아이템의 이름, 효과, 설명 등등을 갖고 있고 이걸 ScriptableObject로 만들어서 관리 하고 아이템 오브젝트 클래스에서 아이템을 작성해준다. 아이템오브젝트는 아이템데이터를 갖고 있고, 아이템 사용과 아이템의 설명이 나오게 하는 함수를 인터페이스 형식으로 갖고 있다. 그리고 상호작용 하는 클래스를 만들고, 거기서 레이캐스트를 계속 해서 쏴서 아이템에 마우스를 갖다대면 아이템의 정보가 나오고, 특정 키를 누르면 아이템을 줍게 하는 기능을 만들자. 

     

    먼저 ScriptableObject를 이용하여 데이터를 관리 하는 이유에 대해서, 그것은 관리하기 더욱 편하기 때문이라고 할 수 있다.

     

    우리는 아이템들을 만들 때 만약에 공통 된 능력치들이 있고 종류마다 다르다면, 보통 능력치를 포함 할 클래스를 하나 만들고 상속을 통해서 새로운 클래스를 만들어서 아이템 종류에 맞는 클래스를 만들었을 것이다. 하지만 이렇게 할 경우 아이템마다 클래스를 계속 만들어야 해서 스크립트가 많아져 관리가 힘들어질 수가 있다. 

     

    그래서 ScriptableObject를 이용 하여 관리를 하게 되면 이 에셋을 추가해서 능력치들을 바꿔주고 넣어주는 것으로 스크립트를 줄일 수가 있게 된다. 

     

    물론 스크립트를 따로 작성 해야 하는 경우도 있겠지만, 이 부분을 잘 생각하면서 아이템을 만들어 줄 때 적절한 방법을 선택 해서 코드를 구성 하면 될 것이다. 

     

    지금 같은 경우는 ScirptableObject로 충분히 아이템들을 다 구현을 할 수 있다. 아이템의 효과, 설명, enum을 이용한 아이템 타입별 어떻게 사용 되는지, 공격력 등을 담게 해서 추가적인 Script 추가 없이 관리하기 쉽게 만들 수가 있다. 그렇기에 ScriptableObject를 사용 한다.

     

    그래서 먼저 아이템이 갖고 있는 Data 클래스를 먼저 만들어 준다. 

     

    우선 enum을 이용하여 아이템의 타입들을 만들어 준다. 

     

    public enum ItemType
    {
        Equipable,
        Consumable,
        Resource
    }

     

    라는 enum을 활용해서 아이템이 장착용인지 소모품인지, 자원인지 확인 하고 그에 맞는 효과가 적용 되게 해줄 것이다.

     

    그리고 소모품일 경우에 회복이 되는 경우 어떤 게 회복이 되는지에 대한 enum도 만들어 준다. 

     

    public enum ConsumableType
    {
        Health,
        Hunger
    }

     

    이렇게 만들어 줘서 체력과 스테미나가 회복이 되는 타입도 만들어 준다. 

     

    [Serializable]
    public class ItemDataConsumbale
    {
        public ConsumableType type;
        public float value;
    }

     

    그리고 위 코드와 같이 작성을 해서 소모품의 타입별 회복이 되는 value도 입력을 하게 해준다. 

     

    그리고 이제 이 enum과 클래스를 활용 할 ItemData 클래스를 만들어 준다. 이 클래스는 ScriptablObject로 관리 해줄 것이므로 MonoBehaviour를 상속 받지 않고 ScriptableObject를 상속 받는다. 

     

    그리고 클래스 상단에 [CreateAssetMenu(fileName = " Item", menuName = "New Item")] 를 적어줘서 에셋을 만들 수 있게 해준다. 

     

    public class ItemData : ScriptableObject
    {
        [Header("Info")]
        public string displayName;
        public string description;
        public ItemType type;
        public Sprite icon;
        public GameObject dropPrefab;

        [Header("Stacking")]
        public bool canStack;
        public int maxStackAmount;

        [Header("Consumable")]
        public ItemDataConsumbale[] consumables;

        [Header("Equip")]
        public GameObject equipPrefab;
    }

     

    그리고 위와 같이 코드를 작성 해준다. 

     

    여기서 Info에서는 아이템의 기본적인 정보들을 담게 해주고, canStack이라는 bool자료형을 볼 수가 있는데 이것은 아이템이 가방에 중첩해서 쌓일 수 있는지에 대한 자료형이다. 만약 스텍이 가능한 아이템이라면 가방 한 칸에 여러개가 쌓이게 할 것이다. 그리고 maxStack만큼.

     

    그리고 Consumable을 배열로써 만들어져 있는 것을 확인 할 수가 있는데 이 것은 소모품은 체력과 스테미나를 동시에 회복 하는 아이템이 있을 수가 있다. 그래서 배열로써 만들어서 체력회복하는 소모품, 스테미나 회복 하는 소모품 등을 동시에 적용 시키게 하기 위해서다. 

     

    그리고 Equip 프리펩 같은 경우는 밖에 생성 돼있는 아이템오브젝트와 플레이어가 들고 있는 프리펩의 정보가 좀 다르다. 그래서 다르게 설정 하기 위해 따로 만들어 준다. 

     

    그리고 이제 이 아이템 Data를 포함하는 오브젝트 클래스를 만들어 준다. 

     

    public class ItemObject : MonoBehaviour
    {
        public ItemData data;

    }

     

    일단 이렇게 만들어 주면 Inspector에서 ScriptableObject를 넣을 수 있게 되고 이 아이템 오브젝트 스크립트를 넣은 오브젝트에 알맞는 스크립터블오브젝트를 넣어주면 될 것이다. 

     

    그리고 이 아이템 오브젝트는 2가지의 기능을 줄 것이다. 아이템의 설명이 나오게끔 하는 기능과 아이템을 클릭 했을 경우에 상호작용이 되게 하는 기능인데 이 기능들은 모든 아이템오브젝트가 사용 하는 것이므로 Interface를 통해 만들어 준다. 그래서 Interface를 만들어준다. // 인터페이스로 만드는 이유는 코드를 작성 할 때 매우 편리 해질 수가 있다. 우리는 코드를 작업 할 때 객체를 생성을 해줘야 하는 경우가 생기는데 이 때 Interface형 객체를 생성 해주면 이 Interface를 상속 받은 모든 클래스의 객체를 생성해 참조를 하게 할 수가 있기에 매우 편리해질 수가 있다. 물론 사용 하는 것은 Interface에 있는 함수들만 사용이 가능하다. // 이처럼 기능은 똑같은데 아이템의 종류나 객체의 종류마다 다르게 생성을 해서 함수를 사용 해야 하는 경우에 매우 유용하다. 굳이 도끼의 상호작용 함수를 호출 하기 위해서 어떠한 번거로운 작업을 하지 않고 그냥 Interface를 사용해서 상호작용 함수를 사용 하면 된다.

     

    public interface IInteractable
    {
        public string GetInteractPrompt();
        public void OnInteract();
    }

     

    이렇게 interface를 작성 해줘서 아이템 설명 표시와 상호작용을 하게 하는 Interface를 만들어 준다. 그리고 ItemObject가 상속 받고 이 기능들을 구현 하면 된다. 

     

    public class ItemObject : MonoBehaviour, IInteractable
    {
        public ItemData data;

        public string GetInteractPrompt()
        {
            string str = $"{data.displayName}\n{data.description}";
            return str ;
        }

        public void OnInteract()
        {
            CharacterManager.Instance.Player.itemData = data;
            CharacterManager.Instance.Player.addItem?.Invoke();
            Destroy(gameObject);
        }
    }

     

    이렇게 생성을 해준다. GetInteractPrompt은 반환형 함수로 만들어서 str문자열을 보간을 사용해서 아이템의 이름과 설명이 나오게 하는 함수를 만들어 준다. 

     

    그리고 OnInteract 함수는 클릭 한 아이템이 싱글턴 변수에 저장이 되게 하고, 그 싱글턴에 있는 addItem 함수를 호출 하고 클릭이 된 오브젝트를 파괴 하게 한다. 

    아이템을 줍고 가방에 들어가게 하는 로직을 실행 하고 필드에 있는 아이템은 파괴 시키게 하는 것이다. 

     

    이렇게 해주면 아이템 오브젝트에 대한 Script 작업은 끝이 나게 된다. 이제 아이템 오브젝트들을 만들어서 적용 시켜주면 된다. 

     

    예를 들어서 도끼 하나만 작성을 하겠다. 우선 도끼 Scriptabl Object를 만들어 준다. 

     

    에셋추가를 통해 만들어둔 ScriptablObject를 만들어 주고 Item_Ax로 해준 다음에 알맞은 데이터값을 입력 해준다.

    도끼는 장비이므로 중첩해서 쌓일 수가 없다. 그래서 체크해제, 그리고 소모품이 아니기에 Consumable도 넣지 않는다. 그리고 장착용 장비이므로 장착 했을 때의 장비프리펩도 넣어주면 된다. 

     

    그리고 이 ScriptablObject를 도끼 오브젝트에 넣어주면 된다. 그러기 위해서 도끼 오브젝트에는 ItemObject Script를 추가 시켜줘야 한다. 

    이렇게 스크립트를 추가 시켜주고 ScriptablObject를 넣어주면 된다. 

     

    그리고 이걸 맵에다가 생성을 한 후에, 우린 이제 이 아이템에 마우스를 갖다대면 마우스의 설명이 나오고 특정 키를 누르면 이 아이템을 가방에 넣는 로직을 만들어 주면 된다. 

Designed by Tistory.