Scriptable Object (스크립터블 오브젝트) 란?
우리는 Unity 프로젝트를 진행하면서 고정된 데이터를 저장하고 사용할 일이 많다.
예를 들어, 게임 캐릭터의 스텟이나 아이템 정보 등을 저장해야 하는 경우가 있다. 이러한 데이터를 효율적으로 관리하기 위해 Unity에서는 ScriptableObject라는 개념을 제공한다.
ScriptableObject는 클래스 인스턴스와 독립적으로 대량의 데이터를 저장할 수 있는 데이터 컨테이너로, 중복 데이터를 최소화하여 메모리 사용량을 줄이는 데 도움이 된다.
ScriptableObject는 MonoBehaviour와 같이 Unity 객체에서 파생되지만, GameObject에는 첨부할 수 없다. 대신, 프로젝트의 Assets에 저장하여 사용한다.
이를 활용하면 Prefab 등에서 데이터를 참조로 접근하여 메모리에 데이터가 한 번만 저장되도록 할 수 있다.
Scriptable Object의 활용
- 데이터 컨테이너로 데이터 공유에 사용할 수 있고, 이를 통해 메모리 사용량을 줄일 수 있다.
- 기존 시스템은 하나의 컴포넌트에 변수를 정의하면 프리팹을 인스턴싱해서 만드는 만큼 메모리 할당이 발생한다.
- Scriptable Object는 데이터를 참조 형태로 오브젝트에서 가져올 수 있게 함으로써 메모리 할당을 최소화하고 고유한 값을 가질 수 있게 한다.
- 프리펩에서 변화가 없는 동일한 데이터를 사용하는 경우, Scriptable Object로 해당 데이터를 관리하면 편리성과 최적화 효과를 얻을 수 있다.
Scriptable Object를 이용하여 적들을 랜덤으로 스폰(spawn)시키기
1) 내가 원하는 적을 스폰시킬 수 있게 C# 스크립트를 생성한다.
(Scriptable Objec는 파일명하고 일치 할 필욘 없지만 일치시키는 게 보기에 좋을것이다.)
파일이 생성되면, VS로 들어가서 MonoBehaviour -> ScriptableObject로 수정한다음, 필요한 정보들을 넣는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
using UnityEngine;
[CreateAssetMenu(fileName = "SpawnPoints", menuName = "Enemy Spawn Point", order = 1)]
public class SpawnPointData : ScriptableObject
{
[SerializeField] //직렬화가 되어야 함
private GameObject EnemyPrefab;
public GameObject GetEnemyPrefab() => EnemyPrefab; // 적 프리펩을 가져옴
[SerializeField]
private int SpawnCount; // 몇 개를 생성할것인지
public int GetSpawnCount() => SpawnCount; // 포인트값을 가져옴
[SerializeField]
private Vector2[] SpawnPoints; // 적의 스폰위치 2차원배열
public Vector3 GetSpawnPoint()
{
Vector2 point = SpawnPoints[Random.Range(0, SpawnPoints.Length)]; // 랜덤으로 위치주기
return new Vector3(point.x, 0, point.y);
}
}
|
cs |
CreateAssetMenu 속성은 스크립터블 오브젝트 스크립트를 이용해서 빠르고 쉽게 에셋을 생성할 수 있게 만들어주는 속성이다.
저장 한 다음, 프로젝트에서 마우스 오른 쪽 버튼 클릭을 하게 되면
이렇게 내가 만든 SpawnPoints가 생성된다.
생성된 [SpawnPoints]를 클릭하여 Inspector창에 떠 있는 정보들을 내가 원하는 것에 맞게 입력한다.
Enemy Prefab : 내가 스폰(생성)시키고 싶은 적의 prefab
Spawn Points : 내가 주고싶은 Vector2 X, Y축 값 ( + 버튼을 추가하여 더 생성할 수 있다)
Spawner을 작성할 것이 때문에 C# Script로 EnemySpawner 추가한다.
방금 만든 EnemySpawner 스크립트를 Scene에다가 추가한다.
Spawn Point Data에다가는 SpawnPoints를 드래그 앤 드롭해준다.
적의 수가 많으면 관리가 힘들기에 관리하기 쉽게 Hierachy에 가서 CreateEmpty를 누른다음 Enemies라고 생성해주자.
이제 여기에 원하는 수의 적들을 붙여넣어주면 된다.
EnemySpawner 스크립트를 열어서 이렇게 작성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
[SerializeField] // 외부에서 입력받을 것이기 때문에
private SpawnPointData spawnPointData; // 아까 작성한 SpawnPointData 타입
private void Start()
{
if (spawnPointData == null)
return;
CreatePool(); // 적 생성 함수 콜
InvokeRepeating("Spawn", 1, 1); // 1초 후부터 1초마다 ""안의 Spawn 함수를 반복하겠다는 뜻
}
// 배열로 저장한 적을 만들기
private List<GameObject> pool;
private void CreatePool() // 적 생성하는 함수
{
GameObject original = spawnPointData.GetEnemyPrefab(); // 내가 원하는 적을 original 변수에 넣기
GameObject parent = GameObject.Find("Enemies"); // 적들을 붙여 줄 오브젝트를 찾는다
if (original == null) // 프리펩이 없다면 수행하지 말아라
return;
pool = new List<GameObject>();
for(int i = 0; i < spawnPointData.GetSpawnCount(); i++) // 내가 원하는 적의 크기 만큼 돌리기
{
GameObject obj = Instantiate(original); // 내가 원하는 적의 프리펩을 생성
obj.name = $"{original.name}_{i:0}"; // 적의 이름 만들어주기
obj.transform.parent = parent.transform; // 부모자식관계는 transform이 맺기 때문에 transform에다가 줘야함
obj.SetActive(false); // 처음 시작 할 때는 active(활성화)를 꺼준다
pool.Add(obj); // 풀에다가 등록시켜준다.
}
}
private void Spawn() // 적을 스폰시킬 함수 : 얘가 콜될 때 마다 스폰을 할 거임
{
GameObject spawn = null;
foreach (GameObject obj in pool)
{
if (obj.activeSelf == false) // 만약 obj가 꺼져있다면 실행
{
spawn = obj;
break;
}
}
Vector3 position = spawnPointData.GetSpawnPoint(); // 스판 포인트 가져옴 position은 랜덤한 포인트가 나올거임
// 꽉 차있으면 더 이상 등장 할 수 없으니까 spawn이 null이 아닐때만 실행
spawn?.transform.SetPositionAndRotation(position, Quaternion.identity);
spawn?.SetActive(true); // spawn이 null이 아니라면 active(활성화) 시켜준다
}
}
|
cs |
그렇다면 이렇게 비어있는 고앵이(Player) 주위로
적들이 스폰(생성) 되는 걸 볼 수 있다!!
풀을 이용하여 전체 적을 만들어 놓고, acitve를 꺼 놨다가 InvokeRepeating을 통해 한 마리씩 active가 켜지는 것도 볼 수 있다!
출처 및 참고 : 강의 짱잘하시는 울 유니티 선생님 수업,
HyunZzang의 프로그래밍 공간 / 함께 공부해요!!
도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 부탁드립니다 :)