본문 바로가기
공부/Unity 기초

3D FPS - 6 / 위치 복귀

by svcbn 2022. 5. 19.

상태 머신에 Enemy가 초기 위치로 복귀하는 상태(State.Return)를 추가한다.

 enum State
    {
        Idle,
        Move,
        Attack,
        Die,
        Return
    }

 

 

 

 

 

 


Enemy가 Player를 쫓아가다가 최대 추적 거리를 넘어가면 복귀 상태로 전환

// 현재 위치가 최대 추적 가능 거리를 넘어갔는지 여부를 판단한다.
        float trace = Vector3.Distance(originPosition, transform.position);

        // 만일, 최대 추적 가능 거리를 넘어갔다면 상태를 복귀 상태로 전환한다.
        if (trace > traceDistance)
        {
            state = State.Return;
        }

 

 

 

 

 

 

추적을 포기하고 다시 원래의 위치로 돌아오는 기능

 void UpdateReturn()
    {
        // 만일, 나의 현재 위치가 originPosition 위치에서 10센티미터 이상이라면
        Vector3 dir = originPosition - transform.position;

        if (dir.magnitude > 0.1f)
        {
            // originPosition 방향으로 이동한다.
            transform.position += dir.normalized * speed * Time.deltaTime;
        }


        // 그렇지 않다면, 나의 위치를 originPosition으로 설정한다.
        else
        {
            transform.position = originPosition;

            // 상태를 다시 대기 상태로 전환한다.
            state = State.Idle;
        }
    }

 

정확한 지점으로 지정하지 않는 이유는 프레임과 속도에 따른 이동거리 때문에

정확한 지점에 도달하지 못해 떠는 현상이 발생한다.

 

 

 

 

 

일단 return 상태로 전이되고 나면 인식범위 안으로 들어가더라도 복귀만을 하기 때문에

다시 Move상태로 전이하는 기능 추가

// 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 복귀 중 감지거리 안으로 Player가 들어오면
        if (distance < findDistance)
        {
            // 상태를 Move 상태로 전이한다.
            state = State.Move;
        }

 

 

 

Enemy 전문

더보기
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


// FSM으로 상태를 제어하고싶다.
// 정지, 이동, 공격, 죽음
public class Enemy : MonoBehaviour
{
    public float speed = 1;
    
    public float findDistance = 5;
    public float attackDistance = 1.5f;
    public float traceDistance = 15;

    
    enum State
    {
        Idle,
        Move,
        Attack,
        Die,
        Return
    }

    State state;

    GameObject target;

    float currentTime;
    float attackTime = 1;

    Vector3 originPosition;

    // Start is called before the first frame update
    void Start()
    {
        state = State.Idle;

        target = GameObject.Find("Player");

        // 최초 위치를 originPosition 변수에 저장한다.
        originPosition = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        if (state == State.Idle)
        {
            UpdateIdle();
        }

        else if (state == State.Move)
        {
            UpdateMove();
        }

        else if (state == State.Attack)
        {
            UpdateAttack();
        }

        else if (state == State.Return)
        {
            UpdateReturn();
        }
    }

    
    private void UpdateIdle()
    {
        // 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 만약 그 거리가 감지거리보다 작으면
        if (distance < findDistance)
        {
            // Move상태로 전이하고싶다.
            state = State.Move;

        }

    }

    private void UpdateMove()
    {
        // 현재 위치가 최대 추적 가능 거리를 넘어갔는지 여부를 판단한다.
        float trace = Vector3.Distance(originPosition, transform.position);

        // 만일, 최대 추적 가능 거리를 넘어갔다면 상태를 복귀 상태로 전환한다.
        if (trace > traceDistance)
        {
            state = State.Return;
        }

        


        // target방향으로 이동하다가
        Vector3 dir = target.transform.position - transform.position;
        dir.Normalize();
        transform.position += dir * speed * Time.deltaTime;

        // 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 만약 그 거리가 공격거리보다 작으면
        if (distance < attackDistance)
        {
            // Attack으로 전이하고싶다.
            state = State.Attack;
        }


    }

    private void UpdateAttack()
    {
        // 시간이 흐르다가
        currentTime += Time.deltaTime;

        // 만약 현재시간이 공격시간이 되면
        if (currentTime > attackTime)
        {
            // 현재시간을 초기화하고
            currentTime = 0;

            // 플레이어를 공격하고
            // target.AddDamage();

            // 만약 target이 공격거리 밖에 있으면 Move상태로 전이하고싶다.
            // 나와 target의 거리를 구해서
            float distance = Vector3.Distance(transform.position, target.transform.position);

            // 만약 그 거리가 공격거리보다 크다면
            if (distance > attackDistance)
            {
                // Move상태로 전이하고싶다.
                state = State.Move;

            }
                        
        }

    }

    
    public void AddDamage (int damage)
    {
        Destroy(gameObject);

    }

    void UpdateReturn()
    {
        
        // 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 복귀 중 감지거리 안으로 Player가 들어오면
        if (distance < findDistance)
        {
            // 상태를 Move 상태로 전이한다.
            state = State.Move;
        }

        // 만일, 나의 현재 위치가 originPosition 위치에서 10센티미터 이상이라면
        Vector3 dir = originPosition - transform.position;

        if (dir.magnitude > 0.1f)
        {
            // originPosition 방향으로 이동한다.
            transform.position += dir.normalized * speed * Time.deltaTime;
        }
        

        // 그렇지 않다면, 나의 위치를 originPosition으로 설정한다.
        else
        {
            transform.position = originPosition;

            // 상태를 다시 대기 상태로 전환한다.
            state = State.Idle;

             
        }
    }
}

'공부 > Unity 기초' 카테고리의 다른 글

3D FPS - 8 / 게임 오버 처리  (0) 2022.05.19
3D FPS - 7 / 피격 처리  (0) 2022.05.19
3D FPS - 5 / 상태머신 설계  (0) 2022.05.18
3D FPS - 4 / 가리키는 대상 표시  (0) 2022.05.18
3D FPS - 3 / 무기 제작  (0) 2022.05.18