안녕하세요,오늘은 Unity 프로젝트에서 메모리 효율을 높이는 방법 중 하나인 ScriptableObject를 활용하여 데이터 관리를 개선하는 방법에 대해 알아보겠습니다. 본 포스팅에서는 ScriptableObject의 개념과 활용 방법을 소개하고, 실제 예제를 통해 이를 적용해 보도록 하겠습니다.

ScriptableObject (스크립터블 오브젝트)란?

우리가 Unity 프로젝트를 진행하면서 고정된 데이터를 저장하고 사용할 일이 많습니다. 예를 들어, 게임 캐릭터의 스텟이나 아이템 정보 등을 저장해야 하는 경우가 있죠. 이러한 데이터를 효율적으로 관리하기 위해 Unity에서는 ScriptableObject라는 개념을 제공합니다. ScriptableObject는 클래스 인스턴스와 독립적으로 대량의 데이터를 저장할 수 있는 데이터 컨테이너로, 중복 데이터를 최소화하여 메모리 사용량을 줄이는 데 도움이 됩니다.

ScriptableObject는 MonoBehaviour와 같이 Unity 객체에서 파생되지만, GameObject에는 첨부할 수 없습니다. 대신, 프로젝트의 Assets에 저장하여 사용합니다. 이를 활용하면 Prefab 등에서 데이터를 참조로 접근하여 메모리에 데이터가 한 번만 저장되도록 할 수 있습니다.

ScriptableObject 활용 방법

ScriptableObject의 주요 사용 사례는 다음과 같습니다.

  • 에디터 세션 중 데이터 저장 및 저장
  • 실행 시간에 사용할 프로젝트의 Asset으로 데이터 저장

ScriptableObject를 사용하려면 ScriptableObject 클래스를 상속하는 스크립트를 작성하고, CreateAssetMenu 어트리뷰트를 사용하여 사용자 지정 애셋을 쉽게 생성할 수 있도록 해야 합니다. 이렇게 하면 Assets 폴더에 스크립트가 있을 때, ScriptableObject의 인스턴스를 생성할 수 있습니다.

이후에는 ScriptableObject를 참조하는 새로운 스크립트를 작성하여 데이터를 사용하면 됩니다. 이때 스크립트 파일 이름이 클래스 이름과 동일해야 한다는 점을 주의해야 합니다.

독립적으로 존재하는 데이터 컨테이너와 같다

ScriptableObject 적용 사례

캐릭터 스텟 ScriptableObject 생성

먼저 캐릭터의 스텟 정보를 저장하는 ScriptableObject를 생성해 보겠습니다.

유니티에서 C# 스크립트 파일을 생성하고, 이름을 CharacterStatScriptableObject로 설정합니다. 유니티 디폴트 클래스가 생성됩니다.

using UnityEngine;

public class CharacterStatScriptableObject : MonoBehaviour
{
}

MonoBehaviour 대신 ScriptableObject를 상속하도록 클래스를 수정합니다. ScriptableObject를 상속받은 클래스는 유니티 오브젝트가 아닌, 프로젝트 내에서 저장되는 데이터 구조를 정의합니다.

using UnityEngine;

public class CharacterStatScriptableObject : ScriptableObject
{
}

CreateAssetMenu 어트리뷰트를 사용하여 새로운 메뉴 항목을 만들어 이 ScriptableObject를 생성할 수 있도록 설정합니다. fileName은 기본 파일 이름을 지정하고, menuName은 유니티 에디터의 메뉴에서 어떻게 표시될지를 지정합니다. order는 메뉴 항목의 순서를 지정합니다.

using UnityEngine;

[CreateAssetMenu(fileName = "CharacterStat", menuName = "ScriptableObjects/CharacterStatScriptableObject", order = 1)]
public class CharacterStatScriptableObject : ScriptableObject
{
}

이제 각 캐릭터의 이름과 능력치를 저장하기 위한 필드를 추가합니다.

먼저, 캐릭터의 이름을 저장할 문자열 변수를 추가합니다.

public string characterName;

그 다음, 캐릭터의 체력(health), 공격력(attack), 방어력(defense)을 저장할 정수형 변수를 추가합니다.

public int health;
public int attack;
public int defense;

전체 코드를 살펴 보면 다음과 같습니다.

using UnityEngine;

[CreateAssetMenu(fileName = "CharacterStat", menuName = "ScriptableObjects/CharacterStatScriptableObject", order = 1)]
public class CharacterStatScriptableObject : ScriptableObject
{
    public string characterName;

