You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
10 KiB

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Networking.Server;
  5. using TMPro;
  6. using UnityEngine.UI;
  7. using System.Linq;
  8. [CreateAssetMenu(menuName = "Major Project/GameModes/Racetrack", order = 201)]
  9. public class RacetrackGameMode : GameMode
  10. {
  11. public MapManager mapManager;
  12. public blockSpawn spawn;
  13. public int MaxRound = 999;
  14. public string nextScene = "ServerTestScene";
  15. List<ClientData> ConnectedClients;
  16. public Material OverlayMaterial;
  17. public float scrollSpeed = 1.0f; //The rate at which the level will scroll past
  18. public int RoundCount { get; private set; }
  19. private Dictionary<ClientData, List<Block>> BlocksOwned;
  20. int currentBoulderCount;
  21. /// <summary>
  22. /// Called once before any players have spawned
  23. /// </summary>
  24. protected override void OnPreGameStart()
  25. {
  26. mapManager.init();
  27. }
  28. /// <summary>
  29. /// Called once all players have finished their moves but before the Objective is checked
  30. /// </summary>
  31. protected override void OnRoundEnd(PlayerData[] allPlayers)
  32. {
  33. cameraCheck(allPlayers);
  34. //At the end of each round, any stuck players are freed to resume moving next round
  35. foreach (PlayerData player in allPlayers)
  36. {
  37. player.character.stuck = false;
  38. if (player.character.inPit && player.client.Lives > 0)
  39. {
  40. player.character.respawnCharacter();
  41. }
  42. }
  43. RoundCount++;
  44. }
  45. void cameraCheck(PlayerData[] allPlayers)
  46. {
  47. //Get the average x-position of all players
  48. float xAvg = 0.0f;
  49. int livePlayerCount = 0;
  50. foreach (PlayerData player in allPlayers)
  51. {
  52. if (player.client.Lives > 0)
  53. {
  54. xAvg += player.character.transform.position.x;
  55. livePlayerCount++;
  56. }
  57. }
  58. xAvg = xAvg / livePlayerCount;
  59. //Turn that position into a vector in viewport space
  60. Vector3 xAvgPos = new Vector3(xAvg, 0.0f, 0.0f);
  61. Vector3 xAvgVP = Camera.main.WorldToViewportPoint(xAvgPos);
  62. //Debug.Log("xAvgPos = " + xAvgPos + ", xAvgVP = " + xAvgVP);
  63. //We move the camera forward by at least one increment
  64. //Keep doing it until the average x-position is roughly centred
  65. do
  66. {
  67. Camera.main.transform.Translate(scrollSpeed, 0, 0, Space.World);
  68. xAvgVP = Camera.main.WorldToViewportPoint(xAvgPos);
  69. //Debug.Log("Camera = " + Camera.main.transform.position + ", xAvgVP = " + xAvgVP);
  70. } while (xAvgVP.x > 0.5f || xAvgVP.y > 0.5f);
  71. //If the foremost player is off the screen, scroll forward to catch up with them
  72. //Find who's furthest ahead
  73. PlayerData playerAhead = allPlayers[0];
  74. foreach (PlayerData player in allPlayers)
  75. {
  76. if (player.client.Lives > 0 && player.character.transform.position.x > playerAhead.character.transform.position.x)
  77. {
  78. playerAhead = player;
  79. }
  80. }
  81. //Turn their position to a viewport vector
  82. Vector3 playerVP = Camera.main.WorldToViewportPoint(playerAhead.character.transform.position);
  83. //If that position is not in view, advance until it is
  84. while (playerVP.x > 1 || playerVP.y > 1)
  85. {
  86. Camera.main.transform.Translate(scrollSpeed, 0, 0, Space.World);
  87. playerVP = Camera.main.WorldToViewportPoint(playerAhead.character.transform.position);
  88. }/**/
  89. //We check for track sections we need to add/remove
  90. mapManager.checkTrack();
  91. //spawn.wakeup();
  92. //Move the camera forward at a steady rate each round
  93. /*if (scrollSpeed > 0.0f)
  94. {
  95. Camera.main.transform.Translate(scrollSpeed, 0, 0, Space.World);
  96. mapManager.checkTrack();
  97. //Debug.Log("New camera position at x = " + Camera.main.transform.position.x);
  98. //Plan: get average position of surviving players, centre camera view on it
  99. //Also, will need to check every time someone moves: are they still on camera?
  100. //If ahead of camera, advance it until they're visible
  101. //If behind camera, they lose a life & respawn
  102. }
  103. else
  104. {
  105. //Debug.Log("Not scrolling");
  106. }*/
  107. }
  108. /// <summary>
  109. /// Checks if the Game is finished
  110. /// </summary>
  111. /// <returns>returns if game is finished</returns>
  112. public override bool isGameOver(PlayerData[] allPlayers)
  113. {
  114. return (RoundCount >= MaxRound -1);
  115. }
  116. /// <summary>
  117. /// Called once per player after they have moved onto a block
  118. /// </summary>
  119. /// <param name="character">Character which moved</param>
  120. /// <param name="client">Client of the character</param>
  121. /// <param name="currentBlock">Block moved onto</param>
  122. protected override void OnPlayerMoved(Character character, ClientData client, Block currentBlock)
  123. {
  124. handleFalling(character, client, currentBlock, character.justMoved);
  125. /*Debug.Log("Moved to square at " + currentBlock.transform.position.x + ", "
  126. + currentBlock.transform.position.y + ", "
  127. + currentBlock.transform.position.z);
  128. //If a character has fallen in the water or into a pit, we mark that fact, and they lose the rest of their turn
  129. character.inWater = currentBlock.isWater;
  130. character.inPit = currentBlock.isPit;
  131. if (character.inWater == true || character.inPit == true)
  132. {
  133. character.stuck = true;
  134. }
  135. Debug.Log("inWater = " + character.inWater + ", inPit = " + character.inPit + ", stuck = " + character.stuck);*/
  136. //Commented out because we don't do this in the racetrack mode
  137. /*ClientData OwnedClient;
  138. Material overlay = null;
  139. if (isOwned(currentBlock, out OwnedClient))
  140. {
  141. if (OwnedClient == client)
  142. return;
  143. BlocksOwned[OwnedClient].Remove(currentBlock);
  144. foreach (Material mat in currentBlock.GetComponent<Renderer>().materials)
  145. {
  146. if (mat.name == OverlayMaterial.name + " (Instance)")
  147. overlay = mat;
  148. }
  149. }
  150. if (overlay == null)
  151. {
  152. overlay = new Material(OverlayMaterial);
  153. List<Material> mats = new List<Material>(currentBlock.GetComponent<Renderer>().materials);
  154. mats.Add(overlay);
  155. currentBlock.GetComponent<Renderer>().materials = mats.ToArray();
  156. }
  157. overlay.SetColor("_NewColor", client.Color);
  158. if (!BlocksOwned.ContainsKey(client))
  159. BlocksOwned.Add(client, new List<Block>());
  160. BlocksOwned[client].Add(currentBlock);
  161. if (overlay != null)
  162. currentBlock.StartCoroutine(AnimateBlock(overlay, 0.25f));*/
  163. }
  164. protected override void OnRoundStart(PlayerData[] allPlayers)
  165. {
  166. }
  167. protected override void OnAllPlayersMoved(PlayerData[] allPlayers)
  168. {
  169. foreach (PlayerData player in allPlayers)
  170. {
  171. /* The justMoved variable is used to determine whether a player taking their turn in the water should become stuck
  172. * (because they moved into/in the water), or not (because they're turning while remaining in the same square)
  173. * It's not needed from move to move, so we clear it
  174. */
  175. player.character.justMoved = false;
  176. /* if (BlocksOwned.ContainsKey(player.client))
  177. player.client.SceneScore = BlocksOwned[player.client].Count;
  178. else
  179. player.client.SceneScore = 0;*/
  180. }
  181. }
  182. protected override void OnGameOver(PlayerData[] allPlayers)
  183. {
  184. throw new System.NotImplementedException();
  185. }
  186. private bool isOwned(Block block, out ClientData client)
  187. {
  188. client = null;
  189. foreach (KeyValuePair<ClientData, List<Block>> ownedList in BlocksOwned)
  190. {
  191. if (ownedList.Value.Contains(block))
  192. {
  193. client = ownedList.Key;
  194. return true;
  195. }
  196. }
  197. return false;
  198. }
  199. private void handleFalling(Character character, ClientData client, Block currentBlock, bool didMove)
  200. {
  201. //If a character has fallen in the water or into a pit, we mark that fact, and they lose the rest of their turn
  202. character.inWater = currentBlock.isWater;
  203. character.inPit = currentBlock.isPit;
  204. character.onCrystal = currentBlock.isCrystals;
  205. character.underRock = currentBlock.isRock;
  206. if (didMove && (character.inWater || character.inPit))
  207. {
  208. character.stuck = true;
  209. }
  210. //Debug.Log("inWater = " + character.inWater + ", inPit = " + character.inPit + ", stuck = " + character.stuck);
  211. }
  212. protected override void OnPlayerKilled(Character character, ClientData client)
  213. {
  214. if (character.inPit || character.onCrystal)
  215. {
  216. character.lives -= 1;
  217. character.ClientLink.Lives = character.lives;
  218. }
  219. if(character.underRock && currentBoulderCount < 1)
  220. {
  221. character.lives -= 1;
  222. character.ClientLink.Lives = character.lives;
  223. }
  224. }
  225. private IEnumerator AnimateBlock(Material mat, float time)
  226. {
  227. float timeElasped = 0;
  228. while (timeElasped < time)
  229. {
  230. mat.SetFloat("_Multiplier", (timeElasped / time));
  231. yield return new WaitForEndOfFrame();
  232. timeElasped += Time.deltaTime;
  233. }
  234. mat.SetFloat("_Multiplier", 1);
  235. }
  236. protected override void OnGameStart(PlayerData[] AllPlayers)
  237. {
  238. BlocksOwned = new Dictionary<ClientData, List<Block>>();
  239. RoundCount = 0;
  240. AllPlayers = getPlayerOrder(AllPlayers);
  241. for (int i = 0; i < AllPlayers.Length; i++)
  242. {
  243. OnPlayerMoved(AllPlayers[i].character, AllPlayers[i].client, AllPlayers[i].character.CurrentBlock);
  244. }
  245. }
  246. public override PlayerData[] getPlayerOrder(PlayerData[] AllPlayers)
  247. {
  248. AllPlayers = AllPlayers.ToArray().OrderBy(unit => unit.character.CurrentBlock.transform.position.x).ToArray();
  249. return AllPlayers;
  250. }
  251. }