/Assets/ThirdPersonCoverShooter/Scripts/AI/Actor.cs

https://bitbucket.org/stefan-g-i/likegta.sgi · C# · 335 lines · 207 code · 53 blank · 75 comment · 18 complexity · db5118ae138fd4ed4eba1f902c17261e MD5 · raw file

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace CoverShooter
  4. {
  5. [RequireComponent(typeof(Collider))]
  6. public class Actor : MonoBehaviour
  7. {
  8. #region Properties
  9. /// <summary>
  10. /// Is the object alive.
  11. /// </summary>
  12. public bool IsAlive
  13. {
  14. get { return _isAlive; }
  15. }
  16. /// <summary>
  17. /// Does the character have a weapon in their hands.
  18. /// </summary>
  19. public bool IsArmed
  20. {
  21. get { return _motor != null && _motor.CurrentWeapon > 0 && _motor.Weapons[_motor.CurrentWeapon - 1].Type != WeaponType.Tool; }
  22. }
  23. /// <summary>
  24. /// Cover the threat is hiding behind. Null if there isn't any.
  25. /// </summary>
  26. public Cover Cover
  27. {
  28. get { return _cover; }
  29. }
  30. /// <summary>
  31. /// Top position when the actor is standing.
  32. /// </summary>
  33. public Vector3 RelativeStandingTopPosition
  34. {
  35. get
  36. {
  37. if (_hasStandingHeight)
  38. return Vector3.up * _standingHeight;
  39. else
  40. return Vector3.up * _height;
  41. }
  42. }
  43. /// <summary>
  44. /// Current top position.
  45. /// </summary>
  46. public Vector3 RelativeTopPosition
  47. {
  48. get { return Vector3.up * _height; }
  49. }
  50. /// <summary>
  51. /// Top position when the actor is standing.
  52. /// </summary>
  53. public Vector3 StandingTopPosition
  54. {
  55. get
  56. {
  57. if (_hasStandingHeight)
  58. return transform.position + Vector3.up * _standingHeight;
  59. else
  60. return transform.position + Vector3.up * _height;
  61. }
  62. }
  63. /// <summary>
  64. /// Current top position.
  65. /// </summary>
  66. public Vector3 TopPosition
  67. {
  68. get { return transform.position + Vector3.up * _height; }
  69. }
  70. /// <summary>
  71. /// Collider attached to the object.
  72. /// </summary>
  73. public Collider Collider
  74. {
  75. get { return _collider; }
  76. }
  77. /// <summary>
  78. /// AI component attached to the object. Can be null.
  79. /// </summary>
  80. public AIController AI
  81. {
  82. get { return _ai; }
  83. }
  84. /// <summary>
  85. /// Current look direction of the actor's head.
  86. /// </summary>
  87. public Vector3 HeadDirection
  88. {
  89. get
  90. {
  91. if (_motor == null)
  92. return transform.forward;
  93. else
  94. return _motor.HeadForward;
  95. }
  96. }
  97. /// <summary>
  98. /// Is the AI attached to the actor alerted.
  99. /// </summary>
  100. public bool IsAlerted
  101. {
  102. get { return _isAlerted; }
  103. }
  104. #endregion
  105. #region Public fields
  106. /// <summary>
  107. /// Team number used by the AI.
  108. /// </summary>
  109. [Tooltip("Team number used by the AI.")]
  110. public int Side = 0;
  111. /// <summary>
  112. /// Is the actor aggresive. Value used by the AI. Owning AI usually overwrites the value if present.
  113. /// </summary>
  114. [Tooltip("Is the actor aggresive. Value used by the AI. Owning AI usually overwrites the value if present.")]
  115. public bool IsAggressive = true;
  116. #endregion
  117. #region Private fields
  118. private bool _isAlive = true;
  119. private Cover _cover;
  120. private bool _hasStandingHeight;
  121. private float _standingHeight;
  122. private float _height;
  123. private Collider _collider;
  124. private AIController _ai;
  125. private CharacterMotor _motor;
  126. private HashSet<DarkZone> _darkZones = new HashSet<DarkZone>();
  127. private HashSet<LightZone> _lightZones = new HashSet<LightZone>();
  128. private HashSet<GrassZone> _grassZones = new HashSet<GrassZone>();
  129. private bool _isAlerted;
  130. #endregion
  131. #region Events
  132. /// <summary>
  133. /// The actor enters a flashlight or any similar object.
  134. /// </summary>
  135. public void OnEnterGrass(GrassZone zone)
  136. {
  137. if (!_grassZones.Contains(zone))
  138. _grassZones.Add(zone);
  139. }
  140. /// <summary>
  141. /// The actor leaves a lighted area.
  142. /// </summary>
  143. public void OnLeaveGrass(GrassZone zone)
  144. {
  145. if (_grassZones.Contains(zone))
  146. _grassZones.Remove(zone);
  147. }
  148. /// <summary>
  149. /// The actor enters a flashlight or any similar object.
  150. /// </summary>
  151. public void OnEnterLight(LightZone zone)
  152. {
  153. if (!_lightZones.Contains(zone))
  154. _lightZones.Add(zone);
  155. }
  156. /// <summary>
  157. /// The actor leaves a lighted area.
  158. /// </summary>
  159. public void OnLeaveLight(LightZone zone)
  160. {
  161. if (_lightZones.Contains(zone))
  162. _lightZones.Remove(zone);
  163. }
  164. /// <summary>
  165. /// The actor enters a dark area.
  166. /// </summary>
  167. public void OnEnterDarkness(DarkZone zone)
  168. {
  169. if (!_darkZones.Contains(zone))
  170. _darkZones.Add(zone);
  171. }
  172. /// <summary>
  173. /// The actor leaves a dark area.
  174. /// </summary>
  175. public void OnLeaveDarkness(DarkZone zone)
  176. {
  177. if (_darkZones.Contains(zone))
  178. _darkZones.Remove(zone);
  179. }
  180. /// <summary>
  181. /// Notify the component of the standing height (used when in cover).
  182. /// </summary>
  183. public void OnStandingHeight(float value)
  184. {
  185. _hasStandingHeight = true;
  186. _standingHeight = value;
  187. }
  188. /// <summary>
  189. /// Notified by components that the actor is no longer alive.
  190. /// </summary>
  191. public void OnDead()
  192. {
  193. _isAlive = false;
  194. Actors.Unregister(this);
  195. }
  196. /// <summary>
  197. /// Tell the threat to mark itself as being behind the given cover.
  198. /// </summary>
  199. public void OnEnterCover(Cover cover)
  200. {
  201. _cover = cover;
  202. }
  203. /// <summary>
  204. /// Tell the threat to mark itself as out of cover.
  205. /// </summary>
  206. public void OnLeaveCover()
  207. {
  208. _cover = null;
  209. }
  210. /// <summary>
  211. /// Notified by an AI that the actor is alerted.
  212. /// </summary>
  213. public void OnAlerted()
  214. {
  215. _isAlerted = true;
  216. }
  217. #endregion
  218. #region Behaviour
  219. private void Update()
  220. {
  221. _height = _collider.bounds.extents.y * 2;
  222. }
  223. private void Awake()
  224. {
  225. _collider = GetComponent<Collider>();
  226. _ai = GetComponent<AIController>();
  227. _motor = GetComponent<CharacterMotor>();
  228. _height = _collider.bounds.extents.y * 2;
  229. }
  230. private void OnEnable()
  231. {
  232. Actors.Register(this);
  233. }
  234. private void OnDisable()
  235. {
  236. Actors.Unregister(this);
  237. }
  238. private void OnDestroy()
  239. {
  240. Actors.Unregister(this);
  241. }
  242. #endregion
  243. #region Public methods
  244. /// <summary>
  245. /// Calculates the view distance when looking at this actor.
  246. /// </summary>
  247. public float GetViewDistance(float viewDistance, bool isAlerted)
  248. {
  249. return Util.GetViewDistance(viewDistance, _darkZones, _lightZones, _motor.IsCrouching ? _grassZones : null, isAlerted);
  250. }
  251. #endregion
  252. }
  253. public static class Actors
  254. {
  255. public static IEnumerable<Actor> All
  256. {
  257. get { return _list; }
  258. }
  259. private static List<Actor> _list = new List<Actor>();
  260. private static Dictionary<GameObject, Actor> _map = new Dictionary<GameObject, Actor>();
  261. public static Actor Get(GameObject gameObject)
  262. {
  263. if (_map.ContainsKey(gameObject))
  264. return _map[gameObject];
  265. else
  266. return null;
  267. }
  268. public static void Register(Actor actor)
  269. {
  270. if (!_list.Contains(actor))
  271. _list.Add(actor);
  272. _map[actor.gameObject] = actor;
  273. }
  274. public static void Unregister(Actor actor)
  275. {
  276. if (_list.Contains(actor))
  277. _list.Remove(actor);
  278. if (_map.ContainsKey(actor.gameObject))
  279. _map.Remove(actor.gameObject);
  280. }
  281. }
  282. }