    public int health;
    public int attack;
    public int defense;
}

이 ScriptableObject를 사용하여 프로젝트에서 캐릭터의 능력치 데이터를 저장하고 관리할 수 있습니다. 각 필드는 유니티 에디터에서 직접 수정할 수 있으며, 프로젝트 내에서 필요한 경우 해당 ScriptableObject를 참조하여 값을 가져올 수 있습니다.

위의 스크립트를 Assets 폴더에 넣으면, ScriptableObject 인스턴스를 생성할 수 있습니다.

ScriptableObject 데이터 사용

이제 캐릭터 스텟을 사용하는 새로운 스크립트를 작성해야 합니다. 이 경우에는 CharacterStatDisplay라는 새로운 스크립트를 작성하겠습니다.

우선 유니티에서 C# 스크립트 파일을 생성하고, 이름을 CharacterStatDisplay로 설정합니다. 유니티 디폴트 클래스가 생성됩니다.

using UnityEngine;

public class CharacterStatDisplay : MonoBehaviour
{
}

이제 UnityEngine.UI 네임스페이스를 추가하여 Text 컴포넌트를 사용할 수 있게 합니다.

using UnityEngine;
using UnityEngine.UI;

public class CharacterStatDisplay : MonoBehaviour
{
}

다음으로 CharacterStatScriptableObject 인스턴스를 참조할 public 변수를 추가합니다.

public CharacterStatScriptableObject characterStatValues;

UI 텍스트 컴포넌트를 참조할 public 변수들을 추가합니다.

public Text characterNameText;
public Text healthText;
public Text attackText;
public Text defenseText;

Start() 메소드에서 UpdateCharacterStats() 메소드를 호출하여 캐릭터의 능력치를 UI에 표시합니다.

using UnityEngine;
using UnityEngine.UI;

public class CharacterStatDisplay : MonoBehaviour
{
    // 위에서 정의한 ScriptableObject 인스턴스
    public CharacterStatScriptableObject characterStatValues;

    // UI 텍스트 컴포넌트 참조
    public Text characterNameText;
    public Text healthText;
    public Text attackText;
    public Text defenseText;

    void Start()
    {
        UpdateCharacterStats();
    }

    void UpdateCharacterStats()
    {
        
    }
}

UpdateCharacterStats() 메소드에서 각 능력치를 UI 텍스트 컴포넌트의 text 속성에 설정합니다.

void UpdateCharacterStats()
{
    characterNameText.text = "Name: " + characterStatValues.characterName;
    healthText.text = "Health: " + characterStatValues.health;
    attackText.text = "Attack: " + characterStatValues.attack;
    defenseText.text = "Defense: " + characterStatValues.defense;
}

전체 코드를 살펴 보면 다음과 같습니다.

using UnityEngine;
using UnityEngine.UI;

public class CharacterStatDisplay : MonoBehaviour
{
    // 위에서 정의한 ScriptableObject 인스턴스
    public CharacterStatScriptableObject characterStatValues;

    // UI 텍스트 컴포넌트 참조
    public Text characterNameText;
    public Text healthText;
    public Text attackText;
    public Text defenseText;

    void Start()
    {
        UpdateCharacterStats();
    }

    void UpdateCharacterStats()
    {
        characterNameText.text = "Name: " + characterStatValues.characterName;
        healthText.text = "Health: " + characterStatValues.health;
        attackText.text = "Attack: " + characterStatValues.attack;
        defenseText.text = "Defense: " + characterStatValues.defense;
    }
}

이제 이 스크립트를 씬에 있는 캐릭터 스텟을 표시할 GameObject에 첨부하고, 인스펙터에서 Character Stat Values 필드를 설정한 CharacterStatScriptableObject로 설정합니다. 그리고 각각의 UI 텍스트 컴포넌트 참조를 설정한 다음, 게임을 실행하면 ScriptableObject에 저장된 캐릭터 스텟이 화면에 표시됩니다.

결론

지금까지 Unity에서 ScriptableObject를 활용하여 데이터 관리를 개선하는 방법을 알아보았습니다.

ScriptableObject를 사용하면 중복 데이터를 최소화하여 메모리 사용량을 줄일 수 있으며, 에디터 세션 중 데이터 저장 및 실행 시간에 사용할 프로젝트의 Asset으로 데이터를 저장할 수 있습니다. 이를 통해 프로젝트의 메모리 효율을 높일 수 있으므로, 여러분의 프로젝트에서도 ScriptableObject를 적극 활용해 보시길 바랍니다.