디자인 패턴 중 플라이웨이트 패턴으로 구현된 기능이다. 미리 지정된 데이터들을 가지고 프리팹화 할 수 있다

  • 유니티에서 에셋으로 취급되며, 미리 입력된 데이터를 게임 내에서 유지할 수 있다. 사용하기에 따라 프로젝트 전반에 대한 초기 설정 데이터, 아이템 데이터 테이블 등 유용하게 사용될 수 있는 기능이다

개요

  • 스크립터블 오브젝트(Scriptable Object)는 데이터와 코드를 분리하기 유용한 기능. 프로그램 관리에 있어 데이터와 코드를 분리함으로써 편해진다
  • 예를들어 밸런스 테스트를 위해 스텟을 조절하는 중 이라고 해보자. 캐릭터의 체력이나 공격력같은 스텟이 변수에 적혀있다면, 코드를 직접 수정해야 한다. 코드를 수정하면 컴파일을 하고, 프로젝트가 커질수록 컴파일 하는 시간이 길어지기 때문에 효율이 떨어진다.
  • 하지만 데이터를 프로젝트와 분리한다면 코드를 수정할 필요없이 데이터만 수정하면 되고, 이렇게 되면 빌드하는 시간을 절약할 수 있다. 뿐만 아니라 라이브 중인 게임의 데이터를 변경할 때에도 데이터만 수정해서 배포할 수 있기 때문에 유용하다. 로컬이 아닌 서버에서 데이터를 관리한다면, 패치를 할 필요없이 즉시 적용된다

유니티에서

  • 데이터를 미리 저장해두고 사용할 수 있도록 하는 클래스
  • MonoBehaviour 스크립트가 아닌 별도의 오브젝트로 관리할 수 있게 한다
  • 게임 데이터를 쉽게 조직화하고 시각적으로 관리할 수 있고, 별도의 파싱기능 구현 없이도 데이터베이스를 구현할 수 있다
  • ScriptableObject 클래스를 상속 받아 틀을 작성한다
[CreateAssetMenu(fileName = "생성시 파일명", menuName = "분류명/선택지 명")]
  • 해당 어트리뷰트를 클래스 위에 추가해서 구현한다

HP 포션 구현

  • 땅에 떨어진 HP 포션을 주워서 인벤토리에 저장하고, 사용하면 체력을 회복할 수 있게 구현해보자
  • 먼저, 스크립터블 오브젝트에디터 상에서 추가할 수 있게 만들어본다

ItemData

  • ScriptableObject를 상속받는 클래스를 작성한다
  • 이 클래스를 상속받는 아이템 클래스들은 스크립터블 오브젝트로 만들 수 있다
public abstract class ItemData : ScriptableObject
{
	// 아이템 이름
    public string Name;
    // 아이템 설명
    [TextArea] public string Description;
    // 아이템 아이콘
    public Sprite Icon;
    // 아이템 3D 프리팹
    public GameObject Prefab;
	
    // 사용: 자식 클래스에서 구체화
    public abstract void Use(PlayerController controller);
}
  • 아이템이 가질 여러 정보들 중 공통적인 것들을 필드로 가진다.
  • 아이템들은 전부 사용이 가능하다고 가정(어짜피 포션만 만듦), 추상화 클래스로 선언하고 추상 함수 Use()를 만든다

ItemObejct

  • 스크립터블 오브젝트게임 오브젝트와 연결해 줄 프리팹의 스크립트다. 삭제 조건 또한 여기서 가진다
public class ItemObject : MonoBehaviour
{
    [field: SerializeField] public ItemData Data { get; private set; }
    private GameObject _childObject;

    private void OnEnable()
    {
        _childObject = Instantiate(Data.Prefab, transform);
    }

    private void OnDisable()
    {
        Destroy(_childObject);
    }
}

  • 씬 창빈 오브젝트를 만들고, 스크립트를 추가, 콜라이더도 추가한다(원하는 크기로 추가)

PlayerController

  • 아이템을 사용하기 위해 간단히 구현된 스크립트다
public class PlayerController : MonoBehaviour
{
    [SerializeField] private int _hp;
    private Inventory _inventory;

    private void Awake() => Init();

