6-4. 15조 MonsterController.cs

keubung·2024년 11월 29일

임시로 디버깅하면서 하드코딩으로 땜빵 버그잡기..리팩토링 필요!!!

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

public class MonsterController : MonoBehaviour
{
    [Header("Stats")]
    public float walkSpeed;
    public float runSpeed;

    [Header("AI")]
    public float detectDistance;
    public float safeDistance;
    public float lookAtPlayerDistance;
    private AIStateType aiState;

    [Header("Wandering")]
    public float minWanderDistance;
    public float maxWanderDistance;
    public float minWanderWaitTime;
    public float maxWanderWaitTime;
    public float wanderingTime = 10f;
    private int wanderingCount;
    private int maxWanderingCount;
    private float wanderingTimer = 0f;

    [Header("Combat")]
    public float attackDistance;
    public float fieldOfView = 120f;

    private float playerDistance;
    private bool isHiding;

    public Transform playerTransform;
    private NavMeshAgent agent;
    [SerializeField] private MeshRenderer meshRenderer;
    //private Animator animator;
    //private SkinnedMeshRenderer[] meshRenderers;

    private Monster monster;
    private Coroutine coroutine;
    private bool check = true;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        //animator = GetComponent<Animator>();
        //meshRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
        SetState(AIStateType.Idle);
        ResetWanderingCount();
    }

    void Update()
    {
        playerDistance = Vector3.Distance(transform.position, playerTransform.position);

        //animator.SetBool("Moving", aiState != AIState.Idle);

        switch (aiState)
        {
            case AIStateType.Idle:
            case AIStateType.Wandering:
                PassiveUpdate();
                break;
            case AIStateType.Attacking:
                AttackingUpdate();
                break;
            case AIStateType.Fleeing:
                FleeingUpdate();
                break;
        }

        if (!meshRenderer.enabled)
        {
            LookingAtPlayerUpdate();
        }
    }

    public void SetState(AIStateType state)
    {
        if (aiState == state)
            return;

        aiState = state;
        switch (aiState)
        {
            case AIStateType.Idle:
                agent.speed = walkSpeed;
                agent.isStopped = true;
                break;
            case AIStateType.Wandering:
                agent.speed = walkSpeed;
                agent.isStopped = false;
                break;
            case AIStateType.Attacking:
                agent.speed = runSpeed;
                agent.isStopped = false;
                break;
            case AIStateType.Fleeing:
                agent.speed = runSpeed;
                agent.isStopped = false;
                break;
        }

        //animator.speed = agent.speed / walkSpeed;
    }

    void PassiveUpdate()
    {
        if (!meshRenderer.enabled)
        {
            return;
        }

        if (playerDistance < detectDistance && !isHiding) // 플레이어가 감지 범위 안에 있고 숨지 않은 경우
        {
            SetState(AIStateType.Attacking);
        }
        else if ((isHiding || playerDistance > detectDistance) && aiState != AIStateType.Wandering) // 플레이어를 놓친 경우 Wandering으로 전환
        {
            SetState(AIStateType.Wandering);
        }

        if (AIStateType.Wandering == aiState && agent.remainingDistance < 0.1f && check)
        {
            check = false;
            Debug.Log(wanderingCount);
            WanderToNewLocation();  // 새 위치로 이동

            // 이동 횟수를 모두 소진하면 투명화 상태로 전환
            if (wanderingCount <= 0)
                BecomeInvisible();
        }
    }

    private void LookingAtPlayerUpdate()
    {
        if (playerDistance > lookAtPlayerDistance)
        {
            SetState(AIStateType.Wandering);
        }
        else
        {
            Vector3 directionToPlayer = (playerTransform.position - transform.position).normalized;
            Quaternion lookRotation = Quaternion.LookRotation(directionToPlayer);
            transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5f);
        }
    }

    void AttackingUpdate()
    {
        if ((playerDistance <= attackDistance))
        {
            agent.isStopped = true;
        }
        else
        {
            if (playerDistance < detectDistance)
            {
                agent.isStopped = false;
                NavMeshPath path = new NavMeshPath();
                if (agent.CalculatePath(playerTransform.position, path))
                {
                    agent.SetDestination(playerTransform.position);
                }
            }
            else
            {
                agent.SetDestination(transform.position);
                agent.isStopped = true;
                SetState(AIStateType.Wandering);
            }
            //animator.speed = 1;
            //animator.SetTrigger("Attack");
        }
    }

    void FleeingUpdate()
    {
        if (agent.remainingDistance < 0.1f)
        {
            agent.SetDestination(GetFleeLocation());
        }
        else
        {
            SetState(AIStateType.Wandering);
        }
    }

    void ResetWanderingCount()
    {
        wanderingCount = Random.Range(6, 11);
    }

    void BecomeInvisible()
    {
        SetState(AIStateType.Idle);
        meshRenderer.enabled = false;
        StopCoroutine(coroutine);
        coroutine = null;
        ResetWanderingCount();
        check = true;
    }

    void WanderToNewLocation()
    {
        coroutine = StartCoroutine(CoTimer.Start(0.5f, () =>
        {
            agent.SetDestination(GetWanderLocation());
            wanderingCount--;
            check = true;
        }));
    }

    bool IsPlayerInFieldOfView()
    {
        Vector3 directionToPlayer = playerTransform.position - transform.position;
        float angle = Vector3.Angle(transform.forward, directionToPlayer);
        return angle < fieldOfView * 0.5f;
    }

    Vector3 GetFleeLocation()
    {
        NavMeshHit hit;

        NavMesh.SamplePosition(transform.position + (Random.onUnitSphere * safeDistance), out hit, maxWanderDistance, NavMesh.AllAreas);

        int i = 0;
        while (GetDestinationAngle(hit.position) > 90 || playerDistance < safeDistance)
        {

            NavMesh.SamplePosition(transform.position + (Random.onUnitSphere * safeDistance), out hit, maxWanderDistance, NavMesh.AllAreas);
            i++;
            if (i == 30)
                break;
        }

        return hit.position;
    }

    Vector3 GetWanderLocation()
    {
        NavMeshHit hit;

        NavMesh.SamplePosition(transform.position + (Random.onUnitSphere * Random.Range(minWanderDistance, maxWanderDistance)), out hit, maxWanderDistance, NavMesh.AllAreas);

        int i = 0;
        while (Vector3.Distance(transform.position, hit.position) < detectDistance)
        {
            NavMesh.SamplePosition(transform.position + (Random.onUnitSphere * Random.Range(minWanderDistance, maxWanderDistance)), out hit, maxWanderDistance, NavMesh.AllAreas);
            i++;
            if (i == 30)
                break;
        }

        return hit.position;
    }

    float GetDestinationAngle(Vector3 targetPos)
    {
        return Vector3.Angle(transform.position - playerTransform.position, transform.position + targetPos);
    }
}
profile
김나영(Unity_6기)

0개의 댓글