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. observersNames.Add(observer.ToString());
  71. }
  72. }
  73. // Update is called once per frame
  74. protected virtual void Update()
  75. {
  76. //Debug.Log("Manager" + NPCManager.Instance);
  77. AnimationController();
  78. }
  79. protected virtual void OnEnable()
  80. {
  81. health = maxHealth;
  82. isDead = false;
  83. }
  84. protected virtual void OnDisable()
  85. {
  86. }
  87. protected virtual void AnimationController()
  88. {
  89. if (!agent.agentStop)
  90. {
  91. lastDirection = agent.agentVelocity.normalized;
  92. }
  93. animator.SetBool("IsStopped", agent.agentStop);
  94. animator.SetFloat("VelocityX", agent.agentVelocity.x);
  95. animator.SetFloat("VelocityY", agent.agentVelocity.y);
  96. animator.SetFloat("LookDirectionX", lastDirection.x);
  97. animator.SetFloat("LookDirectionY", lastDirection.y);
  98. }
  99. //Notify the observers
  100. public void NotifyObservers(NotificationType type,params (string key, object value)[] parameters)
  101. {
  102. ObserverNotification notification = new ObserverNotification(type);
  103. foreach ((string key, object value) param in parameters)
  104. {
  105. notification.AddData(param.key, param.value);
  106. }
  107. foreach (IObserver observer in observers)
  108. {
  109. if (observer != null)
  110. {
  111. Debug.Log("Observer: " + observer.ToString());
  112. observer.OnNotify(notification);
  113. }
  114. else
  115. {
  116. Debug.Log("Observer is NULL: " + nameof(observer));
  117. }
  118. }
  119. }
  120. public virtual int CurrentHealth() => health;
  121. public virtual void Heal(int amount) => health += amount;
  122. public virtual bool IsDead()
  123. {
  124. if (health <= 0 && !isDead)
  125. {
  126. isDead = true;
  127. OnNPCDied.Invoke(this);
  128. return true;
  129. }
  130. return false;
  131. }
  132. public virtual void TakeDamage(int amount)
  133. {
  134. if (isDead) return;
  135. health -= amount;
  136. animator.SetFloat("DamageDirectionX", lastDirection.x);
  137. animator.SetFloat("DamageDirectionY", lastDirection.y);
  138. //Notify Observers
  139. NotifyObservers(NotificationType.WorldUI, ("NPCController", this), ("DamageAmount", amount));
  140. IsDead();
  141. }
  142. //Set Timer to Idle
  143. public void SetIdleTime() => timer = UnityEngine.Random.Range(2f, maxIdleTime);
  144. // Observer pattern methods
  145. public void AddObserver(IObserver observer)
  146. {
  147. if (!observers.Contains(observer))
  148. {
  149. observers.Add(observer);
  150. }
  151. }
  152. public void RemoveObserver(IObserver observer)
  153. {
  154. if (observers.Contains(observer))
  155. {
  156. observers.Remove(observer);
  157. }
  158. }
  159. }