    private void OnTriggerEnter(Collider other)
    {
        // 충돌한게 아이템이 맞는지는 당연히 체크해야됩니다.
        _inventory.GetItem(other.GetComponent<ItemObject>().Data);
        other.gameObject.SetActive(false);
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            _inventory.UseItem(0);
        }
    }

    private void Init()
    {
        _inventory = GetComponent<Inventory>();
    }

    public void Recover(int value)
    {
        _hp += value;
    }
}
  • 포션아이템을 사용해 회복할 hp, 아이템들을 저장할 inventory를 필드로 가진다
  • 충돌 시, 아이템이 맞다면 인벤토리에 추가한다
  • 마우스 왼클릭 입력이 있을 경우 아이템을 사용한다

PlayerInventory

public class Inventory : MonoBehaviour
{
    [SerializeField] private List<ItemData> _slots = new();
    private PlayerController _controller;

    private void Awake() => Init();

    private void Init()
    {
        _controller = GetComponent<PlayerController>();
    }

    public void GetItem(ItemData itemData)
    {
        _slots.Add(itemData);
    }

    public void UseItem(int index)
    {
        _slots[index].Use(_controller);
        _slots.RemoveAt(index);
    }
}
  • ItemData를 저장하기 위한 리스트로 인벤토리를 구현한다
  • index가 무조건 0이 들어오기 때문에, 인벤토리에 들어온 순서대로 사용된다

HpPotion

[CreateAssetMenu(fileName = "Hp Potion", menuName = "Scriptable Objects/Hp Potion", order = 1)]
public class HpPotion : ItemData
{
    public int Value;

    public override void Use(PlayerController controller)
    {
        controller.Recover(Value);
    }
}
  • 어트리뷰트를 추가해, 프로젝트 창에서 새로운 스크립터블 오브젝트로 추가할 수 있다. MonoBehaviour를 상속받지 않는 스크립트다
  • ItemData를 상속 받아서 ScriptableObject 또한 상속받는다
  • override로 추상 함수 Use()를 구현했다. PlayerController 형을 매개변수로 받아서 체력을 회복시킨다
  • 프로젝트 창에서 위와 같이 새로 생성할 수 있다
  • 지정한 fileName과 같이 기본 값은 Hp Potion으로 나온다
  • 2개를 만들고 각각 위와 같이 Name, Description, Value를 설정한다
  • 임시 모델로 쓰일 Cube씬 창에서 만들고 프리팹 화 후, 위 사진처럼 Prefab에 참조시킨다

씬 창에 배치하기

  • ItemObject 프리팹을 먼저 원하는 위치에 배치한다
  • 사진과 같이 스크립터블 오브젝트를 참조시킨다
  • 위와 같이 플레이를 누르면 새로 생성된다
  • 플레이어는 캡슐로 위와 같이 설정한다

플레이

  • 플레이어가 콜라이더에 닿으면 사라진다. 인벤토리에 들어간 것이다
  • 획득한 아이템들이 인벤토리에 들어간 것을 확인할 수 있다
  • PlayerController 스크립트에서 설정한 것과 같이 마우스 왼쪽 클릭을 누르면 사용한다

스크립터블 오브젝트 쓰임처

  • 스크립터블 오브젝트는 다양한 분야에서 활용할 수 있다
  • 게임 기획자들이 프로그래머에게 기능이나 게임 오브젝트의 구현을 요구하는 것이 스크립터블 오브젝트 형태로 제공될 수 있다. 만들어 주면, 기획자들이 원하는 대로 데이터를 고칠 수 있어서 협업이 원활해진다
  • 퀘스트를 구현할 수도 있다. 이벤트 처리를 해서 , 요구 몬스터 처치 수의 경우 -> 플레이어가 처치할 때마다 카운팅, 요구 아이템 수의 경우 -> 플레이어가 아이템을 얻고, 쓰거나 버릴 때마다 카운팅하여 처리할 수 있다
  • 스킬 구현도 가능하다. 필드 습득이나, 오브젝트로 존재시키고 싶을 때 사용할 수 있다
  • 젤다의 전설에서 필드에 떨어져 있는 아이템들을 스크립터블 오브젝트로 만드는 경우, 장비 아이템들을 필드에 떨어져 있는 경우 등을 생각하면 편하다
profile
개발 박살내자

0개의 댓글