본문 바로가기
KDT/유니티 심화

23/08/24 SpaceShooter 몬스터 공격 스크립트

by 잰쟁 2023. 8. 24.
728x90

MonsterController

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting.Antlr3.Runtime.Misc;
using UnityEngine;
using UnityEngine.AI;

public class MonsterController : MonoBehaviour
{
    //상태 정의
    public enum eState 
    {
        IDLE,
        TRACE,
        ATTACK,
        DIE   
    }

    //몬스터의 현재 상태 저장하는 변수
    public eState state;

    //공격사거리 변수 정의
    [SerializeField]
    private float attackRange = 2.0f;

    //추적사거리 변수 정의
    [SerializeField]
    private float traceRange = 10.0f;

    //죽었는지 안 죽었는지 저장하는 변수
    private bool isDie = false;

    private NavMeshAgent agent;
    private Transform playerTrans;
    private Animator anim;
    
    void Start()
    {
        //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.anim = this.GetComponent<Animator>();

        //플레이어 위치로 이동하기
        this.agent.destination = this.playerTrans.position;

        //코루틴 호출
        //상태체크
        this.StartCoroutine(CheckMonsterState());
        //행동수행
        this.StartCoroutine(MonsterAction());
    }

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

            //플레이어와 거리 계산
            var dis = Vector3.Distance(this.transform.position, this.playerTrans.position);

            //공격사거리에 들어왔는지
            if(dis <= this.attackRange)
            {
                //상태변화
                this.state = eState.ATTACK;
            }
            //아니면 추적사거리에 들어왔는지
            else if(dis <= this.traceRange)
            {
                //상태변화
                this.state = eState.TRACE;
            }
            //공격사거리, 추적사거리도 아니면
            else
            {
                //상태변화
                this.state = eState.IDLE;
            }
        }
    }

    //행동수행 메서드
    IEnumerator MonsterAction()
    {
        //몬스터가 죽지 않았다면
        while (this.isDie == false) //!this.isDie
        {
            switch (this.state) 
            {
                case eState.IDLE:
                    //추적 중지
                    this.agent.isStopped = true;
                    //애니메이션 실행
                    this.anim.SetBool("Is Trace", false);
                    break;
                case eState.ATTACK:
                    //추적 중지
                    this.agent.isStopped = true;
                    //애니메이션 실행
                    this.anim.SetBool("Is Attack", true);
                    break;
                case eState.TRACE:
                    //플레이어 좌표로 이동
                    this.agent.SetDestination(this.playerTrans.position);
                    //추적 실행
                    this.agent.isStopped = false;
                    //애니메이션 실행
                    this.anim.SetBool("Is Trace", true);
                    this.anim.SetBool("Is Attack", false);
                    break;
                case eState.DIE:
                    break;
            }
            yield return new WaitForSeconds(0.3f);
        }
    }

    //몬스터의 상태에 따라 동작 수행

    private void OnDrawGizmos()
    {
        //추적사거리 표시
        if(state == eState.TRACE)
        {
            Gizmos.color = Color.blue;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.traceRange);
        }
        //공격사거리 표시
        if(state == eState.ATTACK)
        {
            Gizmos.color = Color.red;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.attackRange);
        }
    }
}

원래 이렇게 쓰지만 MonsterAction 부분이 너무 길어짐

그래서 밑에 상태에 따라 따로 메서드들을 만들어주자~

 

//행동수행 메서드
    IEnumerator MonsterAction()
    {
        //몬스터가 죽지 않았다면
        while (this.isDie == false) //!this.isDie
        {
            switch (this.state) 
            {
                case eState.IDLE:
                    this.Idle();
                    break;
                case eState.ATTACK:
                    this.Attack();
                    break;
                case eState.TRACE:
                    this.Trace();
                    break;
                case eState.DIE:
                    break;
            }
            yield return new WaitForSeconds(0.3f);
        }
    }

    //Idle 상태일때 메서드
    void Idle()
    {
        //추적 중지
        this.agent.isStopped = true;
        //애니메이션 실행
        this.anim.SetBool("Is Trace", false);
    }

    //Trace 상태일때 메서드
    void Trace()
    {
        //플레이어 좌표로 이동
        this.agent.SetDestination(this.playerTrans.position);
        //추적 실행
        this.agent.isStopped = false;
        //애니메이션 실행
        this.anim.SetBool("Is Trace", true);
        this.anim.SetBool("Is Attack", false);
    }

    //Attack 상태일때 메서드
    void Attack()
    {
        //추적 중지
        this.agent.isStopped = true;
        //애니메이션 실행
        this.anim.SetBool("Is Attack", true);
    }

이렇게!