Newer
Older
HierarchicalFSM-Unity3D / Assets / Scripts / NPC / NPCController.cs
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.AI;
  5. [RequireComponent(typeof(NavMeshAgent))]
  6. public class NPCController : MonoBehaviour
  7. {
  8. private NavMeshAgent agent;
  9. private Animator animator;
  10. [SerializeField] private Waypoints waypoints;
  11. private Vector2 Velocity;
  12. private Vector2 SmoothDeltaPosition;
  13. public Animator Animator => animator;
  14. public NavMeshAgent Agent => agent;
  15. public Waypoints Waypoints => waypoints;
  16. void Awake()
  17. {
  18. agent = GetComponent<NavMeshAgent>();
  19. animator = GetComponent<Animator>();
  20. }
  21. // Start is called before the first frame update
  22. void Start()
  23. {
  24. agent.stoppingDistance = 0.1f;
  25. agent.updatePosition = false;
  26. animator.applyRootMotion = true;
  27. agent.updateRotation = true;
  28. }
  29. // Update is called once per frame
  30. void Update()
  31. {
  32. Debug.Log("IsMoving: " + animator.GetBool("IsMoving"));
  33. SynchronizeAnimatoraAndAgent();
  34. }
  35. private void OnAnimatorMove()
  36. {
  37. Vector3 rootPosition = animator.rootPosition;
  38. rootPosition.y = agent.nextPosition.y;
  39. transform.position = rootPosition;
  40. agent.nextPosition = rootPosition;
  41. }
  42. private void SynchronizeAnimatoraAndAgent()
  43. {
  44. //Distance between the agent next position and the Game Object position
  45. Vector3 worldDeltaPosition = agent.nextPosition - transform.position;
  46. worldDeltaPosition.y = 0f;
  47. float dx = Vector3.Dot(transform.right, worldDeltaPosition);
  48. float dy = Vector3.Dot(transform.forward, worldDeltaPosition);
  49. Vector2 deltaPosition = new Vector2(dx, dy);
  50. float smooth = Mathf.Min(1, Time.deltaTime / 0.1f);
  51. SmoothDeltaPosition = Vector2.Lerp(SmoothDeltaPosition, deltaPosition, smooth);
  52. //Calculate the velocity
  53. Velocity = SmoothDeltaPosition / Time.deltaTime;
  54. if (agent.remainingDistance <= agent.stoppingDistance)
  55. {
  56. Velocity = Vector2.Lerp(Vector2.zero, Velocity, agent.remainingDistance / agent.stoppingDistance);
  57. }
  58. bool shouldMove = Velocity.magnitude > 0.5f && agent.remainingDistance > agent.stoppingDistance;
  59. animator.SetBool("IsMoving", shouldMove);
  60. animator.SetFloat("Velocity", Velocity.magnitude);
  61. float deltaMagnitude = worldDeltaPosition.magnitude;
  62. if (deltaMagnitude > agent.radius / 2f)
  63. {
  64. transform.position = Vector3.Lerp(animator.rootPosition, agent.nextPosition, smooth);
  65. }
  66. }
  67. }