[Unity Engine] 종합설계프로젝트2 유니티 엔진 공부 #1

신형석·2023년 3월 20일
0

게임 개발 일지

목록 보기
6/10

이번 학기 참여하게 된 유니티 게임 제작 프로젝트에서, 멘토님이 학습해야 할 알고리즘 몇 개를 가르쳐주셨고, 알고리즘과 유니티 구조 등등을 배우면 이 곳에 적을 예정이다.

이번에 해 볼 것은 스크립터블 오브젝트(Scriptable Object)이다.

스크립터블 오브젝트

유니티 다큐먼트는 이곳을 참고하면 좋을 것 같다. 간단하게 요약하자면, 데이터 컨테이너의 한 종류라고 생각하는 것이 좋을 것 같다. 값의 사본이 생성되는 것을 방지하여, 프로젝트의 메모리 사용을 줄이는 것이 주요 사용 사례라고 한다.

게임 오브젝트를 인스턴스화 할 때 중복 데이터를 저장하는 대신, 스크립터블 오브젝트를 이용하여 데이터를 저장한 후 모든 프리팹의 레퍼런스를 통해 액세스할 수 있다. 나는 이를 흔히 있는 참조를 사용하여, 같은 데이터의 무분별한 복제를 막고 하나의 데이터를 참고함으로써 메모리 사용을 줄이는 방법이라고 이해했다.

그럼 코드를 보면서 스크립터블 오브젝트의 사용 방법을 알아보겠다.

사용방법

using UnityEngine;

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]

public class SpawnManagerScriptableObject : ScriptableObject
{
    public string prefabName;

    public int numberOfPrefabsToCreate;
    public Vector3[] spawnPoints;
}

유니티 다큐먼트의 코드를 그대로 들고 와보았다. 하나하나씩 보겠다.

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]

fileName의 정확한 기능은 아직 모르겠고, 메뉴에도 나타나지 않으므로 일단은 생략하겠다.

menuName은 유니티 메뉴에 표현되는 이름을 나타낸다. /로 구분해서 사용한다면 왼쪽 부분은 폴더가 되고, 오른쪽 부분은 이름이 될 것이다.

order는 말 그대로 목록에서 표시되는 순서를 나타낸다.

public class SpawnManagerScriptableObject : ScriptableObject

우리가 유니티 엔진에서 사용하는 MonoBehaviour가 아닌, ScriptableObject를 사용한다. 이런 식으로 사용하면, 유니티의 스크립트와 비슷하게 사용할 수 있는 데이터 셋이 된다. 물론, MonoBehaviour를 사용하지 않았기 때문에 Start와 Update와 같은 함수는 사용할 수 없다. 애초부터 사용할 필요도 없지만 말이다.

public string prefabName;
public int numberOfPrefabsToCreate;
public Vector3[] spawnPoints;

간단한 변수 설정을 마지막으로, 스크립터블 오브젝트 설정이 끝났다. 스크립터블 오브젝트는 MonoBehaviour와 달리 게임 오브젝트에 연결할 수 없으므로, 프로젝트의 에셋으로 저장해야 한다.


이런식으로, Create -> ScriptableObjects -> SpawnManagerScriptableObject를 만들 수 있게 되었다. 이렇게 만들어진 스크립터블 오브젝트의 값을 사용하려면, 이를 참조하는 스크립트를 하나 만들어야 한다. 이 코드 또한 유니티 다큐먼트에 나와있다.

using UnityEngine;

public class Spawner : MonoBehaviour
{
    // The GameObject to instantiate. (복제할 오브젝트를 선택)
    public GameObject entityToSpawn;

    // An instance of the ScriptableObject defined above. (위에 정의된 인스턴스의 스크립터블 오브젝트)
    public SpawnManagerScriptableObject spawnManagerValues;

    // This will be appended to the name of the created entities and increment when each is created.
    int instanceNumber = 1;

    void Start()
    {
        SpawnEntities(); // Start() 함수에서 SpawnEntities() 불러오기
    }

    void SpawnEntities()
    {
        int currentSpawnPointIndex = 0;

        for (int i = 0; i < spawnManagerValues.numberOfPrefabsToCreate; i++)
        {
            // Creates an instance of the prefab at the current spawn point. (현재 스폰 포인트에 프리팹의 복제품을 만든다. )
            GameObject currentEntity = Instantiate(entityToSpawn, spawnManagerValues.spawnPoints[currentSpawnPointIndex], Quaternion.identity);

            // Sets the name of the instantiated entity to be the string defined in the ScriptableObject and then appends it with a unique number. (스크립터블 오브젝트에 정의된 문자열을 복제된 개체의 이름으로 정하고, 특별한 숫자를 붙인다. )
            currentEntity.name = spawnManagerValues.prefabName + instanceNumber;

            // Moves to the next spawn point index. If it goes out of range, it wraps back to the start. (다음 스폰 포인트 색인으로 옮겨간다. )
            currentSpawnPointIndex = (currentSpawnPointIndex + 1) % spawnManagerValues.spawnPoints.Length;

            instanceNumber++;
        }
    }
}

한글로 색인을 조금 달아보았다. public으로 외부에서 각각 복제할 오브젝트, 그 오브젝트의 스크립터블 오브젝트를 가지고 온 후, 스크립터블 오브젝트의 Vector3[ ]에 저장된 Vector3 값 위치에 Prefab을 복제하여 넣는 코드이다.

이렇게 만든 후, 유니티의 Hierarchy에 빈 오브젝트를 하나 만든다. 또한, 복제하고 싶은 특정 Prefab을 하나 만든다. 이 프리팹을 Entity To Spawn에 넣고, 만들어놓은 스크립터블 오브젝트를 Spawn Manager Values에 넣는다.

코드는 이 스크립터블 오브젝트를 참고하여, Prefab을 복제한 후 각 벡터 위치에 넣는다. 특정 벡터들을 설정하여 구현해보겠다.


값은 자기 마음대로 정하면 된다. 코드를 잘 읽어보면 알겠지만 주의해야할 점이 있다. 바로 Number Of Prefabs To Create의 수와 Spawn Points의 Element 수가 같아야 한다는 점이다.


실행을 해보면, 화면 중앙을 기준으로 벡터 값에 Prefab으로 생성해놓은 하얀 동그라미가 그려져있음을 볼 수 있다.

개념을 배우는 것은 좋지만, 역시 실전에 적용하는 것이 더 와닿을 것 같은 시간이었다. 하고 있는 개인 프로젝트에 적용하여 사용해 볼 수 있도록 하는 것이 좋을 것 같았다.

다음 게시글에서는 싱글톤 패턴(Singleton Pattern)에 대해 작성할 것이다.

0개의 댓글

관련 채용 정보