Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using Assets.Scripts.LevelBehavior;
- using Assets.Scripts.LevelVisuals;
- using Assets.Scripts.SHPlayer;
- using UnityEngine;
- using FMODUnity; // Add FMOD
- namespace Assets.Scripts.Solver
- {
- public enum SolverState
- {
- WaitingForThreats, Solving, WaitingToMove, Moving, Solved
- }
- public enum MovementOption
- {
- None, Clockwise, CounterClockwise
- }
- public class HexagonSolver : MonoBehaviour
- {
- public static HexagonSolver Instance;
- private const float IgnoreThreatsPastRadius = 60f;
- public List<SHLine> NextTriggers;
- public List<SHLine> ThreatsAlignedWithPlayer;
- public SHLine ClosestCwTrigger;
- public SHLine ClosestCcwTrigger;
- public SHLine TriggerAlignedWithPlayer;
- public float ClosestCwTriggerAngle;
- public float ClosestCcwTriggerAngle;
- public bool CanMoveCw;
- public bool CanMoveCcw;
- public bool NeedToMakeDecision;
- public SolverState State = SolverState.WaitingForThreats;
- public MovementOption BestMovementOption = MovementOption.None;
- public List<MovementOption> ValidMovementOptions = new List<MovementOption>();
- public static Action<PatternInstance> OnNextTriggersChanged;
- //SD EDIT START
- //Trigger counter methods established
- private int triggerChangeCount = 0;
- private int totalTriggerChanges = 0;
- // FMOD event instances methods establised
- private FMOD.Studio.EventInstance vert1Instance;
- private FMOD.Studio.EventInstance vert2Instance;
- private FMOD.Studio.EventInstance vert3Instance;
- private FMOD.Studio.EventInstance vert4Instance;
- private void Awake()
- {
- Instance = this;
- //Time.timeScale = 0.5f; // Slow down the simulation for testing
- //Establish FMOD events and event paths
- vert1Instance = RuntimeManager.CreateInstance("event:/vert1");
- vert2Instance = RuntimeManager.CreateInstance("event:/vert2");
- vert3Instance = RuntimeManager.CreateInstance("event:/vert3");
- vert4Instance = RuntimeManager.CreateInstance("event:/vert4");
- }
- //SD EDIT END
- private void Update()
- {
- UpdateMovementOptions();
- }
- private void OnGUI()
- {
- // Optional: Implement GUI updates if needed
- }
- private bool AreTriggerListsEqual(List<SHLine> l1, List<SHLine> l2)
- {
- if (l1.Count != l2.Count) return false;
- for (int i = 0; i < l1.Count; i++)
- {
- if (l1[i] != l2[i])
- {
- return false;
- }
- }
- return true;
- }
- private void UpdateMovementOptions()
- {
- if (ThreatManager.Instance.PatternsOnScreen.Count == 0)
- {
- BestMovementOption = MovementOption.None;
- return; // No threat; nothing to solve!
- }
- PatternInstance pi = ThreatManager.Instance.PatternsOnScreen[0];
- if (pi.ClosestThreat.Radius > IgnoreThreatsPastRadius)
- {
- BestMovementOption = MovementOption.None;
- return; // Too far away to see right now.
- }
- // TODO: Don't calculate this every frame; it is wasteful.
- // Work out which safe lane(s) are next.
- List<SHLine> nextTriggers = pi.NextTriggers();
- bool triggersChanged = false;
- if (!AreTriggerListsEqual(NextTriggers, nextTriggers))
- {
- NeedToMakeDecision = true;
- NextTriggers = nextTriggers;
- triggersChanged = true;
- }
- if (!NeedToMakeDecision) // Already made a decision about what to do, just need to carry out that decision.
- return;
- UpdateClosestTriggers();
- UpdateTriggerAlignedWithPlayer();
- if (TriggerAlignedWithPlayer != null)
- {
- BestMovementOption = MovementOption.None;
- if (triggersChanged)
- {
- Debug.Log("Triggers changed.");
- OnNextTriggersChanged?.Invoke(pi);
- // //SD EDIT START
- triggerChangeCount++;
- totalTriggerChanges++;
- // RATHER THAN TRIGGER WITH OBSTACLES AVOIDED, THIS LOOPS UNTIL CERTAIN NUMBER OF OBSTACLES ARE HIT (ADDED CROSSFADE)
- if (totalTriggerChanges == 1)
- {
- StartCoroutine(CrossfadeToNewEvent(null, vert1Instance)); // vert1Instance.start(); replaced for crossfade on first audio instance of each run
- }
- else if (totalTriggerChanges == 1)
- {
- StartCoroutine(CrossfadeToNewEvent(null, vert1Instance));
- }
- else if (totalTriggerChanges == 16)
- {
- StartCoroutine(CrossfadeToNewEvent(vert1Instance, vert2Instance));
- }
- else if (totalTriggerChanges == 32)
- {
- StartCoroutine(CrossfadeToNewEvent(vert2Instance, vert3Instance));
- }
- else if (totalTriggerChanges == 64)
- {
- StartCoroutine(CrossfadeToNewEvent(vert3Instance, vert4Instance));
- }
- //SD EDIT END
- return; // The player is already where they need to be, stop checking anything else.
- }
- }
- else
- {
- UpdateThreatsAlignedWithPlayer();
- UpdateCanMove();
- }
- if (ClosestCcwTriggerAngle <= ClosestCwTriggerAngle && CanMoveCcw) // A CCW rotation would be faster, and we can do it.
- {
- BestMovementOption = MovementOption.CounterClockwise;
- }
- else if (ClosestCwTriggerAngle <= ClosestCcwTriggerAngle && CanMoveCw)
- {
- BestMovementOption = MovementOption.Clockwise;
- }
- if (triggersChanged)
- {
- Debug.Log("Triggers changed.");
- OnNextTriggersChanged?.Invoke(pi);
- }
- }
- //return;
- //SD EDIT START
- // GetAllMovementOptions IEnumerable method to prevent errors in clashing return/yield return states.
- //private IEnumerable<MovementOption> GetAllMovementOptions()
- //{
- // yield return MovementOption.Clockwise;
- // yield return MovementOption.CounterClockwise;
- // yield return MovementOption.None;
- //}
- //ADDING CROSSFADE TO FMOD EVENTS FOR TRANSITIONING BETWEEN LAYERS
- private FMOD.Studio.PLAYBACK_STATE oldEventState;
- private IEnumerator CrossfadeToNewEvent(FMOD.Studio.EventInstance? oldEvent, FMOD.Studio.EventInstance newEvent)
- {
- float startTime = Time.time;
- float crossfadeDuration = 1.0f;
- newEvent.start();
- if (oldEvent.HasValue)
- {
- oldEvent.Value.getPlaybackState(out oldEventState);
- while (Time.time - startTime < crossfadeDuration)
- {
- float t = (Time.time - startTime) / crossfadeDuration;
- oldEvent.Value.setVolume(1 - t);
- newEvent.setVolume(t);
- yield return null;
- }
- // Wait for the old event to finish playing before continuing
- while (oldEventState == FMOD.Studio.PLAYBACK_STATE.PLAYING)
- {
- oldEvent.Value.getPlaybackState(out oldEventState);
- yield return null;
- }
- }
- else
- {
- // If there's no old event, just fade in the new event
- while (Time.time - startTime < crossfadeDuration)
- {
- float t = (Time.time - startTime) / crossfadeDuration;
- newEvent.setVolume(t);
- yield return null;
- }
- }
- newEvent.setVolume(1);
- }
- // SD EDIT END
- /// <summary>
- /// Work out which of the next trigger(s) are the closest to the player.
- /// </summary>
- private void UpdateClosestTriggers()
- {
- float smallestCwAngle = 360;
- float smallestCcwAngle = 360;
- foreach (SHLine trigger in NextTriggers)
- {
- if (trigger.AngleIsWithin(PlayerBehavior.Instance.CurrentAngle))
- {
- smallestCwAngle = 0;
- smallestCcwAngle = 0;
- ClosestCwTrigger = trigger;
- ClosestCcwTrigger = trigger;
- break;
- }
- float cwDist = trigger.ClockwiseDistance(PlayerBehavior.Instance.CurrentAngle);
- if (cwDist < smallestCwAngle)
- {
- smallestCwAngle = cwDist;
- ClosestCwTrigger = trigger;
- }
- float ccwDist = trigger.CounterclockwiseDistance(PlayerBehavior.Instance.CurrentAngle);
- if (ccwDist < smallestCcwAngle)
- {
- smallestCcwAngle = ccwDist;
- ClosestCcwTrigger = trigger;
- }
- }
- if (ThreatManager.AreTriggersVisible)
- {
- foreach (SHLine trigger in NextTriggers)
- {
- if (trigger == ClosestCcwTrigger || trigger == ClosestCwTrigger)
- {
- trigger._meshRenderer.material = trigger.EditMaterial;
- }
- else
- {
- trigger._meshRenderer.material = trigger.TriggerPreviewMaterial;
- }
- }
- }
- ClosestCwTriggerAngle = smallestCwAngle;
- ClosestCcwTriggerAngle = smallestCcwAngle;
- }
- /// <summary>
- /// Work out if one the triggers is aligned with the player and update "TriggerAlignedWithPlayer"
- /// </summary>
- private void UpdateTriggerAlignedWithPlayer()
- {
- if (ClosestCwTrigger != ClosestCcwTrigger)
- {
- TriggerAlignedWithPlayer = null; // The two triggers aren't the same.
- return;
- }
- if (ClosestCwTrigger.AngleIsWithin(PlayerBehavior.Instance.CurrentAngle))
- {
- TriggerAlignedWithPlayer = ClosestCwTrigger;
- }
- else
- {
- TriggerAlignedWithPlayer = null;
- }
- }
- /// <summary>
- /// Any threats in line with the player could prevent the player from moving particular directions.
- /// </summary>
- private void UpdateThreatsAlignedWithPlayer()
- {
- ThreatsAlignedWithPlayer = new List<SHLine>();
- foreach (SHLine threat in ThreatManager.Instance.PatternsOnScreen[0].Threats)
- {
- if (threat.IsTriggerOnly)
- continue;
- if (threat.Radius > GameParameters.PlayerRadius)
- break; // Because of the sorted list, the next threats aren't possibly aligned with the player.
- if (threat.RadiusOuter < GameParameters.PlayerRadius)
- continue;
- if (threat.Radius <= GameParameters.PlayerRadius && threat.RadiusOuter >= GameParameters.PlayerRadius)
- ThreatsAlignedWithPlayer.Add(threat);
- }
- }
- private void UpdateCanMove()
- {
- if (ThreatsAlignedWithPlayer.Count == 0)
- {
- CanMoveCw = true;
- CanMoveCcw = true;
- return;
- }
- bool cwBlocked = false;
- bool ccwBlocked = false;
- foreach (SHLine threat in ThreatsAlignedWithPlayer)
- {
- if (threat.ClockwiseDistance(PlayerBehavior.Instance.CurrentAngle) < ClosestCwTriggerAngle)
- cwBlocked = true;
- if (threat.CounterclockwiseDistance(PlayerBehavior.Instance.CurrentAngle) < ClosestCcwTriggerAngle)
- ccwBlocked = true;
- }
- CanMoveCcw = !ccwBlocked;
- CanMoveCw = !cwBlocked;
- }
- /// <summary>
- /// If this is true, then the player needs to be moving in some direction to avoid catastrophe!
- /// If it's false, then simply take the shortest path to the trigger.
- /// </summary>
- /// <param name="trigger"></param>
- /// <returns></returns>
- private bool AreThreatsBeforeTrigger(SHLine trigger)
- {
- float triggerRadius = trigger.Radius;
- if (ThreatManager.Instance.PatternsOnScreen.Count == 0)
- return false;
- PatternInstance currentPattern = ThreatManager.Instance.PatternsOnScreen[0];
- foreach (SHLine threat in currentPattern.Threats)
- {
- if (threat.Radius < GameParameters.PlayerRadius)
- continue; // Threat is past player, don't consider it.
- if (threat.Radius < trigger.Radius)
- {
- return true;
- }
- return false; // Because of the sorting, we can exit the loop earlier
- }
- return false;
- }
- //SD EDIT BEGIN
- //RESET MUSIC ON DEATH
- public void ResetTriggerCounters()
- {
- triggerChangeCount = 0;
- totalTriggerChanges = 0;
- // Stop all FMOD events
- vert1Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
- vert2Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
- vert3Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
- vert4Instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
- // Reset volumes to initial state
- vert1Instance.setVolume(1);
- vert2Instance.setVolume(0);
- vert3Instance.setVolume(0);
- vert4Instance.setVolume(0);
- // Restart the first event
- // vert1Instance.start();
- Debug.Log("HexagonSolver: All trigger counters and audio events reset.");
- }
- //CLEANING UP FMOD LOADING INSTANCES; OTHER VERSION GOT LAGGY WITH MORE EVENTS.
- private void OnDestroy()
- {
- vert1Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
- vert2Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
- vert3Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
- vert4Instance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
- vert1Instance.release();
- vert2Instance.release();
- vert3Instance.release();
- vert4Instance.release();
- }
- //SD EDIT END
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement