#유니티 #오브젝트생성 #디자인패턴 ObjectPool

sejun-Lee·2025년 4월 15일

UnityEngine

목록 보기
2/12

<오브젝트 생성 -프리팹 스폰>

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    public GameObject prefab;
    public GameObject target;
    //public GameObject makeOne;


    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            Spawn();
        }
        if (Input.GetKeyDown(KeyCode.D))
        {
            DeSpawn();
        }
    }

    public void Spawn()
    {
        //makeOne = new GameObject("Spawned GameObject"); // 새로운 게임 오브젝트 생성
        Instantiate(prefab, new Vector3(1, 1, 1), Quaternion.identity);    // Quaternion -> 회전값 / identity 회전없이
        // Instantiate 로 프리팹을 생성
    }

    public void DeSpawn()
    {
        Destroy(target, 3); // 3초 뒤에 target을 파괴
    }
}

<디자인 패턴 ObjectPool>

포탄을 미리 일정 수 풀에 생성해서 보관 및 사용

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/*      디자인 패턴 ObjectPool       */

/*
<오브젝트 풀 패턴>
프로그램 내에서 빈번하게 재활용하는 인스턴스들을 풀에 보관한 뒤
인스턴스의 생성&삭제 대신 대여&반납을 사용하는 기법

<구현>
1. 인스턴스들을 보관할 풀을 생성
2. 프로그램의 시작시 풀에 인스턴스들을 생성하여 보관
3. 인스턴스 생성이 필요할 때 풀에서 대여하여 사용
4. 인스턴스 삭제가 필요할 때 풀에 반납하여 보관

<장점>
1. 빈번하게 사용하는 인스턴스 생성에 소요되는 오버헤드를 줄임
2. 빈번하게 사용하는 인스턴스 삭제에 부담되는 가비지 콜렉터의 동작을 줄임

<주의점>
1. 미리 생성해놓은 인스턴스들이 사용하지 않는 경우에도 메모리를 차지하고 있음
2. 오브젝트 풀을 힙영역의 여유공간이 줄어들어 오히려 프로그램에 부담이 되는 경우가 있음.
 */


public class ObjectPool : MonoBehaviour
{
    [SerializeField] List<PooledObject> pool = new List<PooledObject>();    // 미리 보관할 풀을 리스트로 생성
    [SerializeField] PooledObject prefab;
    [SerializeField] int size;  // 처음에 춘비해놓을 인스턴스 개수
    [SerializeField] int capacity; // 풀의 최대 개수

    private void Awake()
    {
        for (int i = 0; i < size; i++)
        {
            PooledObject instance = Instantiate(prefab);    // prefab을 복제하여 인스턴스 생성
            instance.gameObject.SetActive(false);   // 비활성화 해서 
            pool.Add(instance); // 인스턴스를 풀에 보관
        }
    }

    public PooledObject GetPool(Vector3 position, Quaternion rotation)  // 대여
    {                           //      어느위치에서 어느각도로 생성할건지
        if (pool.Count == 0) // 풀에 인스턴스가 없으면
        {
            return Instantiate(prefab, position, rotation); // 새로 생성
        }

        PooledObject instance = pool[pool.Count - 1];   // 풀에서 인스턴스 맨 마지막거 가져오기
        pool.RemoveAt(pool.Count - 1); // 풀에서 인스턴스 제거

        instance.returnPool = this; // 인스턴스의 returnPool 변수에 현재 풀을 설정
        instance.transform.position = position; // 위치 설정
        instance.transform.rotation = rotation; // 회전 설정
        instance.gameObject.SetActive(true); // 활성화

        return instance; // 인스턴스 반환
    }

    public void ReturnPool(PooledObject instance)   // 반납
    {
        if (pool.Count >= capacity)
        {
            Destroy(instance.gameObject); // 풀의 개수가 최대치면 인스턴스 삭제
        }
        instance.gameObject.SetActive(false); // 인스턴스 비활성화
        pool.Add(instance); // 풀에 추가
    }

}

사용한 오브젝트 풀에 반납

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PooledObject : MonoBehaviour
{
    public ObjectPool returnPool; // 오브젝트 풀을 참조하기 위한 변수
    [SerializeField] float returnTime; // 오브젝트 풀에 반납될 시간
    private float timer; // 현재 시각

    private void OnEnable()
    {
        timer = returnTime; // 오브젝트가 활성화될 때 타이머 초기화
    }
    private void Update()
    {
        timer -= Time.deltaTime; // 타이머 감소 - 프레임 마다 진행된 시간
        if (timer <= 0) // 타이머가 0 이하가 되면
        {
            RetuenPool(); // 오브젝트 풀에 반납
        }
    }

    public void RetuenPool()
    {
        if (returnPool == null)
        {
            Destroy(gameObject); // returnPool이 null이면 오브젝트 풀에 반납하지 않고 삭제
        }
        else
        {
            returnPool.ReturnPool(this); // 오브젝트 풀에 반납
        }
            
    }
}

포탄 발사 코드 - 발사 후 3초뒤 삭제

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shooter : MonoBehaviour
{
    [SerializeField] GameObject bulletPrefab; // 총알 프리팹
    [SerializeField] Transform muzzlePoint; // 총알 발사 위치
    [SerializeField] ObjectPool bulletPool; // 총알 오브젝트 풀

    [Range(10, 30)]
    [SerializeField] float bulletSpeed; // 발사 속도


    public void Fire()
    {
        // 총알을 발사하는 메서드
        GameObject instance = Instantiate(bulletPrefab, muzzlePoint.position, muzzlePoint.rotation); // 총알 인스턴스 생성
                                                                                                     // 머즐 포인트 위치와 회전으로 총알 생성
        //PooledObject instance = bulletPool.GetPool(muzzlePoint.position, muzzlePoint.rotation);   
        // 총알 풀에서 총알 인스턴스 가져오기
        Rigidbody bulletRigidbody = instance.GetComponent<Rigidbody>(); // 총알의 리지드바디 컴포넌트 가져오기
        bulletRigidbody.velocity = muzzlePoint.forward * bulletSpeed; // 총알의 속도 설정

        Destroy(instance, 3); // 3초 후 총알 삭제

    }


}                     
profile
초보 개발자

0개의 댓글