Newer
Older
HierarchicalFSM-Unity3D / Assets / Scripts / NPC / NPCController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]
public class NPCController : MonoBehaviour
{
    [SerializeField] private Waypoints waypoints;
    private NavMeshAgent agent;
    private Animator animator;
    private Vector2 Velocity;
    private Vector2 SmoothDeltaPosition;
    private FieldOfView agentFOV;
    private Awareness agentAwareness;

    public Animator Animator => animator;
    public NavMeshAgent Agent => agent;
    public Waypoints Waypoints => waypoints;
    public FieldOfView AgentFOV => agentFOV;
    public Awareness AgentAwareness => agentAwareness;

    void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        agentFOV = GetComponentInChildren<FieldOfView>();
        agentAwareness = GetComponentInChildren<Awareness>();

    }

    // Start is called before the first frame update
    void Start()
    {
        agent.stoppingDistance = 0.1f;
        agent.updatePosition = false;
        animator.applyRootMotion = true;
        agent.updateRotation = true;
    }

    // Update is called once per frame
    void Update()
    {
        Debug.Log("IsMoving: " + animator.GetBool("IsMoving"));
        SynchronizeAnimatoraAndAgent();
    }

    private void OnAnimatorMove()
    {
        Vector3 rootPosition = animator.rootPosition;
        rootPosition.y = agent.nextPosition.y;
        transform.position = rootPosition;
        agent.nextPosition = rootPosition;
    }

    //Synchronize the animation and Agent
    private void SynchronizeAnimatoraAndAgent()
    {
        //Distance between the agent next position and the Game Object position
        Vector3 worldDeltaPosition = agent.nextPosition - transform.position;
        worldDeltaPosition.y = 0f;

        float dx = Vector3.Dot(transform.right, worldDeltaPosition);
        float dy = Vector3.Dot(transform.forward, worldDeltaPosition);

        Vector2 deltaPosition = new Vector2(dx, dy);

        float smooth = Mathf.Min(1, Time.deltaTime / 0.1f);
        SmoothDeltaPosition = Vector2.Lerp(SmoothDeltaPosition, deltaPosition, smooth);

        //Calculate the velocity
        Velocity = SmoothDeltaPosition / Time.deltaTime;

        if (agent.remainingDistance <= agent.stoppingDistance)
        {
            Velocity = Vector2.Lerp(Vector2.zero, Velocity, agent.remainingDistance / agent.stoppingDistance);
        }

        bool shouldMove = Velocity.magnitude > 0.5f && agent.remainingDistance > agent.stoppingDistance;

        animator.SetBool("IsMoving", shouldMove);
        animator.SetFloat("Velocity", Velocity.magnitude);
        animator.SetFloat("VelX", Velocity.x);
        animator.SetFloat("VelY", Velocity.y);

        float deltaMagnitude = worldDeltaPosition.magnitude;

        if (deltaMagnitude > agent.radius / 2f)
        {
            transform.position = Vector3.Lerp(animator.rootPosition, agent.nextPosition, smooth);
        }
    }
}