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.

375 lines
13 KiB

  1. using Networking.Client;
  2. using Networking.Server;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. //public class MapManager : MonoBehaviour
  7. [CreateAssetMenu(menuName = "Major Project/Map Manager")]
  8. public class MapManager : ScriptableObject
  9. {
  10. public ClientList clients;
  11. public GameObject spawn4; //The section to use as a spawn-point for games with 2-5 players
  12. public GameObject spawn8; //The section to use a spawn-point for games with 5-8 players
  13. //In 5-player games, we choose between them at random
  14. public List<MapSection> sections; //The list of sections to choose from after starting
  15. public int minConns = 2; //The minimum number of valid connections between two map sections for them to be allowed to link up
  16. public List<MapSection> activeSections; //The list of sections that have been placed on the map (and not removed)
  17. MapSection lastSection; //Which map-section was most recently added?
  18. float startX = -16.0f; //The x-position of the current start of the track
  19. float endX = -16.0f; //The x-position of the current end of the track
  20. int totalSections = 0; //How many sections have been added? Including ones that have been deleted
  21. int initialPlayerCount;
  22. int diffMin; //Minimum difficulty for a map section to be selected
  23. int diffMax; //Maximum difficulty for a map section to be selected
  24. int diffMinStart = 0; //Initial minimum difficulty for a map section to be selected
  25. int diffMaxStart = 1; //Initial maximum difficulty for a map section to be selected
  26. int diffMinMax = 4; //The highest diffMin can go - ensure that it doesn't go too high to have legal map sections
  27. int widthMin; //The minimum widthIn that we want for a new map section
  28. int widthMax; //The maximum widthIn that we want for a new map section
  29. int minPossibleWidth = 3; //The minimum to which widthMin and widthMax can be reduced
  30. public void init()
  31. {
  32. initialPlayerCount = clients.ConnectedClients.Count;
  33. activeSections = new List<MapSection>();
  34. if (initialPlayerCount < 5)
  35. {
  36. addSection(spawn4.GetComponent<MapSection>());
  37. }
  38. else if (initialPlayerCount > 5)
  39. {
  40. addSection(spawn8.GetComponent<MapSection>());
  41. }
  42. else
  43. {
  44. if (Random.Range(0.0f, 1.0f) < 0.5f)
  45. {
  46. addSection(spawn4.GetComponent<MapSection>());
  47. }
  48. else
  49. {
  50. addSection(spawn8.GetComponent<MapSection>());
  51. }
  52. }
  53. widthMin = activeSections[0].widthOut - 2;
  54. widthMax = activeSections[0].widthOut + 2;
  55. //Set the maximum possible diffMin value to 1 less than the highest difficulty on the section list
  56. diffMinMax = 0;
  57. foreach (MapSection section in sections)
  58. {
  59. if (section.difficulty > diffMinMax)
  60. {
  61. diffMinMax = section.difficulty;
  62. }
  63. }
  64. diffMinMax--;
  65. switch (initialPlayerCount)
  66. {
  67. case 2:
  68. foreach (GameObject spawnBlock in lastSection.spawns2)
  69. {
  70. spawnBlock.GetComponent<Block>().isSpawnable = true;
  71. }
  72. break;
  73. case 3:
  74. foreach (GameObject spawnBlock in lastSection.spawns3)
  75. {
  76. spawnBlock.GetComponent<Block>().isSpawnable = true;
  77. }
  78. break;
  79. case 4:
  80. foreach (GameObject spawnBlock in lastSection.spawns4)
  81. {
  82. spawnBlock.GetComponent<Block>().isSpawnable = true;
  83. }
  84. break;
  85. case 5:
  86. foreach (GameObject spawnBlock in lastSection.spawns5)
  87. {
  88. spawnBlock.GetComponent<Block>().isSpawnable = true;
  89. }
  90. break;
  91. case 6:
  92. foreach (GameObject spawnBlock in lastSection.spawns6)
  93. {
  94. spawnBlock.GetComponent<Block>().isSpawnable = true;
  95. }
  96. break;
  97. case 7:
  98. foreach (GameObject spawnBlock in lastSection.spawns7)
  99. {
  100. spawnBlock.GetComponent<Block>().isSpawnable = true;
  101. }
  102. break;
  103. case 8:
  104. foreach (GameObject spawnBlock in lastSection.spawns8)
  105. {
  106. spawnBlock.GetComponent<Block>().isSpawnable = true;
  107. }
  108. break;
  109. default:
  110. foreach (GameObject spawnBlock in lastSection.spawns1)
  111. {
  112. spawnBlock.GetComponent<Block>().isSpawnable = true;
  113. }
  114. break;
  115. }
  116. checkForward();
  117. }
  118. void chooseNextSection()
  119. {
  120. //First, we determine which sections are valid
  121. List<MapSection> validSections = new List<MapSection>();
  122. updateCriteria(); //We update the section selection criteria for the current gamestate
  123. foreach (MapSection section in sections)
  124. {
  125. if (checkSegments(section))
  126. {
  127. validSections.Add(section); //If a segment is a valid continuation of the current most-recent segment, add it to the list
  128. }
  129. }
  130. //Having generated our list, we choose a random segment from it
  131. /*foreach (MapSection section in validSections)
  132. {
  133. Debug.Log("Valid section: " + section.name);
  134. }*/
  135. Debug.Log("Choosing section");
  136. MapSection nextSection = validSections[(int)Random.Range(0.0f, (float)validSections.Count)];
  137. Debug.Log("Chosen section: " + nextSection.name);
  138. addSection(nextSection);
  139. }
  140. void addSection(MapSection section)
  141. {
  142. //Instantiate new section at x = endX
  143. Vector3 pos = new Vector3(endX, 0.0f, 0.0f);
  144. GameObject newSection = (GameObject)Instantiate(section.gameObject, pos, Quaternion.identity);
  145. //GameObject.Instantiate(section.gameObject, pos, Quaternion.identity);
  146. MapSection newSectionScript = newSection.GetComponent<MapSection>();
  147. newSectionScript.InitSection(activeSections.Count);
  148. newSection.name = newSectionScript.name;
  149. activeSections.Add(newSectionScript);
  150. lastSection = newSectionScript;
  151. endX += newSectionScript.length;
  152. totalSections++;
  153. }
  154. bool checkSegments(MapSection second)
  155. {
  156. return checkSegments(this.lastSection, second);
  157. }
  158. bool checkSegments(MapSection first, MapSection second)
  159. {
  160. int connections = 0;
  161. if (second.difficulty < diffMin || second.difficulty > diffMax)
  162. {
  163. return false;
  164. }
  165. if (second.widthIn < widthMin || second.widthIn > widthMax)
  166. {
  167. return false;
  168. }
  169. //Debug.Log("Checking sections: first = " + first.name + ", second = " + second.name);
  170. foreach (GameObject exit in first.exits)
  171. {
  172. foreach (GameObject entry in second.entrances)
  173. {
  174. /*Debug.Log("Checking connections: exit = " + exit.transform.localPosition.z + ", " + exit.transform.localPosition.x
  175. + ", entry = " + entry.transform.localPosition.z + ", " + entry.transform.localPosition.x);*/
  176. if (checkConnection(exit, entry))
  177. {
  178. connections++;
  179. }
  180. }
  181. }
  182. //Debug.Log("Connections = " + connections);
  183. if (connections >= minConns)
  184. {
  185. //Debug.Log("Valid section!");
  186. }
  187. else
  188. {
  189. //Debug.Log("Invalid section!");
  190. }
  191. return (connections >= minConns);
  192. }
  193. bool checkConnection(GameObject exit, GameObject entry)
  194. {
  195. /*Debug.Log("Checking connections: exit = " + exit.transform.localPosition.z + ", " + exit.transform.localPosition.x
  196. + ", entry = " + entry.transform.localPosition.z + ", " + entry.transform.localPosition.x);*/
  197. //If the squares being checked don't line up, the connection is invalid
  198. if (exit.transform.localPosition.z != entry.transform.localPosition.z)
  199. {
  200. //Debug.Log(exit.transform.localPosition.z + " != " + entry.transform.localPosition.z);
  201. return false;
  202. }
  203. //Debug.Log("Exit.is_Walkable = " + exit.GetComponent<Block>().is_Walkable + ", Entry.is_Walkable = " + entry.GetComponent<Block>().is_Walkable);
  204. //Since we currently don't let people jump over walls, if either block is a wall, the connection is invalid
  205. if (!(exit.GetComponent<Block>().is_Walkable) || !(entry.GetComponent<Block>().is_Walkable))
  206. {
  207. //Debug.Log("Invalid connection - not walkable");
  208. return false;
  209. }
  210. //Debug.Log("Exit.isWater = " + exit.GetComponent<Block>().isWater + ", Entry.isWater = " + entry.GetComponent<Block>().isWater);
  211. //If both components are water, moving through this connection is technically possible, but we don't count it as valid
  212. if ((exit.GetComponent<Block>().isWater) && (entry.GetComponent<Block>().isWater))
  213. {
  214. //Debug.Log("Invalid connection - both water");
  215. return false;
  216. }
  217. //Debug.Log("Valid connection!");
  218. //If we've passed all these tests, the connection is valid!
  219. return true;
  220. }
  221. //Check whether it's time to extend the track forward
  222. void checkForward()
  223. {
  224. //We check if the end of the last section of track is in sight
  225. Vector3 trackEnd = new Vector3(endX, 0.0f); //Get the middle of the end of the last track section
  226. //If it is, then we add a new section
  227. if (checkView(trackEnd))
  228. {
  229. chooseNextSection();
  230. checkForward();
  231. }
  232. }
  233. //Check whether it's time to delete the oldest section of active track
  234. void checkBack()
  235. {
  236. //We check if the end of the first section of track is still in sight
  237. Vector3 firstSectionEnd = new Vector3(startX + activeSections[0].length, 0.0f); //Get the middle of the end of the first track section
  238. //If it's not, then we remove it
  239. if (!(checkView(firstSectionEnd)))
  240. {
  241. startX += activeSections[0].length;
  242. activeSections[0].destroySection();
  243. activeSections.RemoveAt(0);
  244. }
  245. }
  246. //Check whether a point is in sight or not
  247. bool checkView(Vector3 point)
  248. {
  249. Vector3 screenPoint = Camera.main.WorldToViewportPoint(point); //Map it into viewport space
  250. //The camera's field of view is represented by 0 > (x, y) < 1, with z being the distance from the camera
  251. return (screenPoint.z > 0 && screenPoint.x > 0 && screenPoint.x < 1 && screenPoint.y > 0 && screenPoint.y < 1);
  252. }
  253. //Checks in both directions for sections needing to be added or removed
  254. public void checkTrack()
  255. {
  256. checkForward();
  257. checkBack();
  258. }
  259. //Updates minimum and maximum difficulty, width, etc, based on current gamestate
  260. public void updateCriteria()
  261. {
  262. //By default, we can add a section 1 tile wider or narrower on either side than the last section
  263. widthMin = lastSection.widthOut - 2;
  264. widthMax = lastSection.widthOut + 2;
  265. /* Calculate min & max difficulties & width modifications
  266. * We recalculate from scratch each time (that is,
  267. * each time a section is added) so as to avoid having
  268. * to track which one-off increase has been applied
  269. * and which hasn't
  270. */
  271. //Start with base values
  272. diffMin = diffMinStart;
  273. diffMax = diffMaxStart;
  274. //As the number of players shrinks, we ramp up the difficulty and contract the track
  275. if (clients.ConnectedClients.Count <= (float)(0.5f * initialPlayerCount))
  276. {
  277. diffMin++;
  278. diffMax++;
  279. widthMin -= 2;
  280. widthMax -= 2;
  281. }
  282. if (clients.ConnectedClients.Count <= (float)(0.25f * initialPlayerCount))
  283. {
  284. diffMin++;
  285. diffMax += 2;
  286. widthMin -= 2;
  287. widthMax -= 2;
  288. }
  289. //Ramp up the difficulty as the game goes on
  290. diffMin += (totalSections - 2) / 2;
  291. diffMax += totalSections / 2;
  292. //Once the difficulty has ramped up, we cause the track to steadily narrow
  293. //It can no longer widen, only remain constant or shrink
  294. if (diffMin > 2)
  295. {
  296. widthMax--;
  297. }
  298. //Apply caps
  299. if (diffMin > diffMinMax)
  300. {
  301. diffMin = diffMinMax;
  302. }
  303. if (widthMin < minPossibleWidth)
  304. {
  305. widthMin = minPossibleWidth;
  306. }
  307. }
  308. // Update is called once per frame
  309. void Update()
  310. {
  311. //checkTrack();
  312. }
  313. }