OBJECT POOL 오브젝트 풀
동일하게 생긴 적, 동일하게 생긴 투사체 오브젝트를 다수 생성하면 당연히 게임 성능에 큰 무리가 온다. 당장 직접 체험할 수 있는 영역이다.
그래서 일정량의 오브젝트를 미리 생성하여 비활성화 상태로 준비시키고, 상황에 맞게 오브젝트를 활성화(혹은 생성), 비활성화(혹은 파괴)하는 방식으로 무제한 프리팹 생성으로 우려되는 성능 저하를 줄인다.
이 방법이 오브젝트 풀이다.
아래는 이번 강의에서 작성한 오브젝트 풀 스크립트다. 만, 정말 코드를 한줄도 이해하지 못다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool : MonoBehaviour
{
[System.Serializable]
public struct Pool
{
public string tag;
public GameObject prefab;
public int size;
}
public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
private void Awake()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach (var pool in pools)
{
Queue<GameObject> objectPool = new Queue<GameObject>();
for (int i = 0; i < pool.size; i++)
{
GameObject obj = Instantiate(pool.prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
}
public GameObject SpawnFromPool(string tag)
{
if (!poolDictionary.ContainsKey(tag))
{
return null;
}
GameObject obj = poolDictionary[tag].Dequeue();
poolDictionary[tag].Enqueue(obj);
return obj;
}
}
.. 욕 안적는게 다행이다.
MONOBEHAVIOR
유니티에서 C#스크립트를 실행하면 이미 MONOBEHAVIOR라는 클래스에 상속된 상태로 시작하는 것을 볼 수 있다.
이 MONOBEHAVIOR는 작성한 스크립트를 오브젝트에 "컴포넌트"로 적용시킬 때 필요한 클래스다.
바꿔 말해, MONOBEHAVIOR를 상속하지 않는 스크립트는 컴포넌트로 사용할 수 없다.
또한, MONOBEHAVIOR를 상속한 스크립트를 컴포넌트로 가지는 오브젝트는 따로 객체화할 필요 없이 바로 사용 가능하다. 예를 들어, CUBE라는 오브젝트의 컴포넌트로 CUBE : MONOBEHAVIOR 스크립트를 추가했다면, 이 스크립트에서 CUBE를 객체화 할 필요 없이 gameObject나 transform으로 오브젝트의 정보를 가져올 수 있다.
스크립트가 오브젝트의 컴포넌트로 들어가면, 스크립트 내의 Awake()~OnDestroy()함수(이벤트 함수)가 작동하면서 해당 스크립트의 생명 주기가 시작된다. 아래는 이벤트 함수의 실행 순서를 나타내는 그림과 대표적인 이벤트 함수다.

- 시작
Awake : 오브젝트가 생성될 때 한번 실행한다. 비활성화 상태였다면 최초 활성화 시 한번 실행한다.
OnEnable : 오브젝트가 활성화될 때 마다 한번 실행한다.
Start : Awake에 뒤이어 한번 실행한다. - 연속적인 연산 처리
FixedUpdate : 오브젝트간의 물리적 연산을 실행한다.
Update : 게임의 로직을 처리한다.
LateUpdate : 게임 로직 처리 단계 마지막에 실행한다.
위 3개의 함수는 그림에 설명돼 있다. - 종료
OnDisable : 오브젝트가 비활성화될 때 마다 한번 실행한다.
OnDestroy : 오브젝트가 파괴될 때 한번 실행한다. - 충돌 이벤트 함수
OnTrigger~ : 충돌체 반응으로 실행되는 함수. 충돌체의 IsTrigger = true일 때 발동 가능하다. 물리적인 충돌 반응은 없다.
OnCollision~ : 충돌체 반응으로 실행되는 함수. 충돌체의 IsTrigger = false일 때 발동 가능하다. 물리적인 충돌 반응을 동반한다.
deltaTime과 시간흐름의 정규화에 대한 짧은 설명
세상에는 UNITY로 제작된 프로그램을 구동할 수 있는 다양한 종류의 기기들이 있고, 저마다 성능도 천차만별이다.
이제부터 예를 든다.
30FPS를 소화할 수 있는 기기A와, 120FPS를 소화할 수 있는 기기B가 있다.
이 두 기기에 Update(){transform.Translate(Vector3.forward * 1)}하는 cube오브젝트를 실행하는 프로그램을 설치하고, 실행했다.
결과, A의 cube는 1초에 30까지 전진했고,
B의 cube는 1초에 120까지 갔다.
만약 이 프로그램이 레이싱 게임이었다면? B의 승리는 불변할 것이다.
이러한 기기 간의 성능 차이를 극복하게 하는 것이 시간 변화량Time.deltaTime을 곱하는 것이다.
Update(){transform.Translate(Vector3.forward * 1 * Time.deltaTime)}으로 다시 프로그램을 실행한다.
결과, A의 cube는 1프레임에 1*(1/30(초))만큼, 1초에 1*(1/30(초))*30(프레임)만큼 전진했고,
B의 cube는 1프레임에 1*(1/120(초))만큼, 1초에 1*(1/120(초))*120(프레임)만큼 전진했다.
이로써 A와 B는 성능이 다르지만 오브젝트가 같은 속도를 갖고 이동하는 프로그램을 갖게 됐다.
아래는 요약이다.
Time.deltaTime을 곱하지 않았을 때는 오브젝트가 프레임당 지정한 양만큼 이동하고,
Time.deltaTime를 곱함으로써 오브젝트는 초당 지정한 양만큼 이동한다.
이로써 구동 기기 간의 성능 차이를 극복할 수 있으며, 오브젝트의 물리 정보 변화 로직이 연속적인 연산 처리-Update함수에 위치할 경우 반드시 적용해야 할 사항이다.
'UNITY' 카테고리의 다른 글
| UNITY_20230921[개인과제] (0) | 2023.09.22 |
|---|---|
| UNITY_20230920[개인과제] (0) | 2023.09.20 |
| UNITY_20230918[스크립터블 오브젝트] (0) | 2023.09.18 |
| UNITY_20230914[UNITY 팀 프로젝트 종료, 델리게이트] (0) | 2023.09.14 |
| UNITY_20230913[UNITY 팀 프로젝트 - 벽돌 부수기 게임] (0) | 2023.09.13 |