using UnityEngine; using System.Collections.Generic; using TriInspector; namespace R0bbie.Timeline { /// /// Toggle between step option based on what external TimelineTrigger is received /// [AddComponentMenu("Timeline/StepSwitches/External Trigger (Step Switch)")] public class ExternalTriggerStepSwitch : StepSwitch { enum IfStepAlreadyPlayedAction { PlayAgain, DoNothing, SkipSwitch } [System.Serializable] struct TriggerSwitch { [SerializeField] public TimelineTrigger trigger; [SerializeField] public Step stepOption; [SerializeField] public IfStepAlreadyPlayedAction ifStepPrevPlayed; } [Title("Switch Options")] [SerializeField] List triggerSwitches = new List(); [Title("Adjust Trigger Behaviour")] [SerializeField, Tooltip("If a trigger attached to this switch was triggered previously, set the corresponding step option as active immediately, rather than waiting for a live trigger.")] private bool switchImmediatelyIfPrevTriggered; [ShowIf(nameof(switchImmediatelyIfPrevTriggered))] [SerializeField, Tooltip("If no triggers attached to this switch have been triggered previously, just skip this switch altogether.")] private bool skipImmediatelyIfNotPrevTriggered; /// /// Initialise the StepSwitch by Timeline /// public override void Init(StepTimeline _stepTimeline) { // Setup necessary refs such as parent timeline attachedStepTimeline = _stepTimeline; // Inactive by default activeMode = Mode.Inactive; // Init all step switch options foreach (TriggerSwitch triggerSwitch in triggerSwitches) { triggerSwitch.stepOption.Init(attachedStepTimeline, this); } init = true; } /// /// Initialise the StepSwitch by StepController /// public override void Init(StepController _controller) { // Setup necessary refs such as parent controller attachedController = _controller; // Inactive by default activeMode = Mode.Inactive; // Init all step switch options foreach (TriggerSwitch triggerSwitch in triggerSwitches) { triggerSwitch.stepOption.Init(attachedController, this); } init = true; } /// /// Play this StepSwitch, in turn playing whichever step its conditions point to /// public override void Play() { Debug.Log(name + " - Started"); isActive = true; activeMode = Mode.WaitingForEvent; // Option to play a child option immediately if the paired trigger was triggered previously if (switchImmediatelyIfPrevTriggered) { // Loop through all triggers and check if any were triggered before foreach (TriggerSwitch triggerSwitch in triggerSwitches) { // If so we've got our step option to play if (triggerSwitch.trigger.triggered) { activeStepOption = triggerSwitch.stepOption; break; } } // If no triggers were previously triggered, option to just skip over this switch altogether, and inform the timeline to play the next step if (skipImmediatelyIfNotPrevTriggered) { SkipSwitch(); return; } // If active step is now setup, play it! if (activeStepOption) { activeMode = Mode.PlayingChildStep; activeStepOption.Play(); } } // Listen for triggers.. foreach (TriggerSwitch triggerSwitch in triggerSwitches) { triggerSwitch.trigger.onTrigger.AddListener(TriggerContinue); } // If we've got here then we want to wait for an external trigger to send instruction to this switch.. } void SkipSwitch() { activeMode = Mode.Inactive; Continue(); } /// /// Trigger command received from external TimelineTrigger /// public override void TriggerContinue(TimelineTrigger _trigger) { if (!isActive || activeMode != Mode.WaitingForEvent) return; // Remove listeners foreach (TriggerSwitch triggerSwitch in triggerSwitches) { triggerSwitch.trigger.onTrigger.RemoveListener(TriggerContinue); } // Find this trigger in the list, and set the corresponding child step as active int switchIndexInList = triggerSwitches.FindIndex(x => x.trigger == _trigger); // If this trigger wasn't found in the list, we can't play any child step. Don't do anything if (switchIndexInList == -1) { Debug.LogWarning("ExternalTriggerStepSwitch received a command from a trigger not in the switch list, can't do anything."); return; } // With the trigger found in the list, set active step option to corresponding step activeStepOption = triggerSwitches[switchIndexInList].stepOption; // Check if step was previously played, and if we want to execute any custom action here if so if (activeStepOption.wasCompleted) { if (triggerSwitches[switchIndexInList].ifStepPrevPlayed == IfStepAlreadyPlayedAction.DoNothing) { activeStepOption = null; return; } else if (triggerSwitches[switchIndexInList].ifStepPrevPlayed == IfStepAlreadyPlayedAction.SkipSwitch) { SkipSwitch(); return; } } // Target step option to play is now definitely set.. // Play the selected option, unless it's null (in which case just play next step in timeline) if (activeStepOption) { activeMode = Mode.PlayingChildStep; activeStepOption.Play(); } else { Debug.Log("The option selected by the step switch was null, so just proceeding to next step in timeline."); SkipSwitch(); } } } }