EasyCastleUNITY

오브젝트 풀링 연습 본문

유니티 심화

오브젝트 풀링 연습

EasyCastleT 2023. 8. 28. 16:33

한개의 여러 개의 오브젝트를 담았지만, 분리해서 하는 것이 좋음

TestBullet1 -> 총알 컴포넌트

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

public class TestBullet1 : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 1.0f;


    private void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);    
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.CompareTag("Wall"))
        {
            TestBulletPoolManager.instance.ReleaseBullet(this.gameObject);
            Debug.Log("벽과 충돌");
        }
    }


}

TestWall -> 벽 컴포넌트: 벽에서 피격 이펙트를 처리 

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

public class TestWall : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.CompareTag("Bullet"))
        {
            ContactPoint cp = collision.GetContact(0);
            Quaternion cpRot = Quaternion.LookRotation(-cp.normal);

            GameObject sparkGo = TestBulletPoolManager.instance.GetEffectInPool(cp.point, cpRot);
            sparkGo.transform.SetParent(null);
            sparkGo.SetActive(true);
            StartCoroutine(this.CoComeBackExplosionPool(sparkGo));
        }
    }

    private IEnumerator CoComeBackExplosionPool(GameObject go)
    {
        yield return new WaitForSeconds(0.5f);
        TestBulletPoolManager.instance.ReleaseEffect(go);
        yield return null;
    }
}

TestBulletPoolManager -> 오브젝트 풀링을 할 때 사용할 오브젝트를 관리하는 스크립트, 싱글톤으로 어디서나 접근 가능

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

public class TestBulletPoolManager : MonoBehaviour
{
    //총알을 미리 생성해 저장할 리스트 
    [SerializeField] private List<GameObject> bulletPool = new List<GameObject>();
    //오브젝트 풀에 생성할 총알의 최대 개수
    [SerializeField] private int maxBullets = 15;

    //총알 부딫힘 effect를 미리 생성해 저장할 리스트 
    [SerializeField] private List<GameObject> effectPool = new List<GameObject>();
    //오브젝트 풀에 생성할 effect의 최대 개수 
    [SerializeField] private int maxEffects = 15;

    //싱글톤 인스턴스 선언
    public static  TestBulletPoolManager instance = null;
    //총알 프리팹
    [SerializeField] private GameObject bulletPrefab;
    //effect 프리팹 
    [SerializeField] private GameObject effectPrefab;

    public System.Action onPlayComplete;

    private void Awake()
    {
        if(instance == null)
        {
            instance = this;
        }
        else if (instance != null)
        {
            Destroy(this.gameObject);
        }
        DontDestroyOnLoad(this.gameObject);
    }
    // Start is called before the first frame update
    void Start()
    {
        this.CreateBulletPool();
        this.CreateEffectPool();
    }
    

    private void CreateBulletPool()
    {
        for(int i=0; i<this.maxBullets; i++)
        {
            GameObject bullet = Instantiate<GameObject>(this.bulletPrefab);
            bullet.SetActive(false);
            bullet.transform.SetParent(this.transform);
            this.bulletPool.Add(bullet);
        }
    }

    private void CreateEffectPool()
    {
        for(int i=0; i < this.maxEffects; i++)
        {
            GameObject effect = Instantiate<GameObject>(this.effectPrefab);
            effect.SetActive(false);
            effect.transform.SetParent(this.transform);
            this.effectPool.Add(effect);
        }
    }
    public GameObject GetBulletInPool()
    {
        foreach (GameObject bullet in this.bulletPool)
        {
            if(bullet.activeSelf == false)
            {
                return bullet;
            }
        }
        return null;
    }

    public GameObject GetEffectInPool(Vector3 pos, Quaternion rot)
    {
        foreach(GameObject effect in this.effectPool)
        {
            if(effect.activeSelf == false)
            {
                effect.transform.position = pos;
                effect.transform.rotation = rot;
                return effect;
            }
        }
        return null;
    }
    //반환
    public void ReleaseBullet(GameObject bulletGo)
    {
        bulletGo.SetActive(false);
        bulletGo.transform.SetParent(this.transform);
    }

    public void ReleaseEffect(GameObject effectGo)
    {
        effectGo.SetActive(false);
        effectGo.transform.SetParent(this.transform);
        Debug.Log("<color=red>Effect 반환 실행!</color>");
    }
}

TestObjectPoolingMain -> 버튼 누르면 총알 발사 

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

public class TestObjectPoolingMain : MonoBehaviour
{
    [SerializeField] private Button btn;
    // Start is called before the first frame update
    void Start()
    {
        this.btn.onClick.AddListener(() => {
            GameObject bullet = TestBulletPoolManager.instance.GetBulletInPool();
            bullet.transform.SetParent(null); //밖으로 빼기 
            bullet.transform.localPosition = Vector3.zero;
            bullet.SetActive(true);
        });
    }
    
}

1.총알이 벽을 맞추면, 해당 위치에 피격 이펙트가 발생

2. 해당 피격 이펙트는 0.5초 재생하고 다시 오브젝트 풀로 돌아간다. 

실행영상