Enemy.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System;
  5. /// <summary>
  6. /// This component is responsible for moving and enemy and detecting when it has been captured,
  7. /// and/or gone off screen.
  8. /// </summary>
  9. [RequireComponent(typeof(PoolObject))]
  10. [RequireComponent(typeof(FollowTarget))]
  11. public class Enemy : Collidable, ILevelEditorGameEntity
  12. {
  13. public EnemyType type;
  14. public int points = 100;
  15. public SoundEvent[] caughtSounds;
  16. public SoundEvent goneThroughSound = SoundEvent.spermout;
  17. //These are used by the condom to align itself with the enemy
  18. public Vector3 hitOffset;
  19. protected bool captured;
  20. private PoolObject _poolObject;
  21. private bool _hasMultipleSineModifier;
  22. private bool _hasSineMovement;
  23. private FollowTarget _followTarget;
  24. public bool HasSineMovement { get { return _hasSineMovement; } }
  25. public bool HasMultipleSineModifier { get { return _hasMultipleSineModifier; } }
  26. public float scaleYFactor = 1; //0 would mean always from the center, 1 means it can vary through the screen's height
  27. const float MAX_POINTS_SCALE_FACTOR = 2;
  28. #region Unity Callbacks
  29. protected override void Awake()
  30. {
  31. base.Awake();
  32. _poolObject = GetComponent<PoolObject>();
  33. _followTarget = GetComponent<FollowTarget>();
  34. if (GetComponentsInChildren<SineMovement>().Length != 0)
  35. {
  36. _hasSineMovement = true;
  37. }
  38. MultipleSineModifier sineModifier = GetComponentInChildren<MultipleSineModifier>();
  39. if (sineModifier != null && sineModifier.phasors.Length > 1)
  40. {
  41. _hasMultipleSineModifier = true;
  42. }
  43. #if LEVEL_EDITOR
  44. if (!Pool.isSpawning)
  45. {
  46. NotificationCenter.Post(NotificationType.AddEnemyToLevelEditor, this);
  47. }
  48. #endif
  49. }
  50. #if LEVEL_EDITOR
  51. //Since the game designer can drag during level editing, we need to ensure this
  52. void Update()
  53. {
  54. Vector3 pos = transform.localPosition;
  55. pos.z = 0;
  56. transform.localPosition = pos;
  57. }
  58. #endif
  59. #endregion
  60. #region ILevelEditorGameEntity
  61. ushort ILevelEditorGameEntity.GetTypeForEncoding()
  62. {
  63. return (ushort)type;
  64. }
  65. LevelEditorGameEntityType ILevelEditorGameEntity.GetGameEntityType()
  66. {
  67. return LevelEditorGameEntityType.Enemy;
  68. }
  69. #endregion
  70. void CustomFixedUpdate()
  71. {
  72. //AVDebug.Log(RecordingManager.Ticks+" - "+name + ": "+transform.localPosition.x);
  73. //if it is captured let it go on a bit so that the condom linked with goes also off screen
  74. if (captured &&
  75. transform.localPosition.x > GameConstants.GAME_WIDTH * 3/2)
  76. {
  77. _poolObject.Despawn();
  78. }
  79. /// Note that the enemy's sprite's pivot is on the left. So when position of the enemy goes offscreen,
  80. /// it means it is not visible anymore
  81. if (!captured &&
  82. transform.localPosition.x > GameConstants.GAME_WIDTH)
  83. {
  84. _poolObject.Despawn();
  85. GoneThrough();
  86. }
  87. }
  88. public void OnCollisionWithCondom(CondomBase condom)
  89. {
  90. if (!captured)
  91. {
  92. CapturedByACondom(condom);
  93. }
  94. }
  95. #region NGUI Callbacks
  96. void OnPress(bool isPressed)
  97. {
  98. if (isPressed)
  99. {
  100. NotificationCenter.Post(NotificationType.Fire, new Vector2(Input.mousePosition.x, Input.mousePosition.y));
  101. }
  102. }
  103. #endregion
  104. #region Pool Messages
  105. protected virtual void OnSpawnMsg()
  106. {
  107. GetComponent<Collider>().enabled = true;
  108. captured = false;
  109. transform.rotation = Quaternion.identity;
  110. Logger.LogFlurryEvent("EnemySpawned", "Type", type.ToString());
  111. }
  112. #endregion
  113. #region Capturing Behaviours
  114. void CapturedByACondom(CondomBase condom)
  115. {
  116. //In the same frame it might have collided with another enemy
  117. if (condom.CanCaptureEnemy(this))
  118. {
  119. Logger.LogFlurryEvent("EnemyCaptured", "Type", type.ToString(), "CondomType", condom.type.ToString());
  120. captured = true;
  121. HitEvent hitEvent;
  122. hitEvent.hitObject = gameObject;
  123. hitEvent.projectile = condom;
  124. //AVDebug.Log(condom.name + " capture " +name+ " at tick "+RecordingManager.Ticks);
  125. NotificationCenter.Post(NotificationType.HitSomething, hitEvent);
  126. condom.CapturedEnemy(this);
  127. //disable the colliders. They won't hit anything else
  128. GetComponent<Collider>().enabled = false;
  129. GotHit();
  130. }
  131. }
  132. #endregion
  133. protected virtual void GoneThrough()
  134. {
  135. SoundManager.Play(goneThroughSound);
  136. Logger.LogFlurryEvent("EnemyGoneThrough", "Type", type.ToString());
  137. NotificationCenter.Post(NotificationType.EnemyGoneThrough, type);
  138. }
  139. public void Despawn()
  140. {
  141. _poolObject.Despawn();
  142. }
  143. public void Follow(Transform t)
  144. {
  145. BroadcastMessage("OnDisableMovementMsg");
  146. Vector3 offset = hitOffset;
  147. offset.x = -offset.x;
  148. _followTarget.SetTarget(t, offset);
  149. }
  150. public void GotHit()
  151. {
  152. SoundManager.PlayRandom(caughtSounds);
  153. int scaledPoints = GetScaledPointsAccordingToCapturePosition(points, transform.localPosition.x + hitOffset.x);
  154. ScoreChangeData scoreChangeData = new ScoreChangeData(ScoreChangeData.Source.Enemy, scaledPoints, transform.TransformPoint(hitOffset));
  155. NotificationCenter.Post(NotificationType.AddToScore, scoreChangeData);
  156. }
  157. /// <summary>
  158. /// This is to make the score more skill based, where we award players more if the capture it earlier or later.
  159. /// The scaleFactor ranges from MAX_POINTS_SCALE_FACTOR to 1 and back to MAX_POINTS_SCALE_FACTOR, with 1 when it
  160. /// is captured in the middle screen, and MAX_POINTS_SCALE_FACTOR at the edges
  161. /// </summary>
  162. /// <returns>
  163. /// The scaled points according to capture position.
  164. /// </returns>
  165. /// <param name='posX'>
  166. /// The local position in the x, 0 being on the left (just spawned), 1024 being on the right
  167. /// </param>
  168. public static int GetScaledPointsAccordingToCapturePosition(int points, float posX)
  169. {
  170. //normalising the x position to be between 0 and 1. 0 == left, 1 == right
  171. float x = Mathf.InverseLerp(0, GameConstants.GAME_WIDTH, posX);
  172. float scaleFactor;
  173. //if x is in the first in the first half, the scale factor should be 2 on the left, 1 in the middle of the screen
  174. if (x < 0.5f)
  175. {
  176. scaleFactor = Mathf.Lerp(MAX_POINTS_SCALE_FACTOR, 1, x*2);
  177. } else //the scale factor should be 1 in the middle and 2 on the right
  178. {
  179. scaleFactor = Mathf.Lerp(MAX_POINTS_SCALE_FACTOR, 1, (1-x) * 2);
  180. }
  181. AVDebug.Assert(scaleFactor >= 1 && scaleFactor <= MAX_POINTS_SCALE_FACTOR, "Scale factor is beyond expected range - "+scaleFactor);
  182. return (int)(points * scaleFactor);
  183. }
  184. }