카테고리 없음

0730 유니티 테스트 대비

버스창문 2025. 7. 30. 17:55

조건 : 공격과 이동을 각각 스크립트가 있을것

플레이어와 적이 저 코드를 사용할것

공격과 이동의 코드가 특정 인터페이스를 상속할것

 

 

 

______________________________________________________


이동 -> 
agent를 활용해서 이동
좌표값을 넘겨주면 해당 위치까지 이동
공격 -> 
타겟의 게임 오브젝트를 매개변수로 넘김
타겟까지의 거리가 멀다면 해당 위치까지 이동, 충분히 가까워지면 이동을 멈추고 공격
이동 내에 메서드를 활용해서 이동
타겟이 잡혀 있다면 공격 이후 다시 거리 체크해서 공격

각각은 특정 인터페이스를 상속하고, 해당 인터페이스는 Cancel의 구현을 강제함


플레이어 -> 이동 및 공격을 직접 마우스 클릭으로 처리함
적 -> 주변에 플레이어가 없다면 주변을 순찰하도록 처리, 플레이어가 근처에 있다면
해당 플레이어를 공격, 멀어지거나, 플레이어 사망 시 다시 순찰

 

____________________________________________________________

 

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

public interface _Test_IAction
{
    public void Cancel();
}

 

인터페이스

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

[RequireComponent(typeof(NavMeshAgent))]
public class _Test_Mover : MonoBehaviour,_Test_IAction
{
    //agent를 이용해서 좌표를 입력받으면 해당 좌표로 agnet의 목적지를 셋팅하는 함수
    NavMeshAgent agent;
    void Start()
    {
        this.agent = GetComponent<NavMeshAgent>();
    }
    public void MoveSet(Vector3 pos)
    {
        this.agent.SetDestination(pos);
    }
    public float GetDistance()
    {
        return this.agent.remainingDistance;
    }
    public void Cancel()
    {
        //이동 취소시 현재 자신의 위치를 목적지로
        this.agent.SetDestination(this.transform.position);
    }
}

 

이동코드

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

[RequireComponent(typeof(_Test_Mover))]
public class _Test_Fighter : MonoBehaviour,_Test_IAction
{
    //타겟이 있으면, 해당 타겟 위치로 Mover를 이용해 이동, 가까워지면 이동 중지후 공격
    _Test_Mover mover;
    float attackDist = 1;
    void Start()
    {
        this.mover = GetComponent<_Test_Mover>();
    }
    public void AttackSet(GameObject target)
    {
        StartCoroutine(this.AttackRoutine(target));
    }
    WaitForSeconds wsForAttack = new WaitForSeconds(1);
    IEnumerator AttackRoutine(GameObject target)
    {
        while (Vector3.Distance(target.transform.position,this.transform.position) > this.attackDist)
        {
            this.mover.MoveSet(target.transform.position);
            yield return null;
        }
        //충분히 가까워져서 while문을 빠져나왔을 때
        this.mover.Cancel();
        while (true)
        {
            Debug.Log("공격");
            yield return this.wsForAttack;
        }
    }
    public void Cancel()
    {
        this.StopAllCoroutines();
        this.mover.Cancel();
    }
}

공격코드

 

 

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

public class _Test_PlayerCtrl : MonoBehaviour
{
    int groundLayerMask = 1 << 6;
    int enemyLayerMask = 1 << 7;
    Ray ray;
    RaycastHit hit;
    _Test_Mover mover;
    _Test_Fighter fighter;

    void Start()
    {
        this.mover = GetComponent<_Test_Mover>();
        this.fighter = GetComponent<_Test_Fighter>();
    }
    void Update()
    {
        if (Input.GetMouseButtonDown(1)) //우클릭 하면
        {

            this.ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(this.ray, out hit, Mathf.Infinity, this.groundLayerMask))
            {
                this.fighter.Cancel();
                this.mover.MoveSet(hit.point);
            }

        }

        if (Input.GetMouseButtonDown(0)) //좌클릭 하면
        {

            this.ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(this.ray, out hit, Mathf.Infinity, this.enemyLayerMask))
            {
                this.fighter.AttackSet(hit.transform.gameObject);
            }

        }

    }
}

플레이어

 

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

public class _Test_EnemyCtrl : MonoBehaviour
{
    _Test_Mover mover;
    _Test_Fighter fighter;
    _Test_PatrolPointCtrl patrolPointCtrl;
    GameObject target;
    float attackDist = 5;
    int patrolIdx = -1; // 순찰 컨트롤이 계속 1을 더해줄거기 때문에 -1로 시작함
    float lookAroundTime = 0;
    void Start()
    {
        this.mover = GetComponent<_Test_Mover>();
        this.fighter = GetComponent<_Test_Fighter>();
        this.target = GameObject.FindWithTag("Player");
        this.patrolPointCtrl = GameObject.Find("PatrolPoints").GetComponent<_Test_PatrolPointCtrl>();

        StartCoroutine(EnemyRoutine());
    }

    IEnumerator EnemyRoutine()
    {
        this.mover.MoveSet(this.patrolPointCtrl.GetPoint(ref this.patrolIdx));
        
        while (true)
        {
            while (Vector3.Distance(this.target.transform.position, this.transform.position) > attackDist)
            {
                if (this.mover.GetDistance() < 1)
                {
                    this.mover.MoveSet(this.patrolPointCtrl.GetPoint(ref this.patrolIdx));
                }
                yield return null;
            }
            //타겟이 가까워져서 여기로 나왔다면
            this.fighter.AttackSet(this.target); // 공격 셋팅
            while (Vector3.Distance(this.target.transform.position, this.transform.position) <= attackDist)
            {
                yield return null;
            }
            //다시 멀어진다면(추가적인 조건 셋팅 해야함, 타겟이 죽는다거나)
            this.fighter.Cancel();
            this.lookAroundTime = 0;
            while(Vector3.Distance(this.target.transform.position, this.transform.position) > attackDist && this.lookAroundTime < 2)
            {
                //다시 안가까워지는 동안만, 2초 동안만 제자리에 서있음
                this.lookAroundTime += Time.deltaTime;
                yield return null;
            }
        }
    }
}

적

 

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

public class _Test_PatrolPointCtrl : MonoBehaviour
{
    List<Transform> points = new List<Transform>();
    void Awake()
    {
        GetComponentsInChildren<Transform>(points);
        this.points.RemoveAt(0);
    }
    public Vector3 GetPoint(ref int curIdx)
    {
        if(++curIdx == this.points.Count)
        {
            curIdx = 0;
        }
        return this.points[curIdx].position;
    }
}

적이 사용하는 순찰 포인트 컨트롤

 

업데이트보단 코루틴을 적극적으로 활용해서, 내가 원하지 않는 이동효과가 나오는 경우를 최대한 배제함,

또한 업데이트를 그냥 쓰면 발생하는, 불필요하게 계속 값이 들어가는 경우를 최대한 배제시킴