메모리풀 스크립트
using System.Collections;
using System.Collections.Generic;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
//-----------------------------------------------------------------------------------------
// 메모리 풀 클래스
// 용도 : 특정 게임오브젝트를 실시간으로 생성과 삭제하지 않고,
// : 미리 생성해 둔 게임오브젝트를 재활용하는 클래스입니다.
//-----------------------------------------------------------------------------------------
// MonoBehaviour 상속 안받음. IEnumerable 상속시 foreach 사용 가능
// System.IDisposable 관리되지 않는 메모리(리소스)를 해제 함
public class MemoryPool : IEnumerable, System.IDisposable
{
class Item
{
public bool active; // 오브젝트가 사용하고 있는 중인지 판단하는 변수
public GameObject gameObject; // 저장할 오브젝트
}
Item[] table;
public IEnumerator GetEnumerator()
{
if (table == null) // 만약 table이 객체화 되지 않았다면?
yield break; // 함수를 그냥 탈출
// count는 table의 길이 (즉, 배열의 크기)
int count = table.Length;
for (int i = 0; i < count; i++) //총 count만큼 반복
{
Item item = table[i];
// item에 table의 i위치에 해당하는 객체를 대입
if (item.active) // item이 사용중이면
{
yield return item.gameObject; // 현 item의 오브젝트를 반환
}
}
}
//-------------------------------------------------------------------------------------
// 메모리 풀 생성
// original : 미리 생성해 둘 원본소스
// count : 풀 최고 갯수
//-------------------------------------------------------------------------------------
public void Create(Object original, int count)
{
Dispose(); // 메모리풀 초기화
table = new Item[count]; // count 만큼 배열을 생성
for (int i = 0;i < count;i++) // count 만큼 반복
{
Item item = new Item();
item.active = false;
item.gameObject = GameObject.Instantiate(original) as GameObject;
// original을 GameObject 형식으로 item.gameObject에 저장
item.gameObject.SetActive(false);
// SetActive는 활성화 함수인데 메모리에만 올릴 것이므로 비활성화 상태로 저장
table[i] = item;
}
}
//-------------------------------------------------------------------------------------
// 새 아이템 요청 - 쉬고 있는 객체를 반납한다.
//-------------------------------------------------------------------------------------
public GameObject NewItem() // GetEnumerator()와 비슷
{
if (table == null)
return null;
int count = table.Length;
for (int i = 0; i < count; i++)
{
Item item = table[i];
if (item.active == false)
{
item.active = true;
item.gameObject.SetActive (true);
return item.gameObject;
}
}
return null;
}
//--------------------------------------------------------------------------------------
// 아이템 사용종료 - 사용하던 객체를 쉬게한다.
// gameOBject : NewItem으로 얻었던 객체
//--------------------------------------------------------------------------------------
public void RemoveItem(GameObject gameObject)
{
if (table == null || gameObject == null)
return;
int count = table.Length;
for (int i = 0; i < count; i++)
{
Item item = table[i];
// 매개변수 gameObject와 item의 gameObject가 같다면
if (item.gameObject == gameObject)
{
// active 변수를 false로
item.active = false;
// 그리고 게임오브젝트를 비활성화 시킨다.
item.gameObject.SetActive(false) ;
break;
}
}
}
//--------------------------------------------------------------------------------------
// 모든 아이템 사용종료 - 모든 객체를 쉬게한다.
//--------------------------------------------------------------------------------------
public void ClearItem()
{
if(table == null) return;
int count = table.Length;
for (int i = 0;i < count; i++)
{
Item item = table[i];
if (item != null & item.active)
{
item.active = false;
item.gameObject.SetActive(false) ;
}
}
}
//--------------------------------------------------------------------------------------
// 메모리 풀 삭제 (게임 종료 or 플레이어 사망)
//--------------------------------------------------------------------------------------
public void Dispose()
{
if (table == null) return;
int count = table.Length;
for (int i = 0; i < count; i++)
{
Item item = table[i];
GameObject.Destroy(item.gameObject);
// 메모리 풀을 삭제하는 것이기 때문에 모든 오브젝트를 Destroy 처리
}
table = null;
}
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
플레이어 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CsPlayerFire : MonoBehaviour
{
//투사체가 사라져야 할 조건에서 Collider를 비활성화를 시키고
//그걸 캐치해서 미사일을 돌려보내는 방법
public GameObject BoltPrefab; // 복제할 투사체 오브젝트
public Transform BoltMuzzle; // 총구 위치
public bool FireState; // 투사체 발사 준비 여부
public float FireDelay; // 투사체 발사 딜레이
public int BoltMaxPool; // 메모리풀에 저장할 투사체 갯수
MemoryPool MPool; // 메모리풀
GameObject[] BoltArray; // 메모리풀과 연동하여 사용할 투사체 배열
private void OnApplicationQuit()
{
// 메모리풀 청소
MPool.Dispose();
}
void Start()
{
// 메모리풀 준비(초기화)
MPool = new MemoryPool();
// Bolt투사체를 MaxPool만큼 생성
MPool.Create(BoltPrefab, BoltMaxPool);
// 배열 준비(초기화) 이때 모든 값은 null이 됨
BoltArray = new GameObject[BoltMaxPool];
}
IEnumerator FireCycleControl()
{
// 처음에 FireState를 false로 만들고
FireState = false;
// FireDelay초 후에
yield return new WaitForSeconds(FireDelay);
// FireState를 true로 만든다.
FireState = true;
}
void Shoot()
{
if (FireState == true)
{
StartCoroutine(FireCycleControl());
// 미사일 풀에서 발사되지 않은 미사일을 찾아서 발사
for (int i = 0; i < BoltMaxPool; i++)
{
// 만약 미사일배열[i]가 비어있다면
if (BoltArray[i] == null)
{
// 메모리풀에서 미사일을 가져온다.
BoltArray[i] = MPool.NewItem();
// 해당 미사일의 위치를 미사일 발사지점으로 맞춘다.
BoltArray[i].transform.position = BoltMuzzle.transform.position;
// 발사 후에 for문을 바로 빠져나간다.
break;
}
}
//SoundManager.Instance.FireSound()
}
// 미사일이 발사될때마다 미사일을 메모리풀로 돌려보내는 것을 체크한다.
for (int i = 0;i < BoltMaxPool;i++)
{
// 만약 미사일[i]가 활성화 되어있다면
if (BoltArray[i])
{
// 미사일[i]의 Collider2D가 비활성 되었다면
if (BoltArray[i].GetComponent<Collider2D>().enabled == false)
{
// 다시 Collider2D를 활성화 시키고
BoltArray[i].GetComponent <Collider2D>().enabled = true;
// 미사일을 메모리로 돌려보내고
MPool.RemoveItem(BoltArray[i]);
// 가리키는 배열의 해당 항목도 null(값 없음)로 만든다.
BoltArray[i] = null;
}
}
}
}
// Update is called once per frame
void Update()
{
Shoot();
}
}
투사체 스크립트
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CsPlayerBolt : MonoBehaviour
{
public GameObject explosiveEffect;
public float bulletSpeed;
private void OnTriggerEnter2D(Collider2D collision)
{ // 충돌한 물체의 태그가 Enemy일 경우
if (collision.gameObject.tag == "Enemy")
{
// 투사체의 Collider 제거
this.gameObject.GetComponent<Collider2D>().enabled = false;
// 폭발 이펙트 생성
Instantiate(explosiveEffect, transform.position * 1.1f, transform.rotation);
}
}
void Update()
{
// 발사체 up 방향으로 실시간 이동
transform.Translate(Vector2.up * bulletSpeed * Time.deltaTime);
}
}