[유니티] UNITY (두번째: Pooling방식) 총쏘기 게임 만들 때 총알을 생성하는 방법은 무엇이 있나요?
안녕하세요. 오늘도 태풍이 지나가고 가을 구름이 떠다니는 쾌청하고 평화로운 하루입니다.
이전에 총알을 생성 및 파괴하는 방식(Instantite/destroy)에 대해서 설명했는데, 이번에는 풀(Pool)방식에 대해서 알아보겠습니다.
풀링 또는 풀 방식이라고 하는 것은 단어 뜻 그대로 풀장에 물을 미리 모아 놓고 필요한 만큼 그때 그때 쓰겠다는 것입니다. 총알을 필요할 때마다 생성하고 파괴하면 CPU에 부하가 발생합니다. 그 원인은 오브젝트를 생성하고 파괴할 때 발생하는 불필요한 메모리를 정리하기위해서 GC(Garbage Colletor)가 생성되는데, 최대한 방지할 필요가 있습니다.
총알을 미리 만들어 놓고 필요할 때 SetActive 값을 True로해서 사용하고, 필요없을 때는 False 로해서 보관만하는 방식으로 처리하는 방법을 알아보겠습니다.
그럼, How??? 어떻게 Pooling 방식으로 총알이 나가도록 할지 알아보겠습니다.
아래의 순서로 설명을 하겠습니다.
1. 총알 Prefab 생성
2. 총알 미리 생성해서 List 형태로 보관했다가 발사하기
3. 실행화면보기
자세한 방법은 아래의 예제를 통해서 얘기하겠습니다.
[예제] 총에서 총알을 생성하기(Pooling 방식)
먼저, 이전에 했던 것 처럼 아래와 같이 화면을 구성하였습니다. Cube를 3개 추가해서 총을 만들고 이름을 ' Chong '으로 하고, 그 옆에 총알역할을 할 수 있는 Sphere를 1개 추가해서 이름을 ' ChongAl ' 이라고 했습니다.

1. 총알 Prefab 생성.
-. 총알이 날아가게 하기 위해서 물리적요소인 Rigidbody를 추가해서 AddForce() 함수를 사용할 것입니다. 그래서 , ' ChongAl ' 오브젝트에 ' Add Component ' 를 눌러서 ' Rigidbody ' 를 추가하고 Use Gravity 속성은 ' 체크해제 ' 해야합니다. 만약에 Use Gravity가 체크되어 있어면 중력의 힘을 받아서 아래로 총알이 떨어져서 원하는 효과를 얻기 힘듭니다.

-. 아래와 같이 ' Al ' 이라는 이름으로 스크립터를 생성합니다.
using UnityEngine;
public class Al : MonoBehaviour
{
public void Al_Bogan() //다시 총알을 보관하기 위해 비활성화함
{
Invoke("Al_End", 0.4f); //0.4초 후에 Al_End 실행
}
public void Al_End()
{
gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero; //AddForce를 초기화함
gameObject.SetActive(false); // 총알을 비활성화함
}
}
-. ' Al '스크립트를 ' ChongAl ' 오브젝트에 ' 드래그앤드롭 ' 하여 넣어줍니다.
-. Assets 밑에 ' Prefabs '라는 빈 폴더를 만들고 ' ChongAl ' 오브젝트를 드래그앤드롭 하면 아래와 같이 파랗게 글자색이 바뀌면서 Prefab으로 됩니다. 그리고나서, Hierarchy 에 있는 ChongAl 오브젝트를 지우면 사용할 총알 Prefab이 완성됩니다.

2. 총알 미리 생성해서 List 형태로 보관했다가 발사하기
-. 빈 오브젝트를 생성해서 이름을 Startposi 라고 두고 총알이 생성될 위치인 총구앞에 옮겨둡니다.

