유니티 기초

보스 시야 들어가면 따라오기

노재두내 2023. 8. 14. 17:32

1. 시야 들어가면 색깔 바뀌기 + hero 움직임 

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

namespace Test_Boss
{
    public class Bull : MonoBehaviour
    {
        public System.Action onDetectTarget;
        public System.Action onLoseTarget;
        public System.Action onMoveComplete;
        public System.Action onAttackCancel;
        private Transform target;
        [SerializeField]
        private float sight = 7f;
        [SerializeField]
        private float range = 3f;
        public float Range => this.range;
        private Animator anim;
        private bool isWithinSight;

        private Coroutine stateRoutine;
        
        void Start()
        {
            this.anim = this.GetComponent<Animator>();
        }

        //초기화
        public void Init()
        {
            this.FindTarget();//타겟을 찾는다
            this.stateRoutine = this.StartCoroutine(this.CoCheckWithinHeroTheRange());  
        }

        //타겟찾기
        private void FindTarget()
        {
            var go = GameObject.Find("HeroPrefab");
            if (go != null)
                this.target = go.transform;
        }

        private IEnumerator CoCheckWithinHeroTheRange()//범위내에 히어로 있는지 체크(움직이지 X)
        {
            while (true) {
                var dis = Vector3.Distance(this.transform.position, this.target.transform.position);
                //Debug.Log(dis);
                this.isWithinSight = dis <= this.sight;//시야내에 들어오면 true 밖이면 false

                if (this.isWithinSight) {
                    this.onDetectTarget();
                    break;
                }

                yield return null;
            }
        }
        //탐지하고 움직이기
        public void DetectAndMove()
        {
            if (this.stateRoutine != null) {//범위내에 히어로가 있으면 
                this.StopCoroutine(this.stateRoutine);//찾는걸 멈춘다.
            }

            this.stateRoutine = this.StartCoroutine(this.CoDetectAndMove());//범위내에 히어로 없으면 계속 탐지?
        }

        private IEnumerator CoDetectAndMove()
        {
            this.transform.LookAt(this.target);
            //이동 애니메이션 실행 

            while (true)
            {
                var dis = Vector3.Distance(this.transform.position, this.target.transform.position);
                //Debug.Log(dis);
                this.isWithinSight = dis <= this.sight;

                if (this.isWithinSight == false)//시야 내에 없으면 멈춘다
                {
                    this.onLoseTarget();//다켓이 시야에서 나가면 idle()호풀, idle 출력
                    break;
                }

                this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);//있으면 움직인다.
                yield return null;
            }
        }
        //idle 상태일때 
        public void Idle()
        {
            Debug.Log("Idle");

            this.StartCoroutine(this.CoCheckWithinHeroTheRange());//범위에 있는지 체크한다(idle상태일때)
        }


        //public void MoveForward(Transform targetTrans)
        //{
        //    this.targetTrans = targetTrans;
        //    //this.StartCoroutine(coMoveForward());
        //    this.StartCoroutine(this.CoMoveForward());
        //}

        //private IEnumerator CoMoveForward()
        //{
        //    while (true){

        //        if (targetTrans == null)
        //            break;

        //        var dis = Vector3.Distance(this.transform.position, this.targetTrans.position);
        //        if (dis > 7)//시야 안에 들어오면
        //        {
        //            yield return null;
        //            continue;
        //        }
        //        this.transform.LookAt(this.targetTrans);
        //        this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);

        //        if (dis <= this.range)//공격사거리안에 들어오면
        //        {
        //            Debug.Log("<color=red>공격사거리 안에 들어왔습니다.</color>");
        //            break;
        //        }
        //        yield return null;
        //    }
        //    if (this.targetTrans == null)
        //    {
        //        Debug.Log("타겟을 잃었습니다.");
        //        this.anim.SetInteger("State", 0);
        //    }
        //    else
        //    {
        //        Debug.Log("이동을 완료함");
        //        this.onMoveComplete();
        //    }

        //}
        //public void Attack(Transform targetTrans)
        //{
        //    this.targetTrans = targetTrans;
        //    this.StartCoroutine(this.CoAttack());
        //}
        //private IEnumerator CoAttack()
        //{
        //    yield return null;
        //    var dis = Vector3.Distance(this.transform.position, this.targetTrans.position);
        //    if (dis < this.range)
        //    {
        //        anim.SetInteger("State", 3);

        //    }
        //    else
        //    {
        //        this.onAttackCancel();
        //        anim.SetInteger("State", 1);
        //    }
        //}
        private void OnDrawGizmos()
        {
            //시야 
            if (isWithinSight)//범위 안에 있으면 빨간색
            {
                Gizmos.color = Color.red;
            }
            else 
            {
                Gizmos.color = Color.white;
            }
            
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.sight, 20);
            //공격사거리
            //Gizmos.color = Color.red;
            //GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.range, 20);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

namespace Test_Boss
{
    
