Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Scripts / NPC / NPCController.cs
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using MyCollections.AI.FinitStateMachine;
  5. using UnityEngine.UI;
  6. using MyCollections.DesignPatterns.Visitor;
  7. using System;
  8. [RequireComponent(typeof(Animator))]
  9. public abstract class NPCController : MonoBehaviour, IHealthSystem, INotifyObservers
  10. {
  11. //Attributes
  12. [Header("NPC Attributes: ")]
  13. [SerializeField] protected string npcName;
  14. [SerializeField] protected int health;
  15. [SerializeField] protected int maxHealth;
  16. //Idle settings
  17. [Header("NPC Idle Settings: ")]
  18. public float timer = 0f;
  19. [SerializeField] protected float minIdleTime = 2f;
  20. [SerializeField] protected float maxIdleTime = 10f;
  21. [SerializeField] protected Vector2 lastDirection = Vector2.right; // Default facing right
  22. //Components
  23. [Header("NPC Components: ")]
  24. [SerializeField] protected FSM fsm;
  25. [SerializeField] protected Agent agent;
  26. [SerializeField] protected Animator animator;
  27. [SerializeField] protected FOV agentFOV;
  28. [SerializeField] protected Image healthBarImage;
  29. [SerializeField] private GameObject healthDamageObject;
  30. [SerializeField] protected AudioSource audioSource;
  31. protected NPCManager npcManager;
  32. private bool isDead = false;
  33. //Observers
  34. protected List<IObserver> observers = new List<IObserver>();
  35. //TESTING
  36. [SerializeField] protected List<string> observersNames = new List<string>();
  37. //Events
  38. public event Action<NPCController> OnNPCDied = delegate { };
  39. //Properties
  40. public Agent Agent => agent;
  41. public Animator Animator => animator;
  42. public FOV AgentFOV => agentFOV;
  43. public int MaxHealth => maxHealth;
  44. public bool IsCoroutineRunning { get; set; }
  45. public NPCManager NPCManager => npcManager;
  46. public string NPCname => npcName;
  47. public Image HealthBarImage => healthBarImage;
  48. public Vector2 LastDirection
  49. {
  50. get => lastDirection;
  51. set => lastDirection = value;
  52. }
  53. public AudioSource AudioSource => audioSource;
  54. protected virtual void Awake()
  55. {
  56. if (!TryGetComponent(out agent))
  57. {
  58. Debug.LogError("Agent component not found on this GameObject!");
  59. }
  60. if (!TryGetComponent(out agentFOV))
  61. Debug.LogError($"{nameof(FOV)} component not found on this GameObject!");
  62. animator = GetComponent<Animator>();
  63. }
  64. // Start is called before the first frame update
  65. protected virtual void Start()
  66. {
  67. npcManager = gameObject.GetComponentInParent<NPCManager>();
  68. foreach (IObserver observer in observers)
  69. {
  70. if (observer != null)
  71. {
  72. observersNames.Add(observer.ToString());
  73. }
  74. }
  75. }
  76. // Update is called once per frame
  77. protected virtual void Update()
  78. {
  79. //Debug.Log("Manager" + NPCManager.Instance);
  80. AnimationController();
  81. }
  82. protected virtual void OnEnable()
  83. {
  84. health = maxHealth;
  85. isDead = false;
  86. }
  87. protected virtual void OnDisable()
  88. {
  89. }
  90. protected virtual void AnimationController()
  91. {
  92. if (!agent.agentStop)
  93. {
  94. lastDirection = agent.agentVelocity.normalized;
  95. }
  96. animator.SetBool("IsStopped", agent.agentStop);
  97. animator.SetFloat("VelocityX", agent.agentVelocity.x);
  98. animator.SetFloat("VelocityY", agent.agentVelocity.y);
  99. animator.SetFloat("LookDirectionX", lastDirection.x);
  100. animator.SetFloat("LookDirectionY", lastDirection.y);
  101. }
  102. //Notify the observers
  103. public void NotifyObservers(NotificationType type,params (string key, object value)[] parameters)
  104. {
  105. ObserverNotification notification = new ObserverNotification(type);
  106. foreach ((string key, object value) param in parameters)
  107. {
  108. notification.AddData(param.key, param.value);
  109. }
  110. foreach (IObserver observer in observers)
  111. {
  112. if (observer != null)
  113. {
  114. Debug.Log("Observer: " + observer.ToString());
  115. observer.OnNotify(notification);
  116. }
  117. else
  118. {
  119. Debug.Log("Observer is NULL: " + nameof(observer));
  120. }
  121. }
  122. }
  123. public virtual int CurrentHealth() => health;
  124. public virtual void Heal(int amount) => health += amount;
  125. public virtual bool IsDead()
  126. {
  127. if (health <= 0 && !isDead)
  128. {
  129. isDead = true;
  130. OnNPCDied.Invoke(this);
  131. return true;
  132. }
  133. return false;
  134. }
  135. public virtual void TakeDamage(int amount)
  136. {
  137. if (isDead) return;
  138. health -= amount;
  139. animator.SetFloat("DamageDirectionX", lastDirection.x);
  140. animator.SetFloat("DamageDirectionY", lastDirection.y);
  141. //Notify Observers
  142. NotifyObservers(NotificationType.WorldUI, ("NPCController", this), ("DamageAmount", amount));
  143. IsDead();
  144. }
  145. //Set Timer to Idle
  146. public void SetIdleTime() => timer = UnityEngine.Random.Range(2f, maxIdleTime);
  147. // Observer pattern methods
  148. public void AddObserver(IObserver observer)
  149. {
  150. if (!observers.Contains(observer))
  151. {
  152. observers.Add(observer);
  153. }
  154. }
  155. public void RemoveObserver(IObserver observer)
  156. {
  157. if (observers.Contains(observer))
  158. {
  159. observers.Remove(observer);
  160. }
  161. }
  162. }