유니티 심화

오브젝트 풀링 - 총알, 이펙트

다모아 2023. 8. 28. 16:58

EffectPoolManager

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

public class EffectPoolManager : MonoBehaviour
{
    public static EffectPoolManager instance;
    //리스트로 이펙트 풀 생성
    public List<GameObject> effectPool = new List<GameObject>();
    //이펙트 프리팹 가져오기
    [SerializeField]
    private GameObject effectPrefab;
    //몇개나 할지 max정하기
    private int maxEffects = 10;
    //코루틴 방지
    private Coroutine effectRoutine;
    private void Awake()
    {
        instance = this;
        DontDestroyOnLoad(this.gameObject);
    }
    // Start is called before the first frame update
    void Start()
    {
        for(int i = 0; i < this.maxEffects; i++)
        {
            //생성
            GameObject effect = Instantiate(this.effectPrefab);
            //꺼놔야지
            effect.SetActive(false);
            //부모 위치
            effect.transform.SetParent(this.transform);
            //리스트에 저장
            this.effectPool.Add(effect);
        }    
    }

    public GameObject GetEffect()
    {
        //켜져있는게 있는지 없는지
        foreach(GameObject effect in effectPool)
        {
            if(effect.activeSelf == false)
            {
                effect.transform.SetParent(null);
                return effect;
            }
        }
        return null;
    }

    public void StopEffect(GameObject effect)
    {
        if(this.effectRoutine != null)
        {
            this.StopCoroutine(this.effectRoutine);
        }
        this.effectRoutine = this.StartCoroutine(this.CoStopEffect(effect));
    }

    private IEnumerator CoStopEffect(GameObject effect)
    {
        yield return new WaitForSeconds(2.0f);
        //비활성화
        effect.SetActive(false);
        //위치
        effect.transform.SetParent(this.transform);
    }
}

 

BulletPool

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

public class BulletPool : MonoBehaviour
{
    public static BulletPool instance;
    //리스트로 풀 구성
    public List<GameObject> bulletPool = new List<GameObject>();
    //누구인지 알기
    [SerializeField]
    private GameObject bulletPrefab;
    //몇개나 만들지
    private int maxBullets = 10;

    public Action<GameObject> onRemove;
    private void Awake()
    {
        instance = this;
        DontDestroyOnLoad(this.gameObject);
    }

    // Start is called before the first frame update
    void Start()
    {
        for(int i = 0; i < this.maxBullets; i++)
        {
            GameObject bullet = Instantiate(this.bulletPrefab);
            //어디에 생성할지
            bullet.transform.SetParent(this.transform);
            //꺼두고
            bullet.SetActive(false);
            //리스트에 저장
            this.bulletPool.Add(bullet);
        }
    }

    public GameObject GetBullet()
    {
        foreach(GameObject bullet in bulletPool)
        {
            if(bullet.activeSelf == false)
            {
                bullet.transform.SetParent(null);
                return bullet;
            }
        }
        return null;
    }

    public void BulletStop(GameObject bullet)
    {
        bullet.SetActive(false);
        bullet.transform.SetParent(this.transform);
        onRemove(bullet);
    }
}

 

TestBullet

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

public class TestBullet : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

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

    private void OnCollisionEnter(Collision collision)
    {
        if(collision.collider.CompareTag("Wall"))
        {
            BulletPool.instance.BulletStop(this.gameObject);
        }
    }
}

 

ObjectPoolingMain

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

public class ObjectPoolingMain : MonoBehaviour
{
    [SerializeField]
    private Button btn;
    //경과시간
    private float elapsedTime = 0f;
    [SerializeField]
    private BulletPool bulletPool;
    // Start is called before the first frame update
    void Start()
    {
        BulletPool.instance.onRemove = (target) => {
            //결과가져오기
            GameObject effect = EffectPoolManager.instance.GetEffect();
            //위치 조정
            effect.transform.position = target.transform.position;
            //활성화
            effect.SetActive(true);
            //2초 뒤 비활성화
            EffectPoolManager.instance.StopEffect(effect);
        };

        this.btn.onClick.AddListener(() => {
            //결과 가져오기
            GameObject bullet = bulletPool.GetBullet();
            //위치 조정
            bullet.transform.position = Vector3.zero;
            //활성화
            bullet.SetActive(true);
        });
    }
}