SceneryGenerator.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using System;
  4. using UnityEngine.UI;
  5. /// <summary>
  6. /// This component is responsible for creating scenery props randomly selected from <code>sceneryPrefabs</code>
  7. /// The randomness does not use the <code>RandomSingleton</code>. This is due to the fact that we don't have control
  8. /// of order of execution (unless we use Execution Order feature which we find hacky). So since it doesn't affect the
  9. /// gameplay as such, for now we decided to use Unity's random which is independent from RandomSingleton used to
  10. /// generate the enemies.
  11. /// </summary>
  12. public class SceneryGenerator : MonoBehaviour
  13. {
  14. public static SceneryGenerator Instance;
  15. /// <summary>
  16. /// Prefabs will be randomly selected from here with gamedesigner-set weights
  17. /// To create prefabs, the sprites will probably be normal textures, rather than part of an atlas. This is because
  18. /// they will be quite big and would defeat the purpose of putting them in an atlas. So in NGUI you can create
  19. /// a texture widget, where you just drag and drop the texture on the widget's texture field. You might need
  20. /// to change the shader so it's transparent as well. The widget's pivot needs to be set carefully.
  21. /// The horizontal pivolt must always be set to the right pivot. If it's a top-bottom prop, leave the vertical pivot to middle.
  22. /// Otherwise set it accordingly, e.g. if it's a prop coming from the top, set the vertical pivot to top.
  23. /// Reset the transform's position to zero
  24. /// </summary>
  25. public LootTable sceneryPrefabs;
  26. public int minSpacing = 300;
  27. public int maxSpacing = 600;
  28. /// <summary>
  29. /// Tweak this value to get a parallax effect
  30. /// </summary>
  31. public float speed = 150;
  32. /// <summary>
  33. /// This is the z value used for the generated props, where together with the appropriate speed
  34. /// will achieve a parallax effect.
  35. /// For foreground we are currently using -2 (in front of bullets)
  36. /// For midground we are currently using 9 (just in front of backgrounds)
  37. /// </summary>
  38. public float zValue;
  39. Transform _anchor;
  40. List<Transform> _sceneryPropsTransforms = new List<Transform>();
  41. List<SceneryProp> _sceneryProps = new List<SceneryProp>();
  42. float _nextSceneryX = 0;
  43. float _originalSpeed;
  44. bool _isSpawning;
  45. public bool _isPlaying = false;
  46. const int STOP_SPAWNING_AT_TIME_LEFT = 18;
  47. #region Unity Callbacks
  48. void Awake()
  49. {
  50. Instance = this;
  51. _anchor = LevelsManager.Instance.levelEndAnchor;
  52. _originalSpeed = speed;
  53. if (enabled) //for debugging purposes so we can disable the component at design time for a debug session
  54. {
  55. enabled = false;
  56. NotificationCenter.AddListener(OnGameStart, NotificationType.GameStart);
  57. NotificationCenter.AddListener(OnEndLife, NotificationType.EndLife);
  58. NotificationCenter.AddListener(OnGetLife, NotificationType.GetLife);
  59. NotificationCenter.AddListener(OnGameOver, NotificationType.GameOver);
  60. NotificationCenter.AddListener(OnChangeScrollingSpeed, NotificationType.ChangeScrollingSpeed);
  61. NotificationCenter.AddListener(OnTimeLeftUpdate, NotificationType.TimeLeftUpdate);
  62. }
  63. }
  64. private void OnGetLife(Notification note)
  65. {
  66. //_isPlaying = true;
  67. }
  68. private void OnEndLife(Notification note)
  69. {
  70. _isPlaying = false;
  71. }
  72. void OnDestroy()
  73. {
  74. NotificationCenter.RemoveListener(OnGameStart, NotificationType.GameStart);
  75. NotificationCenter.RemoveListener(OnGameOver, NotificationType.GameOver);
  76. NotificationCenter.RemoveListener(OnChangeScrollingSpeed, NotificationType.ChangeScrollingSpeed);
  77. NotificationCenter.RemoveListener(OnTimeLeftUpdate, NotificationType.TimeLeftUpdate);
  78. NotificationCenter.RemoveListener(OnEndLife, NotificationType.EndLife);
  79. NotificationCenter.RemoveListener(OnGetLife, NotificationType.GetLife);
  80. }
  81. void Update()
  82. {
  83. if (!BackgroundManager.Instance._isPlaying)
  84. {
  85. return;
  86. }
  87. float deltaX = speed * Time.deltaTime;
  88. if (_isSpawning)
  89. {
  90. _nextSceneryX += deltaX;
  91. //if the next scenery marker is visible, create the next prop
  92. if (_nextSceneryX > -GameConstants.GAME_WIDTH/2)
  93. {
  94. CreateNextSceneryProp();
  95. }
  96. }
  97. for (int i = _sceneryPropsTransforms.Count-1; i >= 0; i--)
  98. {
  99. Transform sceneryPropTransform = _sceneryPropsTransforms[i];
  100. SceneryProp sceneryProp = _sceneryProps[i];
  101. //move scenery
  102. sceneryPropTransform.GetComponent<RectTransform>().anchoredPosition += new Vector2(deltaX, 0);
  103. //check if needs to be removed
  104. if (sceneryPropTransform.GetComponent<RectTransform>().anchoredPosition.x> GameConstants.GAME_WIDTH)
  105. {
  106. sceneryProp.Despawn();
  107. _sceneryPropsTransforms.RemoveAt(i);
  108. _sceneryProps.RemoveAt(i);
  109. }
  110. }
  111. }
  112. #endregion
  113. #region Notification Callbacks
  114. void OnGameStart(Notification note)
  115. {
  116. enabled = true;
  117. _isSpawning = true;
  118. _isPlaying = true;
  119. _nextSceneryX -= UnityEngine.Random.Range(minSpacing, maxSpacing);
  120. }
  121. void OnGameOver(Notification note)
  122. {
  123. enabled = false;
  124. foreach (SceneryProp s in _sceneryProps)
  125. {
  126. s.Despawn();
  127. }
  128. _sceneryPropsTransforms.Clear();
  129. _sceneryProps.Clear();
  130. }
  131. void OnChangeScrollingSpeed(Notification note)
  132. {
  133. float scrollingSpeedFactor = (float)note.data;
  134. speed = _originalSpeed * scrollingSpeedFactor;
  135. }
  136. void OnTimeLeftUpdate(Notification note)
  137. {
  138. float timeLeft = (float)note.data;
  139. //Stop spawning stuff so that it doesn't intermingle with the end of level scenery
  140. if (_isSpawning && timeLeft <= STOP_SPAWNING_AT_TIME_LEFT)
  141. {
  142. _isSpawning = false;
  143. }
  144. }
  145. #endregion
  146. void CreateNextSceneryProp()
  147. {
  148. Transform sceneryPropTransform = sceneryPrefabs.GetRandomItem();
  149. SceneryProp sceneryProp = sceneryPropTransform.GetComponent<SceneryProp>();
  150. Vector3 originalPos = sceneryPropTransform.GetComponent<RectTransform>().anchoredPosition;
  151. originalPos.x = _nextSceneryX /*- sceneryProp.MaxX*/;
  152. originalPos.z = zValue;
  153. Vector3 originalScale = sceneryPropTransform.localScale;
  154. sceneryPropTransform.SetParent(_anchor);
  155. sceneryPropTransform.GetComponent<RectTransform>().anchoredPosition = originalPos;
  156. sceneryPropTransform.localScale = originalScale;
  157. _sceneryPropsTransforms.Add(sceneryPropTransform);
  158. _sceneryProps.Add(sceneryProp);
  159. //_nextSceneryX += sceneryProp.MinX;
  160. _nextSceneryX -= UnityEngine.Random.Range(minSpacing, maxSpacing);
  161. //add some randomness in flipping on the X axis
  162. bool isXFlipped = UnityEngine.Random.value < 0.5f;
  163. if (isXFlipped)
  164. {
  165. RawImage uiTexture = sceneryPropTransform.GetComponent<RawImage>();
  166. if (uiTexture != null) //if it is null, it must be some composite scenery prop with multiple UITextures... just skip it in that case
  167. {
  168. Rect r = uiTexture.uvRect;
  169. r.x = 1;
  170. r.width = -1;
  171. uiTexture.uvRect = r;
  172. }
  173. }
  174. }
  175. }