오브젝트 생성과 삭제란?
게임 개발에서 오브젝트를 동적으로 생성하고 삭제하는 것은 매우 중요한 기능입니다. 예를 들어, 총알을 발사할 때 총알 오브젝트를 생성하고, 화면 밖으로 나가면 삭제하는 등의 상황에서 사용합니다.
기본 개념
- Instantiate(): 프리팹이나 오브젝트를 복제하여 새로 생성
- Destroy(): 오브젝트를 메모리(memory)에서 제거
- 프리팹: 재사용 가능한 오브젝트 템플릿
1. Instantiate() - 오브젝트 생성
Instantiate()는 프리팹이나 기존 오브젝트를 복제하여 새로운 오브젝트를 생성합니다.
기본 사용법
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
// 화살 프리팹 (Inspector에서 할당)
public GameObject arrowPrefab;
void Update()
{
// 프리팹을 복제하여 새 화살 생성
GameObject newArrow = Instantiate(arrowPrefab);
}
}
위치 지정하여 생성
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
public GameObject arrowPrefab;
void Update()
{
// 특정 위치에 화살 생성
Vector3 spawnPosition = new Vector3(0, 6f, 0);
GameObject newArrow = Instantiate(arrowPrefab, spawnPosition, Quaternion.identity);
}
}
랜덤 위치에 생성
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
public GameObject arrowPrefab;
float spawnTime = 0.3f;
float delta = 0f;
void Update()
{
// 시간 누적
delta += Time.deltaTime;
// 일정 시간이 지나면 화살 생성
if (delta > spawnTime)
{
delta = 0f;
// 랜덤한 X 위치 계산
float randomX = Random.Range(-8.4f, 8.4f);
// 랜덤 위치에 화살 생성
Vector3 spawnPosition = new Vector3(randomX, 6f, 0);
GameObject newArrow = Instantiate(arrowPrefab, spawnPosition, Quaternion.identity);
}
}
}
Instantiate() 매개변수(variable)(parameter)
// 1. 프리팹만 지정 (현재 위치에 생성)
GameObject obj = Instantiate(prefab);
// 2. 위치 지정
GameObject obj = Instantiate(prefab, position, rotation);
// 3. 부모 지정
GameObject obj = Instantiate(prefab, parentTransform);
// 4. 위치, 회전, 부모 모두 지정
GameObject obj = Instantiate(prefab, position, rotation, parentTransform);
2. Destroy() - 오브젝트 삭제
Destroy()는 오브젝트를 메모리(memory)에서 제거합니다.
기본 사용법
using UnityEngine;
public class ArrowController : MonoBehaviour
{
public float arrowSpeed = 0.1f;
void Update()
{
// 화살을 아래로 이동
transform.Translate(0, -arrowSpeed, 0);
// 화면 밖으로 나갔는지 확인
if (transform.position.y < -6f)
{
// 화살 삭제
Destroy(gameObject);
}
}
}
다른 오브젝트 삭제
using UnityEngine;
public class EnemyController : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
// 충돌한 오브젝트가 "Bullet" 태그를 가진 경우
if (other.CompareTag("Bullet"))
{
// 총알 삭제
Destroy(other.gameObject);
// 자신도 삭제
Destroy(gameObject);
}
}
}
지연 삭제
using UnityEngine;
public class Explosion : MonoBehaviour
{
void Start()
{
// 2초 후에 삭제
Destroy(gameObject, 2f);
}
}
Destroy() 매개변수(variable)(parameter)
// 1. 즉시 삭제
Destroy(gameObject);
// 2. 지연 삭제 (초 단위)
Destroy(gameObject, 2f);
// 3. 컴포넌트만 삭제 (오브젝트는 유지)
Destroy(GetComponent<Rigidbody2D>());
3. 실제 사용 예제
예제 1: 화살 생성기
using UnityEngine;
public class ArrowGenerator : MonoBehaviour
{
public GameObject arrowPrefab;
float spawnTime = 0.3f;
float delta = 0f;
void Update()
{
// 시간 누적
delta += Time.deltaTime;
// 일정 시간이 지나면 화살 생성
if (delta > spawnTime)
{
// 타이머 초기화
delta = 0f;
// 화살 프리팹을 복제하여 생성
GameObject arrow = Instantiate(arrowPrefab);
// 랜덤한 X 위치 설정
float randomX = Random.Range(-8.4f, 8.4f);
arrow.transform.position = new Vector3(randomX, 6f, 0);
}
}
}
예제 2: 화살 자동 삭제
using UnityEngine;
public class ArrowController : MonoBehaviour
{
public float arrowSpeed = 0.1f;
void Update()
{
// 화살을 아래로 이동
transform.Translate(0, -arrowSpeed, 0);
// 화면 아래로 나갔는지 확인
if (transform.position.y < -6f)
{
// 화살 삭제
Destroy(gameObject);
}
}
}
예제 3: 불덩어리 생성기
using UnityEngine;
public class FireballSpawner : MonoBehaviour
{
public GameObject fireballPrefab;
public float spawnHeight = 8f;
public float minX = -5f;
public float maxX = 5f;
void Start()
{
// 불덩어리 생성 시작
StartCoroutine(SpawnFireballs());
}
System.Collections.IEnumerator SpawnFireballs()
{
for (int i = 0; i < 10; i++)
{
// 랜덤 위치 계산
float randomX = Random.Range(minX, maxX);
Vector3 spawnPosition = new Vector3(randomX, spawnHeight, 0);
// 불덩어리 생성
GameObject fireball = Instantiate(fireballPrefab, spawnPosition, Quaternion.identity);
fireball.SetActive(true);
// 0.5초 ~ 2초 사이의 랜덤한 시간 대기
float delay = Random.Range(0.5f, 2f);
yield return new WaitForSeconds(delay);
}
}
}
4. 주의사항
1. null 체크
void Update()
{
// ✅ 안전한 방법
if (arrowPrefab != null)
{
GameObject arrow = Instantiate(arrowPrefab);
}
}
2. 메모리(memory) 관리
// ❌ 나쁜 예: 무한정 생성
void Update()
{
GameObject obj = Instantiate(prefab);
// 삭제하지 않으면 메모리 누수 발생
}
// ✅ 좋은 예: 생성 후 적절히 삭제
void Update()
{
GameObject obj = Instantiate(prefab);
Destroy(obj, 5f); // 5초 후 자동 삭제
}
3. Destroy() 타이밍
void Update()
{
// Destroy()는 즉시 실행되지 않음
Destroy(gameObject);
// ❌ 위험: 삭제된 오브젝트에 접근
Debug.Log(gameObject.name); // 에러 발생 가능
// ✅ 안전: return으로 즉시 종료
Destroy(gameObject);
return;
}
4. 프리팹 vs 인스턴스(instance)
public GameObject arrowPrefab; // 프리팹 (원본)
void Start()
{
// 프리팹을 복제하여 인스턴스 생성
GameObject arrow1 = Instantiate(arrowPrefab);
GameObject arrow2 = Instantiate(arrowPrefab);
// arrow1과 arrow2는 서로 다른 오브젝트
// arrowPrefab은 원본이므로 변경하지 않음
}
5. 고급 사용법
오브젝트 풀링 (Object Pooling)
많은 오브젝트를 생성/삭제할 때는 오브젝트 풀링을 사용하는 것이 효율적입니다.
using UnityEngine;
using System.Collections.Generic;
public class ObjectPool : MonoBehaviour
{
public GameObject prefab;
public int poolSize = 10;
private List<GameObject> pool = new List<GameObject>();
void Start()
{
// 미리 오브젝트 생성
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
pool.Add(obj);
}
}
// 사용 가능한 오브젝트 가져오기
public GameObject GetObject()
{
foreach (GameObject obj in pool)
{
if (!obj.activeInHierarchy)
{
obj.SetActive(true);
return obj;
}
}
// 모두 사용 중이면 새로 생성
GameObject newObj = Instantiate(prefab);
pool.Add(newObj);
return newObj;
}
// 오브젝트 반환 (비활성화)
public void ReturnObject(GameObject obj)
{
obj.SetActive(false);
}
}
6. 정리
Instantiate()
- 용도: 프리팹이나 오브젝트를 복제하여 생성
- 위치 지정:
Instantiate(prefab, position, rotation) - 주의: null 체크 필수, 메모리(memory) 관리 중요
Destroy()
- 용도: 오브젝트를 메모리(memory)에서 제거
- 즉시 삭제:
Destroy(gameObject) - 지연 삭제:
Destroy(gameObject, delay) - 주의: 삭제 후 접근하지 않기
베스트 프랙티스
- 필요할 때만 생성: 불필요한 생성은 성능 저하
- 적절히 삭제: 메모리(memory) 누수 방지
- 프리팹 사용: 재사용 가능한 오브젝트는 프리팹으로
- 오브젝트 풀링: 자주 생성/삭제하는 경우 고려
연습 문제
-
스페이스바를 누르면 총알을 생성하는 스크립트를 작성하세요.
-
화면 밖으로 나간 오브젝트를 자동으로 삭제하는 스크립트를 작성하세요.
-
1초마다 랜덤한 위치에 코인을 생성하고, 5초 후에 자동으로 삭제하는 스크립트를 작성하세요.