    public class HeroController : MonoBehaviour
    {
        private Vector3 targetPosition;
        private Coroutine moveRoutine;
        private float radius = 1f;
        // Start is called before the first frame update
        void Start()
        {

        }

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

        }
        public void Move(Vector3 hitPosition)
        {
            this.targetPosition = hitPosition;
            if (this.moveRoutine != null)
            {
                this.StopCoroutine(this.moveRoutine);
            }
            this.moveRoutine = StartCoroutine(CoMove());
        }
        private IEnumerator CoMove()
        {
            while (true)
            {
                this.transform.LookAt(this.targetPosition);
                this.transform.Translate(Vector3.forward * 2f * Time.deltaTime);
                float dis = Vector3.Distance(this.transform.position, this.targetPosition);
                if (dis <= 0.1f)
                {
                    break;
                }
                yield return null;
            }
        }
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.red;
            GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius, 20);
            
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace Test_Boss
{
    public class Test_BossSceneMain : MonoBehaviour
    {
        //[SerializeField]
        //private GameObject bossPrefab;
        //[SerializeField]
        //private GameObject heroPrefab;
        [SerializeField]
        private Button btnMove;
        [SerializeField]
        private Button btnRemove;
        [SerializeField]
        private Bull bull;
        [SerializeField]
        private Transform targetTrans;
        [SerializeField]
        private HeroController heroController;
        // Start is called before the first frame update
        void Start()
        {
            this.bull.onDetectTarget = () => {
                this.bull.DetectAndMove();
            };

            this.bull.onLoseTarget = () => {
                this.bull.Idle();
            };

            //this.bull.onAttackCancel = () =>
            //{
            //    this.BullMoveAndAttack();//거리계산
            //};
            //this.bull.onMoveComplete = () =>
            //{
            //    //Debug.LogError("!");
            //    this.BullMoveAndAttack();//거리계산
            //};
            ////this.CreateBoss();
            ////this.CreateHero();
            //this.btnMove.onClick.AddListener(() =>
            //{
            //    Debug.Log("move");
            //    this.bull.MoveForward(targetTrans);
            //});

            //this.btnRemove.onClick.AddListener(() =>
            //{
            //    Debug.Log("remove");
            //    //Destroy(this.bull.gameObject);
            //    //Destroy(this.gameObject);
            //    Destroy(this.targetTrans.gameObject);

            //});

            this.bull.Init();

        }
        //private void BullMoveAndAttack()
        //{
        //    Debug.Log("사거리 계산");
        //    var dis = Vector3.Distance(this.transform.position, this.targetTrans.position);
        //    if (dis <= this.bull.Range)
        //    {
        //        Debug.Log("공격");
        //        this.bull.Attack(targetTrans);
        //    }
        //    else
        //    {
        //        Debug.Log("이동");
        //        this.bull.MoveForward(targetTrans);
        //    }
        //}
        //private void CreateBoss()
        //{
        //    GameObject bossGo = Instantiate(this.bossPrefab);
        //    bossGo.transform.position = new Vector3(6, 0, -9);
        //}
        //private void CreateHero()
        //{
        //    GameObject heroGo = Instantiate(this.heroPrefab);
        //}
        //// Update is called once per frame

        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                Debug.DrawRay(ray.origin, ray.direction*100f, Color.red, 2f);
                RaycastHit hit;
                if(Physics.Raycast(ray,out hit, 100f)){
                    this.heroController.Move(hit.point);
                }
            }
        }
    }
}

2. 애니메이션 적용(공격빼고)

bull

private IEnumerator CoDetectAndMove()
        {
            this.transform.LookAt(this.target);
            this.anim.SetInteger("State", 1);
            //이동 애니메이션 실행 

            while (true)
            {
                var dis = Vector3.Distance(this.transform.position, this.target.transform.position);
                //Debug.Log(dis);
                this.isWithinSight = dis <= this.sight;

                if (this.isWithinSight == false)//시야 내에 없으면 멈춘다
                {
                    this.onLoseTarget();//타켓이 시야에서 나가면 idle()호풀, idle 출력
                    break;
                }
                
                this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);//있으면 움직인다.
                yield return null;
            }
        }
        //idle 상태일때 
        public void Idle()
        {
            Debug.Log("Idle");
            this.anim.SetInteger("State", 0);
            this.StartCoroutine(this.CoCheckWithinHeroTheRange());//범위에 있는지 체크한다(idle상태일때)
        }

        public void Attack()
        {
            //var dis = Vector3.Distance(this.transform.position, this.target.transform.position);
            //if (dis <= 1f)
            //{
                this.anim.SetInteger("State", 3);
            //}
        }

heroController

private IEnumerator CoMove()
        {
            while (true)
            {
                this.transform.LookAt(this.targetPosition);
                this.anim.SetInteger("State", 1);
                this.transform.Translate(Vector3.forward * 2f * Time.deltaTime);
                float dis = Vector3.Distance(this.transform.position, this.targetPosition);
                if (dis <= 0.1f)
                {
                    this.anim.SetInteger("State", 0);
                    break;
                }
                yield return null;
            }
        }

bossScneneMain

void Start()
        {
            this.bull.onDetectTarget = () => {
                this.bull.DetectAndMove();
            };

            this.bull.onLoseTarget = () => {
                this.bull.Idle();
            };
            this.bull.onAttack = () =>
            {
                this.bull.Attack();
            };