-. 아래와 같이 ' Chong ' 이라는 이름으로 스크립터를 생성합니다.
using System.Collections.Generic;
using UnityEngine;
public class Chong : MonoBehaviour
{
public GameObject Start_Posi; //총알 발사위치를 가져옴
public GameObject Chong_Al; //총알 Prefab을 가져옴
public int Al_Size = 10; // 미니 만들 총알갯수
public List<GameObject> Al_List = new List<GameObject>(); // 오브젝트용 리스트 생성
GameObject Balsa; //총알용 게임오브젝트 변수
private void Al_Mandum() //총알을 만드는 함수
{
for (int i = 0; i < Al_Size; i++) //기본적으로 10개의 총알을 생성함
{
Balsa = Instantiate(Chong_Al, transform.position, Quaternion.identity); //총알 생성
Balsa.SetActive(false); // 총알 오브젝트의 Active 값을 false 함
Al_List.Add(Balsa); // 리스트에 추가
}
}
public GameObject GetAl() //총알리스트중에서 비활성화된 오브젝트를 반환함
{
for (int i = 0; i < Al_List.Count; i++) //총알리스트갯수만큼 for문
{
if (!Al_List[i].activeSelf) // 총알이 비활성화되었다면
{
return Al_List[i]; // 비활성화된 총알을 반환해라
}
}
int tmp = Al_List.Count; //총알리스트마지막값을 기억해라
Al_Mandum(); // 비활성화된 총알이 모두 없어면 다시 10개 만들어라
return Al_List[tmp]; // 다시만든 10개중 첫번째를 반환해라
}
private void Awake()
{
Al_Mandum(); // 총알을 미리 10개 만들어라
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)) //스페이스 키를 누르면
{
Balsa = GetAl(); // 비활성화된 총알을 오브젝트변수에 넣어라
Balsa.SetActive(true); //활성화 해라
Balsa.transform.position = Start_Posi.transform.position; // 생성된 총알을 총구로 이동시킴
Balsa.GetComponent<Rigidbody>().AddForce(new Vector3(1, 0, 0) * 20, ForceMode.Impulse); // 총알을 총구앞쪽 방향으로 발사시킴
Balsa.GetComponent<Al>().Al_Bogan(); // 활성화된 총알을 0.4초뒤에 비활성화해라
}
}
}
-. ' Chong '스크립트를 ' Chong ' 오브젝트에 ' 드래그앤드롭 ' 하여 넣어줍니다.
-. ' Start_Posi ' 변수에 ' Startposi ' 오브젝트를 드래그앤드롭으로 넣고, ' Chong_Al ' 변수에 프리팹에 있는 ' ChongAl ' 오브젝트를 드래그앤드롭으로 넣습니다.

3. 실행화면
-. 이제 실행하고 스페이스바를 누르면 아래와 같이 총알이 잘 동작하는 것을 확인 할 수 있습니다. 여러번 누르면 총알이 계속해서 생성되서 날아가는 것을 볼 수 있습니다.
-. Hierarchy 창을 보면 총알 오브젝트가 활성화되었다가 비활성화되는 것을 반복하는 것을 확인 할 수 있습니다.

*총알에 비활성화하기위한 스크립터를 생성한 이유
; 0.4초의 시간지연 후에 총알이 비활성화되어야 하므로 그것을 메인 스크립터에서 비활성화하게 하려면 각각의 총알에 대해서 계속해서 오브젝트를 유지시켜야하는 번거로움이 있기 때문입니다. 그래서 각각의 오브젝트를 비활성화하거나 파괴하는 경우에는 주로 없애려는 오브젝트에 스크립터를 넣어서 처리하게 됩니다.
* 참고 : AddForce() 함수의 초기화
-. AddForce()를 여러번 사용하게 되면 계속해서 기존의 힘에 추가해서 발생합니다. 그래서, 처음 총알의 속도가 뒤로 갈수록 점검 커지는 것을 볼 수 있습니다. 속도 뿐만 아니라 방향도 처음 총알의 마지막 방향의 영향을 받습니다. 함수명에 왜 ' Add ' 라는 글자가 들어가는지 알 수 있는 대목입니다.
그래서 AddForce() 함수를 같은 오브젝트에 여러번 사용하게 될 경우에는 초기화를 해주어야 합니다.
방법은 아래와 같습니다.
GetComponent<Rigidbody>().velocity = Vector3.zero;
List<>를 사용해서 생성된 총알을 보관하였다가 사용해 보았습니다. 그 밖에 배열(Array)이나 큐(Queue)나 스택(Stack)을 사용해서 총알을 보관하였다가 사용할 수 있습니다. 그럼 나머지는 또 다음에 글을 남겨보도록 하겠습니다.
그럼 오늘도 즐유!(즐거운 유니티) ^^
'유니티 프로그램' 카테고리의 다른 글
| [유니티] UNITY 시간이 느리게 흐르게 하거나 멈추게 하려면 어떻게 할까요? (0) | 2022.09.26 |
|---|---|
| [유니티] UNITY (첫번째: 생성/파괴방식) 총쏘기 게임 만들 때 총알을 생성하는 방법은 무엇이 있나요? (0) | 2022.09.13 |
| [유니티] UNITY 게임 시작 화면에 간단하게 마우스에 반응하는 메뉴목록을 넣는 방법은 무엇입니까? (0) | 2022.09.05 |
| [유니티] UNITY string형 값으로 전달받은 자료를 어떻게 int형으로 바꿔야 할까요? (1) | 2022.08.29 |
| [유니티] UNITY 게임오브젝트 여러개를 동시에 안보이게 하려면 어떻게 해야 할까요? (0) | 2022.08.23 |