유니티 심화

절대강좌 유니티 - 애니메이션, 몬스터 [피격, 공격, 추적, 정지]

다모아 2023. 8. 23. 13:18

MonsterController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class MonsterController : MonoBehaviour
{
    public enum eState
    {
        Idle, Trace, Attack, Die
    }

    [SerializeField]
    private NavMeshAgent agent;
    private Transform playerTrans;

    [SerializeField]
    private float attackRange = 2f; //공격사거리
    [SerializeField]
    private float traceRange = 10f; //추적사거리

    [SerializeField]
    private eState state; //상태 저장 변수

    private bool IsDie = false;

    private Animator anim;

    private readonly int hashTrace = Animator.StringToHash("IsTrace");
    private readonly int hashAttack = Animator.StringToHash("IsAttack");
    private readonly int hashHit = Animator.StringToHash("Hit");
    // Start is called before the first frame update
    void Start()
    {
        //애니메이션 컴포넌트 가져오기
        this.anim = this.GetComponent<Animator>();
        //agent컴포넌트를 가져오고
        this.agent = this.GetComponent<NavMeshAgent>();
        ////타겟의 위치
        //GameObject playerGo = GameObject.FindWithTag("Player");
        //Transform playerTrans = playerGo.GetComponent<Transform>();
        //Vector3 playerPosition = playerTrans.position;

        this.playerTrans = GameObject.FindWithTag("Player").GetComponent<Transform>();

        //this.playerTrans = GameObject.FindWithTag("Player").transform;

        //this.agent.destination = this.playerTrans.position;

        this.StartCoroutine(this.CoCheckMonsterState());

        this.StartCoroutine(this.CoMonsterAction());
    }

    private IEnumerator CoCheckMonsterState()
    {
        while(true)
        {
            yield return new WaitForSeconds(0.3f);

            //플레이어와 거리계산
            float dis = Vector3.Distance(this.transform.position, this.playerTrans.position);
            
            if (dis <= attackRange)
            {
                //공격사거리에 들어왔는지
                this.state = eState.Attack;
                
            }
            else if(dis <= this.traceRange)
            {
                //아니면 추적사거리에 들어왔는지
                this.state = eState.Trace;
            }
            else
            {
                //공격사걸에도 추적사거리에도 안들어왔는지
                this.state = eState.Idle;
            }
        }
    }

    private IEnumerator CoMonsterAction()
    {
        while (!this.IsDie)
        {
            yield return new WaitForSeconds(0.3f);

            switch(this.state)
            {
                case eState.Idle:
                    //추적 중지
                    this.agent.isStopped = true;
                    this.anim.SetBool(hashTrace, false);
                    break;
                case eState.Trace:
                    //플레이어 좌표로 이동
                    this.agent.SetDestination(this.playerTrans.position);
                    this.agent.isStopped = false;
                    this.anim.SetBool(hashTrace, true);
                    this.anim.SetBool(hashAttack, false);
                    break;
                case eState.Attack:
                    this.anim.SetBool(hashAttack, true);
                    break;
                case eState.Die:
                    break;
            }
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        if(collision.collider.CompareTag("Bullet"))
        {
            //충돌한 총알 삭제
            Destroy(collision.gameObject);
            //피격 리액션 애니메이션 실행
            this.anim.SetTrigger(hashHit);
        }
    }
    private void OnDrawGizmos()
    {
        if (this.state == eState.Trace)
        {
            Gizmos.color = Color.blue;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.attackRange);
        }
        else if(this.state == eState.Attack)
        {
            Gizmos.color = Color.red;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.traceRange);
        }
    }
}