Advertisement
SiobhanBD

Untitled

Aug 8th, 2024
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.19 KB | None | 0 0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Assets.Scripts.LevelBehavior;
  5. using Assets.Scripts.LevelVisuals;
  6. using Assets.Scripts.SHPlayer;
  7. using UnityEngine;
  8. using FMODUnity; // Add FMOD
  9.  
  10. namespace Assets.Scripts.Solver
  11. {
  12. public enum SolverState
  13. {
  14. WaitingForThreats, Solving, WaitingToMove, Moving, Solved
  15. }
  16.  
  17. public enum MovementOption
  18. {
  19. None, Clockwise, CounterClockwise
  20. }
  21.  
  22. public class HexagonSolver : MonoBehaviour
  23. {
  24. public static HexagonSolver Instance;
  25.  
  26. private const float IgnoreThreatsPastRadius = 60f;
  27. public List<SHLine> NextTriggers;
  28. public List<SHLine> ThreatsAlignedWithPlayer;
  29. public SHLine ClosestCwTrigger;
  30. public SHLine ClosestCcwTrigger;
  31. public SHLine TriggerAlignedWithPlayer;
  32. public float ClosestCwTriggerAngle;
  33. public float ClosestCcwTriggerAngle;
  34. public bool CanMoveCw;
  35. public bool CanMoveCcw;
  36.  
  37. public bool NeedToMakeDecision;
  38.  
  39. public SolverState State = SolverState.WaitingForThreats;
  40. public MovementOption BestMovementOption = MovementOption.None;
  41. public List<MovementOption> ValidMovementOptions = new List<MovementOption>();
  42.  
  43. public static Action<PatternInstance> OnNextTriggersChanged;
  44.  
  45. //SD EDIT START
  46. //Trigger counter methods established
  47. private int triggerChangeCount = 0;
  48. private int totalTriggerChanges = 0;
  49.  
  50. // FMOD event instances methods establised
  51. private FMOD.Studio.EventInstance vert1Instance;
  52. private FMOD.Studio.EventInstance vert2Instance;
  53. private FMOD.Studio.EventInstance vert3Instance;
  54. private FMOD.Studio.EventInstance vert4Instance;
  55.  
  56. private void Awake()
  57. {
  58. Instance = this;
  59. //Time.timeScale = 0.5f; // Slow down the simulation for testing
  60.  
  61. //Establish FMOD events and event paths
  62. vert1Instance = RuntimeManager.CreateInstance("event:/vert1");
  63. vert2Instance = RuntimeManager.CreateInstance("event:/vert2");
  64. vert3Instance = RuntimeManager.CreateInstance("event:/vert3");
  65. vert4Instance = RuntimeManager.CreateInstance("event:/vert4");
  66. }
  67. //SD EDIT END
  68. private void Update()
  69. {
  70. UpdateMovementOptions();
  71. }
  72.  
  73. private void OnGUI()
  74. {
  75. // Optional: Implement GUI updates if needed
  76. }
  77.  
  78. private bool AreTriggerListsEqual(List<SHLine> l1, List<SHLine> l2)
  79. {
  80. if (l1.Count != l2.Count) return false;
  81.  
  82. for (int i = 0; i < l1.Count; i++)
  83. {
  84. if (l1[i] != l2[i])
  85. {
  86. return false;
  87. }
  88. }
  89.  
  90. return true;
  91. }
  92.  
  93. private void UpdateMovementOptions()
  94. {
  95. if (ThreatManager.Instance.PatternsOnScreen.Count == 0)
  96. {
  97. BestMovementOption = MovementOption.None;
  98. return; // No threat; nothing to solve!
  99. }
  100.  
  101. PatternInstance pi = ThreatManager.Instance.PatternsOnScreen[0];
  102.  
  103. if (pi.ClosestThreat.Radius > IgnoreThreatsPastRadius)
  104. {
  105. BestMovementOption = MovementOption.None;
  106. return; // Too far away to see right now.
  107. }
  108.  
  109. // TODO: Don't calculate this every frame; it is wasteful.
  110. // Work out which safe lane(s) are next.
  111. List<SHLine> nextTriggers = pi.NextTriggers();
  112.  
  113. bool triggersChanged = false;
  114.  
  115. if (!AreTriggerListsEqual(NextTriggers, nextTriggers))
  116. {
  117. NeedToMakeDecision = true;
  118. NextTriggers = nextTriggers;
  119.  
  120. triggersChanged = true;
  121. }
  122.  
  123. if (!NeedToMakeDecision) // Already made a decision about what to do, just need to carry out that decision.
  124. return;
  125.  
  126. UpdateClosestTriggers();
  127. UpdateTriggerAlignedWithPlayer();
  128.  
  129. if (TriggerAlignedWithPlayer != null)
  130. {
  131. BestMovementOption = MovementOption.None;
  132.  
  133. if (triggersChanged)
  134. {
  135. Debug.Log("Triggers changed.");
  136. OnNextTriggersChanged?.Invoke(pi);
  137.  
  138. // //SD EDIT START
  139. triggerChangeCount++;
  140. totalTriggerChanges++;
  141.  
  142. // RATHER THAN TRIGGER WITH OBSTACLES AVOIDED, THIS LOOPS UNTIL CERTAIN NUMBER OF OBSTACLES ARE HIT (ADDED CROSSFADE)
  143. if (totalTriggerChanges == 1)
  144. {
  145. StartCoroutine(CrossfadeToNewEvent(null, vert1Instance)); // vert1Instance.start(); replaced for crossfade on first audio instance of each run
  146. }
  147. else if (totalTriggerChanges == 1)
  148. {
  149. StartCoroutine(CrossfadeToNewEvent(null, vert1Instance));
  150. }
  151. else if (totalTriggerChanges == 16)
  152. {
  153. StartCoroutine(CrossfadeToNewEvent(vert1Instance, vert2Instance));
  154. }
  155. else if (totalTriggerChanges == 32)
  156. {
  157. StartCoroutine(CrossfadeToNewEvent(vert2Instance, vert3Instance));
  158. }
  159. else if (totalTriggerChanges == 64)
  160. {
  161. StartCoroutine(CrossfadeToNewEvent(vert3Instance, vert4Instance));
  162. }
  163. //SD EDIT END
  164. return; // The player is already where they need to be, stop checking anything else.
  165. }
  166.  
  167. }
  168. else
  169. {
  170. UpdateThreatsAlignedWithPlayer();
  171. UpdateCanMove();
  172. }
  173.  
  174. if (ClosestCcwTriggerAngle <= ClosestCwTriggerAngle && CanMoveCcw) // A CCW rotation would be faster, and we can do it.
  175. {
  176. BestMovementOption = MovementOption.CounterClockwise;
  177. }
  178. else if (ClosestCwTriggerAngle <= ClosestCcwTriggerAngle && CanMoveCw)
  179. {
  180. BestMovementOption = MovementOption.Clockwise;
  181. }
  182.  
  183. if (triggersChanged)
  184. {
  185. Debug.Log("Triggers changed.");
  186. OnNextTriggersChanged?.Invoke(pi);
  187. }
  188. }
  189.  
  190.  
  191. //return;
  192. //SD EDIT START
  193.  
  194. // GetAllMovementOptions IEnumerable method to prevent errors in clashing return/yield return states.
  195. //private IEnumerable<MovementOption> GetAllMovementOptions()
  196. //{
  197. // yield return MovementOption.Clockwise;
  198. // yield return MovementOption.CounterClockwise;
  199. // yield return MovementOption.None;
  200. //}
  201.  
  202. //ADDING CROSSFADE TO FMOD EVENTS FOR TRANSITIONING BETWEEN LAYERS
  203.  
  204. private FMOD.Studio.PLAYBACK_STATE oldEventState;
  205.  
  206. private IEnumerator CrossfadeToNewEvent(FMOD.Studio.EventInstance? oldEvent, FMOD.Studio.EventInstance newEvent)
  207. {
  208. float startTime = Time.time;
  209. float crossfadeDuration = 1.0f;
  210. newEvent.start();
  211.  
  212. if (oldEvent.HasValue)
  213. {
  214. oldEvent.Value.getPlaybackState(out oldEventState);
  215.  
  216. while (Time.time - startTime < crossfadeDuration)
  217. {
  218. float t = (Time.time - startTime) / crossfadeDuration;
  219. oldEvent.Value.setVolume(1 - t);
  220. newEvent.setVolume(t);
  221. yield return null;
  222. }
  223.  
  224. // Wait for the old event to finish playing before continuing
  225. while (oldEventState == FMOD.Studio.PLAYBACK_STATE.PLAYING)
  226. {
  227. oldEvent.Value.getPlaybackState(out oldEventState);
  228. yield return null;
  229. }
  230. }
  231. else
  232. {
  233. // If there's no old event, just fade in the new event
  234. while (Time.time - startTime < crossfadeDuration)
  235. {
  236. float t = (Time.time - startTime) / crossfadeDuration;
  237. newEvent.setVolume(t);
  238. yield return null;
  239. }
  240. }
  241.  
  242. newEvent.setVolume(1);
  243. }
  244. // SD EDIT END
  245.  
  246.  
  247. /// <summary>
  248. /// Work out which of the next trigger(s) are the closest to the player.
  249. /// </summary>
  250. private void UpdateClosestTriggers()
  251. {
  252. float smallestCwAngle = 360;
  253. float smallestCcwAngle = 360;
  254.  
  255. foreach (SHLine trigger in NextTriggers)
  256. {
  257. if (trigger.AngleIsWithin(PlayerBehavior.Instance.CurrentAngle))
  258. {
  259. smallestCwAngle = 0;
  260. smallestCcwAngle = 0;
  261.  
  262. ClosestCwTrigger = trigger;
  263. ClosestCcwTrigger = trigger;
  264. break;
  265. }
  266.  
  267. float cwDist = trigger.ClockwiseDistance(PlayerBehavior.Instance.CurrentAngle);
  268. if (cwDist < smallestCwAngle)
  269. {
  270. smallestCwAngle = cwDist;
  271. ClosestCwTrigger = trigger;
  272. }
  273.  
  274. float ccwDist = trigger.CounterclockwiseDistance(PlayerBehavior.Instance.CurrentAngle);
  275. if (ccwDist < smallestCcwAngle)
  276. {
  277. smallestCcwAngle = ccwDist;
  278. ClosestCcwTrigger = trigger;
  279. }
  280. }
  281.  
  282. if (ThreatManager.AreTriggersVisible)
  283. {
  284. foreach (SHLine trigger in NextTriggers)
  285. {
  286. if (trigger == ClosestCcwTrigger || trigger == ClosestCwTrigger)
  287. {
  288. trigger._meshRenderer.material = trigger.EditMaterial;
  289. }
  290. else
  291. {
  292. trigger._meshRenderer.material = trigger.TriggerPreviewMaterial;
  293. }
  294. }
  295. }
  296.  
  297. ClosestCwTriggerAngle = smallestCwAngle;
  298. ClosestCcwTriggerAngle = smallestCcwAngle;
  299. }
  300.  
  301. /// <summary>
  302. /// Work out if one the triggers is aligned with the player and update "TriggerAlignedWithPlayer"
  303. /// </summary>
  304. private void UpdateTriggerAlignedWithPlayer()
  305. {
  306. if (ClosestCwTrigger != ClosestCcwTrigger)
  307. {
  308. TriggerAlignedWithPlayer = null; // The two triggers aren't the same.
  309. return;
  310. }
  311.  
  312. if (ClosestCwTrigger.AngleIsWithin(PlayerBehavior.Instance.CurrentAngle))
  313. {
  314. TriggerAlignedWithPlayer = ClosestCwTrigger;
  315. }
  316. else
  317. {
  318. TriggerAlignedWithPlayer = null;
  319. }
  320. }
  321.  
  322. /// <summary>
  323. /// Any threats in line with the player could prevent the player from moving particular directions.
  324. /// </summary>
  325. private void UpdateThreatsAlignedWithPlayer()
  326. {
  327. ThreatsAlignedWithPlayer = new List<SHLine>();
  328.  
  329. foreach (SHLine threat in ThreatManager.Instance.PatternsOnScreen[0].Threats)
  330. {
  331. if (threat.IsTriggerOnly)
  332. continue;
  333.  
  334. if (threat.Radius > GameParameters.PlayerRadius)
  335. break; // Because of the sorted list, the next threats aren't possibly aligned with the player.
  336.  
  337. if (threat.RadiusOuter < GameParameters.PlayerRadius)
  338. continue;
  339.  
  340. if (threat.Radius <= GameParameters.PlayerRadius && threat.RadiusOuter >= GameParameters.PlayerRadius)
  341. ThreatsAlignedWithPlayer.Add(threat);
  342. }
  343. }
  344.  
  345. private void UpdateCanMove()
  346. {
  347. if (ThreatsAlignedWithPlayer.Count == 0)
  348. {
  349. CanMoveCw = true;
  350. CanMoveCcw = true;
  351. return;
  352. }
  353.  
  354. bool cwBlocked = false;
  355. bool ccwBlocked = false;
  356.  
  357. foreach (SHLine threat in ThreatsAlignedWithPlayer)
  358. {
  359. if (threat.ClockwiseDistance(PlayerBehavior.Instance.CurrentAngle) < ClosestCwTriggerAngle)
  360. cwBlocked = true;
  361. if (threat.CounterclockwiseDistance(PlayerBehavior.Instance.CurrentAngle) < ClosestCcwTriggerAngle)
  362. ccwBlocked = true;
  363. }
  364.  
  365. CanMoveCcw = !ccwBlocked;
  366. CanMoveCw = !cwBlocked;
  367. }
  368.  
  369. /// <summary>
  370. /// If this is true, then the player needs to be moving in some direction to avoid catastrophe!
  371. /// If it's false, then simply take the shortest path to the trigger.
  372. /// </summary>
  373. /// <param name="trigger"></param>
  374. /// <returns></returns>
  375. private bool AreThreatsBeforeTrigger(SHLine trigger)
  376. {
  377. float triggerRadius = trigger.Radius;
  378.  
  379. if (ThreatManager.Instance.PatternsOnScreen.Count == 0)
  380. return false;
  381.  
  382. PatternInstance currentPattern = ThreatManager.Instance.PatternsOnScreen[0];
  383. foreach (SHLine threat in currentPattern.Threats)
  384. {
  385. if (threat.Radius < GameParameters.PlayerRadius)
  386. continue; // Threat is past player, don't consider it.
  387.  
  388. if (threat.Radius < trigger.Radius)
  389. {
  390. return true;
  391. }
  392.  
  393. return false; // Because of the sorting, we can exit the loop earlier
  394. }
  395.  
  396. return false;
  397. }
  398. //SD EDIT BEGIN
  399. //RESET MUSIC ON DEATH
  400. public void ResetTriggerCounters()
  401. {
  402. triggerChangeCount = 0;
  403. totalTriggerChanges = 0;
  404. // Stop all FMOD events
  405. vert1Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
  406. vert2Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
  407. vert3Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
  408. vert4Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
  409.  
  410. // Reset volumes to initial state
  411. vert1Instance.setVolume(1);
  412. vert2Instance.setVolume(0);
  413. vert3Instance.setVolume(0);
  414. vert4Instance.setVolume(0);
  415.  
  416. // Restart the first event
  417. // vert1Instance.start();
  418.  
  419. Debug.Log("HexagonSolver: All trigger counters and audio events reset.");
  420.  
  421. }
  422.  
  423. //CLEANING UP FMOD LOADING INSTANCES; OTHER VERSION GOT LAGGY WITH MORE EVENTS.
  424. private void OnDestroy()
  425. {
  426. vert1Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
  427. vert2Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
  428. vert3Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
  429. vert4Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
  430.  
  431. vert1Instance.release();
  432. vert2Instance.release();
  433. vert3Instance.release();
  434. vert4Instance.release();
  435. }
  436. //SD EDIT END
  437. }
  438. }
  439.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement