/Tower Defense Rewind/Assets/Scripts/Game/Game.cs

https://bitbucket.org/realityfoil/ld26-optimality · C# · 300 lines · 258 code · 41 blank · 1 comment · 44 complexity · 3a44f4e68a392237d20f3370b0614c1f MD5 · raw file

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Xml.Serialization;
  6. using System;
  7. public class Game : MonoBehaviour {
  8. public GameObject wallPrefab;
  9. public GameObject basePrefab;
  10. public GameObject spawnerPrefab;
  11. public GameObject towerPrefab;
  12. public GameObject background;
  13. public GUIManager guiManager;
  14. public AudioSource explosion;
  15. public AudioSource towerRemove;
  16. public AudioSource baseExplosion;
  17. public float selectDistance;
  18. public LayerMask selectionMask;
  19. public int startingBaseHP;
  20. public int basePoints;
  21. public int towerPoints;
  22. public Texture2D[] levels;
  23. public int level;
  24. public int[] waves;
  25. [Serializable]
  26. public class WaveScores {
  27. public int[] waveScore;
  28. }
  29. public WaveScores[] levelScores;
  30. public Map map;
  31. private List<GameObject> levelObjects;
  32. private IDictionary<Square, GameObject> prefabMap;
  33. [HideInInspector]
  34. public int score;
  35. [HideInInspector]
  36. public int enemies;
  37. [HideInInspector]
  38. public int numTowers;
  39. [HideInInspector]
  40. public int wave;
  41. [HideInInspector]
  42. public int baseHP;
  43. [HideInInspector]
  44. public Vector3[,] directionToMove;
  45. private List<Spawner> spawners;
  46. private List<Tower> towers;
  47. private GameObject @base;
  48. public enum Mode {
  49. START,
  50. LEVEL_SELECT,
  51. NEXT_WAVE,
  52. PLAY,
  53. SURVIVE,
  54. LOSE,
  55. }
  56. [HideInInspector]
  57. public Mode mode;
  58. public void DamageBase() {
  59. baseHP--;
  60. baseExplosion.Play();
  61. }
  62. public void RemoveEnemy() {
  63. explosion.Play();
  64. enemies--;
  65. }
  66. void Start() {
  67. prefabMap = new Dictionary<Square, GameObject>() {
  68. { Square.EMPTY, null },
  69. { Square.WALL, wallPrefab },
  70. { Square.BASE, basePrefab },
  71. { Square.SPAWNER, spawnerPrefab },
  72. { Square.ENEMY, null },
  73. { Square.TOWER, towerPrefab },
  74. };
  75. mode = Mode.START;
  76. guiManager.StartGame();
  77. Clear();
  78. }
  79. public void LoadLevel(int level) {
  80. this.level = level;
  81. mode = Mode.NEXT_WAVE;
  82. guiManager.NextWave();
  83. background.SetActive(true);
  84. map = new Map(levels[level - 1]);
  85. directionToMove = new Vector3[map.width, map.height];
  86. BuildMap();
  87. ShortestPaths();
  88. wave = waves.Length;
  89. score = 0;
  90. baseHP = startingBaseHP;
  91. }
  92. void Clear() {
  93. if (levelObjects != null) {
  94. foreach (GameObject obj in levelObjects) {
  95. Destroy(obj);
  96. }
  97. }
  98. levelObjects = new List<GameObject>();
  99. background.SetActive(false);
  100. }
  101. void LevelSelect() {
  102. Clear();
  103. mode = Mode.LEVEL_SELECT;
  104. guiManager.SelectLevel();
  105. }
  106. public int WaveScore() {
  107. return baseHP * basePoints + numTowers * towerPoints;
  108. }
  109. void Update() {
  110. switch (mode) {
  111. case Mode.START:
  112. UpdateStart();
  113. break;
  114. case Mode.LEVEL_SELECT:
  115. UpdateLevelSelect();
  116. break;
  117. case Mode.NEXT_WAVE:
  118. UpdateNextWave();
  119. break;
  120. case Mode.PLAY:
  121. UpdatePlay();
  122. break;
  123. case Mode.LOSE:
  124. UpdateLose();
  125. break;
  126. case Mode.SURVIVE:
  127. UpdateSurvive();
  128. break;
  129. }
  130. }
  131. void UpdateStart() {
  132. if (Input.GetButtonDown("Click")) {
  133. mode = Mode.LEVEL_SELECT;
  134. guiManager.SelectLevel();
  135. }
  136. }
  137. void UpdateLevelSelect() {
  138. // Waiting on callback from a level button.
  139. }
  140. void UpdateNextWave() {
  141. if (Input.GetButtonDown("Back")) {
  142. LevelSelect();
  143. return;
  144. }
  145. if (!Input.GetButtonDown("Click")) {
  146. return;
  147. }
  148. guiManager.PlayGame();
  149. mode = Mode.PLAY;
  150. enemies = 0;
  151. foreach (Tower tower in towers) {
  152. tower.Reset();
  153. }
  154. foreach (Spawner spawner in spawners) {
  155. spawner.numEnemies = waves[wave - 1];
  156. enemies += spawner.numEnemies;
  157. }
  158. }
  159. void UpdatePlay() {
  160. if (Input.GetButtonDown("Back")) {
  161. LevelSelect();
  162. return;
  163. }
  164. RaycastHit hit;
  165. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  166. if (Physics.Raycast(ray, out hit, selectDistance, selectionMask)) {
  167. Tower tower = hit.collider.GetComponent<Tower>();
  168. if (Input.GetButtonDown("Click")) {
  169. map[tower.transform.position] = Square.EMPTY;
  170. ShortestPaths();
  171. tower.Remove();
  172. numTowers--;
  173. } else {
  174. tower.hover = true;
  175. }
  176. }
  177. if (baseHP <= 0) {
  178. mode = Mode.LOSE;
  179. guiManager.LoseGame();
  180. score += WaveScore();
  181. } else if (enemies == 0) {
  182. score += WaveScore();
  183. --wave;
  184. if (wave == 0) {
  185. guiManager.SurviveGame();
  186. mode = Mode.SURVIVE;
  187. } else {
  188. guiManager.NextWave();
  189. mode = Mode.NEXT_WAVE;
  190. }
  191. }
  192. }
  193. void UpdateLose() {
  194. if (Input.GetButtonDown("Click") || Input.GetButtonDown("Back")) {
  195. LevelSelect();
  196. }
  197. }
  198. void UpdateSurvive() {
  199. if (Input.GetButtonDown("Click") || Input.GetButtonDown("Back")) {
  200. LevelSelect();
  201. }
  202. }
  203. void BuildMap() {
  204. numTowers = 0;
  205. Vector3 position = Vector3.zero;
  206. spawners = new List<Spawner>();
  207. towers = new List<Tower>();
  208. for (position.x = 0; position.x < map.width; ++position.x) {
  209. for (position.y = 0; position.y < map.height; ++position.y) {
  210. Square type = map[position];
  211. GameObject prefab = prefabMap[type];
  212. if (prefab != null) {
  213. GameObject obj = (GameObject)Instantiate(
  214. prefab,
  215. position,
  216. prefab.transform.localRotation);
  217. obj.transform.parent = transform;
  218. if (type == Square.SPAWNER) {
  219. spawners.Add(obj.GetComponent<Spawner>());
  220. } else if (type == Square.BASE) {
  221. @base = obj;
  222. } else if (type == Square.TOWER) {
  223. numTowers++;
  224. towers.Add(obj.GetComponent<Tower>());
  225. }
  226. levelObjects.Add(obj);
  227. }
  228. }
  229. }
  230. }
  231. void ShortestPaths() {
  232. int[,] shortest = new int[map.width, map.height];
  233. for (int x = 0; x < shortest.GetLength(0); ++x) {
  234. for (int y = 0; y < shortest.GetLength(1); ++y) {
  235. shortest[x, y] = 1000;
  236. }
  237. }
  238. shortest[(int)@base.transform.position.x, (int)@base.transform.position.y] = 0;
  239. ShortestPathsRecursive(@base.transform.position, shortest);
  240. }
  241. void ShortestPathsRecursive(Vector3 target, int[,] shortest) {
  242. int myShortest = shortest[(int)target.x, (int)target.y];
  243. foreach (Vector3 direction in new Vector3[] {
  244. Vector3.down, Vector3.left, Vector3.up, Vector3.right, }) {
  245. Vector3 check = target + direction;
  246. if (check.x < 0 || check.y < 0 || check.x >= shortest.GetLength(0)
  247. || check.y >= shortest.GetLength(1)) {
  248. continue;
  249. }
  250. if (map[check] == Square.EMPTY || map[check] == Square.SPAWNER) {
  251. if (shortest[(int)check.x, (int)check.y] > myShortest + 1) {
  252. shortest[(int)check.x, (int)check.y] = myShortest + 1;
  253. directionToMove[(int)check.x, (int)check.y] = -direction;
  254. ShortestPathsRecursive(check, shortest);
  255. }
  256. }
  257. }
  258. }
  259. }