[Unity] ScriptableObject 를 이용한 데이터 저장 및 참조

ScriptableObject

유니티에서 제공하는 데이터 컨테이너이다. 

저장된 데이터를 여러 오브젝트들이 공유해서 사용하는 방식이기 때문에,

값이 정해진 데이터를 여러 오브젝트가 복사해서 사용하며 생기는 불필요한 메모리 사용을 막을 수 있다.

데이터와 실제 게임 코드를 분리하여 직렬화 할 수 있으며, 유니티 에디터에서 수정 및 관리가 용이한 장점이 있다.

 

 

https://unity.com/kr/how-to/architect-game-code-scriptable-objects

위 문서를 참고하여 아래와 같은 샘플 코드를 작성해보았다.

 

우선, 같이 PlayerData 라는 ScriptableObject 객체를 만들었다.

using UnityEngine;

[CreateAssetMenu]
public class PlayerData : ScriptableObject, ISerializationCallbackReceiver
{
    [SerializeField]
    private int initialHp; // 인스펙터에서 10으로 입력함.

    public int Hp    { get; set; }
    public int MaxHp { get; private set; }

    /// <summary>
    /// 역직렬화된 후에 호출
    /// </summary>
    public void OnAfterDeserialize()
    { 
        Hp    = initialHp;
        MaxHp = initialHp;
    }

    /// <summary>
    /// 직렬화되기 전에 호출
    /// </summary>
    public void OnBeforeSerialize()
    {
    }
}
@warning
ISerializationCallbackReceiver 는 객체가 직렬화 될 때/역직렬화 될 때 특정 콜백을 실행할 수 있게 해주는 인터페이스이다.

CreateAssetMenu 속성을 class 앞에 붙여 에디터 메뉴에서 PlayerData를 생성할 수 있도록 하였다.

initialHp를 SerializeField속성을 붙여 인스펙터상에서 수정할 수 있도록 하였고, 다른 객체에서는 접근 불가하도록 하였다.

다른 객체에서는 Hp, MaxHp값만 참조하여 사용하며, 역직렬화 될 때 해당 값을 초기화 해주도록 작성하였다.

 

 

아래 코드에서 Player객체는 PlayerData의 Hp값을 변경하고 있고, HpBar 객체는 PlayerData의 Hp값을 참조해 UI를 갱신한다.

using UnityEngine;

public class Player : MonoBehaviour
{
	[SerializeField]
	private PlayerData playerData;

	void Update()
	{
		// 마우스 왼쪽 버튼 누를 때 마다 HP 감소.
		if (Input.GetMouseButtonDown(0))
		{
			playerData.Hp -= 1;
		}
	}
}
using UnityEngine;
using UnityEngine.UI;

public class HpBar : MonoBehaviour
{
    [SerializeField]
    private PlayerData playerData;

    [SerializeField]
    private Image bar;

    private void Update()
    {
        bar.fillAmount = playerData.Hp / (float)playerData.MaxHp;
    }
}

이렇게 마우스 왼쪽 클릭할 때 마다 Hp값이 변경되어 HpBar에도 변경된 Hp값으로 UI 표시를 해주고 있지만

역직렬화 할 때 Hp값이 인스펙터 상에서 입력한 InitialHp의 값으로 초기화가 되게 된다.

 

예시를 Hp로 작성하긴 했지만, ScriptableObject는 런타임 시에 변경한 값이 저장되지 않으므로

실제 사용 시엔 값이 바뀌지 않는 아이템이나 맵 데이터 등을 저장하는데에 쓰면 좋을 것 같다.