지금까지는 필요한 오브젝트를 만들때 아래 두 함수를 사용했습니다.
Destroy(gameOjbect);
Instantiate(gameObject);
그러나 Destroy와 Instantiate는 오브젝트를 생성, 삭제하면서 가비지(Garbage : 쓰레기 값)를 만듭니다. 이 가비지가 쌓이면 유니티에서 가비지컬렉트(GC : 쌓인 조각난 메모리를 비우는 기술)를 실행하는데, 이때 게임이 끊기게됩니다. 이를 방지하기 위해 오브젝트 풀링(Object Pooling)이란 기술을 사용합니다.
* 오브젝트 풀링이란? : 미리 생성해둔 풀에서 활성화/비활성화로 사용
게임이 시작할때 미리 오브젝트들을 만들어놓고 SetActive로 활성화/비활성화만 조작해서 오브젝트를 재사용합니다. 기존에 한 오브젝트의 생명이 Instantiate(생성) -> Destroy(삭제)로 끝났다면, 오브젝트 풀링을 사용함으로써 생명주기가 생성 -> 활성화 -> 비활성화 -> 활성화 -> 비활성화.... 반복으로 바뀝니다. 쳇바퀴 구조라고 보면 됩니다.
먼저 OjbectManager 오브젝트와 스크립트를 생성합니다.
OjbectManager 스크립트에 코드 입력
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectManager : MonoBehaviour
{
//--- Prefabs ---
//Enemy
public GameObject enemyLPrefab;
public GameObject enemyMPrefab;
public GameObject enemySPrefab;
//Item
public GameObject itemCoinPrefab;
public GameObject itemPowerPrefab;
public GameObject itemBoomPrefab;
//Bullet
public GameObject bulletPlayerAPrefab;
public GameObject bulletPlayerBPrefab;
public GameObject bulletEnemyAPrefab;
public GameObject bulletEnemyBPrefab;
//--- GameObjects ---
//Enemy
GameObject[] enemyL;
GameObject[] enemyM;
GameObject[] enemyS;
//Item
GameObject[] itemCoin;
GameObject[] itemPower;
GameObject[] itemBoom;
//Bullet
GameObject[] bulletPlayerA;
GameObject[] bulletPlayerB;
GameObject[] bulletEnemyA;
GameObject[] bulletEnemyB;
//GameObject for Copy
GameObject[] targetPool;
void Awake()
{
//Enemy
enemyL = new GameObject[20];
enemyM = new GameObject[20];
enemyS = new GameObject[20];
//Item
itemCoin = new GameObject[20];
itemPower = new GameObject[20];
itemBoom = new GameObject[20];
//Bullet
bulletPlayerA = new GameObject[20];
bulletPlayerB = new GameObject[20];
bulletEnemyA = new GameObject[20];
bulletEnemyB = new GameObject[20];
generate();
}
void generate() {
//Enemy
for (int i = 0; i < enemyL.Length; i++) {
enemyL[i] = Instantiate(enemyLPrefab);
enemyL[i].SetActive(false);
}
for (int i = 0; i < enemyM.Length; i++)
{
enemyM[i] = Instantiate(enemyMPrefab);
enemyM[i].SetActive(false);
}
for (int i = 0; i < enemyS.Length; i++)
{
enemyS[i] = Instantiate(enemySPrefab);
enemyS[i].SetActive(false);
}
//Item
for (int i = 0; i < itemCoin.Length; i++)
{
itemCoin[i] = Instantiate(itemCoinPrefab);
itemCoin[i].SetActive(false);
}
for (int i = 0; i < itemPower.Length; i++)
{
itemPower[i] = Instantiate(itemPowerPrefab);
itemPower[i].SetActive(false);
}
for (int i = 0; i < itemBoom.Length; i++)
{
itemBoom[i] = Instantiate(itemBoomPrefab);
itemBoom[i].SetActive(false);
}
//Bullet
for (int i = 0; i < bulletPlayerA.Length; i++)
{
bulletPlayerA[i] = Instantiate(bulletPlayerAPrefab);
bulletPlayerA[i].SetActive(false);
}
for (int i = 0; i < bulletPlayerB.Length; i++)
{
bulletPlayerB[i] = Instantiate(bulletPlayerBPrefab);
bulletPlayerB[i].SetActive(false);
}
for (int i = 0; i < bulletEnemyA.Length; i++)
{
bulletEnemyA[i] = Instantiate(bulletEnemyAPrefab);
bulletEnemyA[i].SetActive(false);
}
for (int i = 0; i < bulletEnemyB.Length; i++)
{
bulletEnemyB[i] = Instantiate(bulletEnemyBPrefab);
bulletEnemyB[i].SetActive(false);
}
}
public GameObject makeObj(string type) {
switch (type) {
case "EnemyL":
targetPool = enemyL;
break;
case "EnemyM":
targetPool = enemyM;
break;
case "EnemyS":
targetPool = enemyS;
break;
case "ItemCoin":
targetPool = itemCoin;
break;
case "ItemPower":
targetPool = itemPower;
break;
case "ItemBoom":
targetPool = itemBoom;
break;
case "BulletPlayerA":
targetPool = bulletPlayerA;
break;
case "BulletPlayerB":
targetPool = bulletPlayerB;
break;
case "BulletEnemyA":
targetPool = bulletEnemyA;
break;
case "BulletEnemyB":
targetPool = bulletEnemyB;
break;
}
for (int i = 0; i < targetPool.Length; i++)
{
if (!targetPool[i].activeSelf)
{
targetPool[i].SetActive(true);
return targetPool[i];
}
}
return null;
}
public GameObject[] getPool(string type) {
switch (type)
{
case "EnemyL":
targetPool = enemyL;
break;
case "EnemyM":
targetPool = enemyM;
break;
case "EnemyS":
targetPool = enemyS;
break;
case "ItemCoin":
targetPool = itemCoin;
break;
case "ItemPower":
targetPool = itemPower;
break;
case "ItemBoom":
targetPool = itemBoom;
break;
case "BulletPlayerA":
targetPool = bulletPlayerA;
break;
case "BulletPlayerB":
targetPool = bulletPlayerB;
break;
case "BulletEnemyA":
targetPool = bulletEnemyA;
break;
case "BulletEnemyB":
targetPool = bulletEnemyB;
break;
}
return targetPool;
}
}
ObjectManager 오브젝트에 스크립트를 할당하고 맵핑합니다.
실행하면 아래처럼 오브젝트들이 만들어져 비활성화로 게임을 시작하게 됩니다.
이제 이 만들어놓은 오브젝트를 이용하기 위해선, 기존에 Instantiate, Destroy 코드를 바꿔야합니다.
Instantiate는 maekObj, Destroy는 SetActive(false)를 사용합니다.
Destroy 예)
Item 스크립트
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "BorderBullet") {
gameObject.SetActive(false);
//Destroy(gameObject);
}
}
Instantiate 예)
Player 스크립트
void fire() {
if (!Input.GetButton("Fire1")) {
return;
}
if (curShotDelay < maxShotDelay) {
return;
}
switch (power) {
case 1:
GameObject bullet = objectManager.makeObj("BulletPlayerA");
bullet.transform.position = transform.position + new Vector3(0, 0.7f, 0);
//Instantiate(bulletObjA, transform.position + new Vector3(0, 0.7f, 0), transform.rotation);
...
case 2:
GameObject bulletR = objectManager.makeObj("BulletPlayerA");
bulletR.transform.position = transform.position + new Vector3(0.1f, 0.7f, 0);
//(bulletObjA, transform.position + new Vector3(0.1f, 0.7f, 0), transform.rotation);
GameObject bulletL = objectManager.makeObj("BulletPlayerA");
bulletL.transform.position = transform.position + new Vector3(-0.1f, 0.7f, 0);
//Instantiate(bulletObjA, transform.position + new Vector3(-0.1f, 0.7f, 0), transform.rotation);
...
case 3:
GameObject bulletRR = objectManager.makeObj("BulletPlayerA");
bulletRR.transform.position = transform.position + new Vector3(0.3f, 0.7f, 0);
//Instantiate(bulletObjA, transform.position + new Vector3(0.3f, 0.7f, 0), transform.rotation);
GameObject bulletLL = objectManager.makeObj("BulletPlayerA");
bulletLL.transform.position = transform.position + new Vector3(-0.3f, 0.7f, 0);
//Instantiate(bulletObjA, transform.position + new Vector3(-0.3f, 0.7f, 0), transform.rotation);
GameObject bulletCC = objectManager.makeObj("BulletPlayerB");
bulletCC.transform.position = transform.position + new Vector3(0, 0.7f, 0);
//Instantiate(bulletObjB, transform.position + new Vector3(0, 0.7f, 0), transform.rotation);
...
}
curShotDelay = 0;
}
'종스크롤 슈팅게임(1942)' 카테고리의 다른 글
10. 보조슈터 만들기 (0) | 2022.01.25 |
---|---|
9. 텍스트파일을 이용한 커스텀 배치 구현 (0) | 2022.01.25 |
7. 원근감 있는 무한 배경 만들기 (0) | 2022.01.21 |
6. 아이템과 필살기 구현하기 (0) | 2022.01.20 |
5. 간단한 UI 만들기 (0) | 2022.01.19 |