씬에 있는 특정 오브젝트(ex. 몬스터)를 감지하게 하는 법 모음

2022. 3. 23. 10:01Unity3D/경험 기록

이번 포스팅에서는 씬에 있는 오브젝트(예를 들어 몬스터)와

상호작용해야 하는 오브젝트(Ex.플레이어)가 있을 경우,

대상 오브젝트를 플레이어 오브젝트가 감지하게끔 하는 방법을 정리할 것이다.

 


1. 감지가 필요할 때마다 매니져에서 감지 후 지시

 

    void LetPlayerShoot()
    {
        GameObject[] monsters = GameObject.FindGameObjectsWithTag("Monster");
        foreach(GameObject mon in monsters)
        {
            MonsterControl monster = mon.GetComponent<MonsterControl>();
            if (!monster.dieOnce)
            {
                player.SetMonsterTarget(monster);
                break;
            }
        }
    }

감지가 필요할 때마다 (Ex. 몬스터를 찾아야 할 때)

게임매니져에서 씬에 있는 몬스터들을 찾아 배열에 넣은 다음,

현재 살아 있는 몬스터를 배열에서 순회해 찾는다.

그리고 찾은 몬스터의 정보를 플레이어에게 타겟으로 넘겨준다.

그리고 몬스터가 죽을 때마다, (새로운 감지가 필요할 때)

OnDie 대리자에서 이 함수를 콜백하여 새로운 몬스터를 탐색한다.

플레이어는 타겟으로 넘겨받은 몬스터를 참조할 수 있게 된다.

 

이 코드의 문제점은 감지할 '때마다' 씬에 있는 전체 몬스터를 탐색하며,

배열에 넣고, 그걸 순회하는 과정을 반복해야 한다는 것이다.

몬스터가 많을 경우 새 몬스터를 찾으려할 때마다 심한 렉이 걸릴 수 있다.

 

 


2. 매니져에서 좀비 생성 후 리스트에 넣어 관리 & 

좀비가 플레이어 참조하여 인지시키기

 

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

public class Area : MonoBehaviour
{
    public GameObject zombiePrefab;
    private List<GameObject> zombieList;

    public void ResetArea()
    {
        RemoveAll();
        SpawnZombie();
    }

    public int ZombieRemaining
    {
        get { return ZombieList.Count; }
    }

    private void RemoveAll()
    {
        if (zombieList != null)
        {
            for (int i = 0; i < zombieList.Count; i++)
            {
                if (zombieList[i] != null)
                {
                    Destroy(zombieList[i]);
                }
            }
        }
        zombieList = new List<GameObject>();
    }

    private void SpawnZombie()
    {
        GameObject zombieObject = Instantiate<GameObject>(zombiePrefab.gameObject);
        zombieObject.transform.localPosition = transform.position + new Vector3(Random.Range(-4.9f, 4.9f), 0.5f, -4.9f);
        zombieObject.transform.SetParent(transform);
        zombieObject.GetComponent<Zombie>().MoveToAgent(agent.transform);
        zombieObject.GetComponent<Zombie>().OnDie += () =>
        {
            zombieList.Remove(zombieObject);
            Destroy(zombieObject, 2f);
        };
        zombieList.Add(zombieObject);
    }

    private void Start()
    {
        ResetArea();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Zombie : MonoBehaviour
{
    public float moveSpeed;
    public bool alive = true;

    public void MoveToAgent(Transform agent)
    {
        StartCoroutine(MoveRoutine(agent));
    }

    IEnumerator MoveRoutine(Transform agent)
    {
        while (true)
        {
            if (alive)
            {
                transform.LookAt(agent);

                transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
                
                if(Vector3.Distance(agent.transform.position, transform.position) < 4f)
                {
                    agent.gameObject.GetComponent<ManAgent>().NoticeZombie(this.gameObject);
                }
                
                yield return null;
            }
            else
            {
                break;
            }
        }
    }
}

보면 area 스크립트에서 좀비 생성 후 리스트에 넣어 관리하고 있다.

이렇게 하면 좀비가 죽었을 때 씬에서 없애기도 편하고,

removeAll()로 모든 좀비를 한번에 없애기도 용이하다.

 

그리고 좀비 스크립트에서는 플레이어에게 다가가다가,

일정 거리 이하가 되자 플레이어를 참조하여

NoticeZombie(this.gameObject)를 호출한다.

 

이렇게 플레이어가 몬스터를 감지하는 코드를 몬스터 스크립트에 작성하는 방법도 있다.