본문 바로가기

Unity 공부/Unity_2D

[Day 3] 오브젝트 풀링으로 소환

[ 오브젝트 풀링으로 소환 ] --> 몬스터가 시간에 지남에 따라 자동으로 소환되는 기믹 만들기

  • Prefabs 폴더 만들기 --> Hierachy의 Enemy 종류별로 Prefabs 안쪽에 드래그&드랍
    (많은 종류의 오브젝트를 관리하는데 효과적) 
  • Hierachy의 Enemy를 Prefabs 폴더에 저장했다면, Hierachy에서 삭제
  • Hierachy에 Create Empty --> PoolManager(Prefabs을 관리)
  • C# 스크립트 추가 -> PoolManager
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolManager : MonoBehaviour{
    public GameObject[] prefabs;

    List<GameObject>[] pools;

    private void Awake(){
        pools = new List<GameObject>[prefabs.Length];

        for(int index = 0; index < pools.Length; index++){
            pools[index] = new List<GameObject>();
        }
    }

    public GameObject Get(int index) {
        GameObject select = null;
        
        // ... 선택한 풀의 비활성화 된 게임 오브젝트 접근
        foreach (GameObject item in pools[index]){
            if (!item.activeSelf){
            	// ... 발견하면 select 변수에 할당
                select = item;
                select.SetActive(true);
                break;
            }
        }
		
        // ... 게임 오브젝트가 모두 활성화 되어 있다면?
        if (!select){
        	// ... 새롭게 생성하고 select 변수에 할당
            select = Instantiate(prefabs[index], transform); // 프리펩에 있는 오브젝트를 복사하여 변수에 할당
            pools[index].Add(select); // 생성된 오브젝트를 풀 리스트에 Add 함수로 추가
        }
        return select;
    }
}
  • 기존 Enemy 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public float speed;
    public float hp;
    public float maxHp;
    public RuntimeAnimatorController[] animCon;
    public Rigidbody2D target;

    bool isLive;

    Rigidbody2D rigid;
    Animator anim;
    SpriteRenderer spriter;

    void Awake()
    {
        rigid = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
        spriter = GetComponent<SpriteRenderer>();
    }

    // Update is called once per frame
    private void FixedUpdate(){

        if (!isLive){
            return;
        }

        Vector2 dirVec = target.position - rigid.position;
        Vector2 nextVec = dirVec.normalized * speed * Time.fixedDeltaTime;
        rigid.MovePosition(rigid.position + nextVec);
        rigid.velocity = Vector2.zero;
    }

    private void LateUpdate()
    {
        if (!isLive){
            return;
        }
        spriter.flipX = target.position.x < rigid.position.x;
    }

    private void OnEnable()
    {
        target = GameManager.instance.player.GetComponent<Rigidbody2D>(); // Enemy 스스로 플레이어를 타겟으로 초기화
    }

}
  • Hierachy의 Player\Spawner에 Create Empty --> Point(몬스터가 소환 될 지점)
  • Point를 Scene 바깥을 빙 두르듯 배치(Ctrl + D로 복사)
  • 기존의 Spawner 스크립트에 코드 추가
    ㅡ아래는 완성된 코드ㅡ
using System.Collections;
using System.Collections.Generic;
using UnityEditor.ShaderGraph.Internal;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    public Transform[] spawnPoint; // spawnPoint의 위치를 받는 변수

    float timer;

    private void Awake()
    {
        spawnPoint = GetComponentsInChildren<Transform>(); // 자신(Spawner)을 포함한 자식 오브젝트(Point)의 위치를 받음
    }

    void Update()
    {
        timer += Time.deltaTime;

        if (timer > 0.2f) // 일정 시간마다 소환
        {
            timer = 0;
            Spawn();  // 소환 함수 호출
        }
    }

    void Spawn() // 몬스터 소환 함수
    {
        GameObject enemy = GameManager.instance.pool.Get(0); // pool의 첫번째 엔트리를 enemy에 초기화
        enemy.transform.position = spawnPoint[Random.Range(1, spawnPoint.Length)].position; // enemy가 소환되는 위치는 자신(Spawner)을 제외한 자식 오브젝트(Point) 중 랜덤한 위치  
    }
}

 

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

 

★Slow and Steady★