빠른 흐름
csharp
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private Transform firePoint;
private void Fire()
{
GameObject bullet = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation, firePoint.parent);
Destroy(bullet, 3f);
}기본 흐름
- Unity에서 런타임 오브젝트를 다룰 때는 "어떻게 만들까"보다 먼저 "누가 소유하고 언제 정리할까"를 정해야 합니다.
Instantiate는 프리팹 asset이나 기존 오브젝트를 복제해 씬에 배치하는 가장 직접적인 방식입니다. 부모Transform을 함께 넘기면 생성 직후 계층 구조와 좌표 기준을 한 번에 정리할 수 있습니다.Destroy는 즉시 메모리에서 사라지는 호출이라기보다, 해당 프레임 말미에 파괴를 예약하는 흐름에 가깝습니다. 그래서 파괴 직후 참조를 다시 쓰는 코드가 있으면MissingReferenceException이나 null-like 동작을 만나기 쉽습니다.- 총알, 이펙트, 짧은 적 스폰처럼 수명이 짧고 반복 횟수가 많은 대상은
Instantiate -> Destroy를 계속 반복하기보다 object pooling으로 전환하는 편이 좋습니다. 반대로 한 번 생성하고 오래 유지되는 UI 창, 보스, 체크포인트 오브젝트는 단순 생성/삭제가 더 읽기 쉽습니다. - 결국 선택 기준은 "반복 생성 빈도", "초기화 비용", "비활성 상태로 유지해도 되는가" 세 가지입니다.
체크포인트
| 선택지 | 언제 쓰면 좋은가 |
|---|---|
Instantiate(prefab) | 장면 수가 적고 생성 빈도가 낮을 때 |
Instantiate(prefab, pos, rot, parent) | 생성과 계층 배치를 동시에 정리하고 싶을 때 |
Destroy(obj) | 더 이상 필요 없는 오브젝트를 정리할 때 |
Destroy(obj, delay) | 이펙트, 임시 투사체처럼 생명주기가 짧을 때 |
| 비활성화 후 재사용 | UI 패널, 적 프리팹, 반복 투사체처럼 자주 다시 쓸 때 |
| object pooling | 생성/삭제가 프레임마다 반복될 만큼 빈도가 높을 때 |
주의할 점
pooling에서 이상 동작이 생기면 대부분 reset 누락 문제입니다. pool에서 꺼낼 때 반드시 초기화하세요.
csharp
// ❌ SetActive(true)만 호출 — 이전 상태(위치, velocity, trail) 그대로
pooledBullet.SetActive(true);
// ✅ 상태 초기화 후 활성화
pooledBullet.transform.SetPositionAndRotation(spawnPos, spawnRot);
bulletComponent.ResetState(); // HP, velocity, trail, 이벤트 구독 초기화
pooledBullet.SetActive(true);참고 링크
3 sources