From c33bb139b1046c32b01d4650bb9f7aa328da8e0e Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Fri, 25 Mar 2016 11:31:47 +0000 Subject: [PATCH] Changes to support Fungus Script execution --- Assets/Fungus/Flowchart/Scripts/Block.cs | 41 +++--- .../Fungus/Flowchart/Scripts/Commands/Call.cs | 4 +- Assets/Fungus/Flowchart/Scripts/Flowchart.cs | 131 +++++++++++------- .../Fungus/Narrative/Scripts/Commands/Say.cs | 2 +- Assets/Fungus/Narrative/Scripts/MenuDialog.cs | 10 +- Assets/Fungus/Narrative/Scripts/SayDialog.cs | 10 +- Assets/Fungus/UI/Scripts/Writer.cs | 8 +- 7 files changed, 124 insertions(+), 82 deletions(-) diff --git a/Assets/Fungus/Flowchart/Scripts/Block.cs b/Assets/Fungus/Flowchart/Scripts/Block.cs index 8b3c0685..2c7760c0 100644 --- a/Assets/Fungus/Flowchart/Scripts/Block.cs +++ b/Assets/Fungus/Flowchart/Scripts/Block.cs @@ -142,26 +142,25 @@ namespace Fungus return executionCount; } - public virtual bool Execute(Action onComplete = null) + /// + /// Execute the Block in a coroutine. Only one running instance of each Block is permitted. + /// + /// Index of command to start execution at + /// Delegate function to call when execution completes + public virtual IEnumerator Execute(int commandIndex = 0, Action onComplete = null) { - if (executionState != ExecutionState.Idle) - { - return false; - } - - if (!executionInfoSet) - { - SetExecutionInfo(); - } + if (executionState != ExecutionState.Idle) + { + yield break; + } - executionCount++; - StartCoroutine(ExecuteBlock(onComplete)); + if (!executionInfoSet) + { + SetExecutionInfo(); + } - return true; - } + executionCount++; - protected virtual IEnumerator ExecuteBlock(Action onComplete = null) - { Flowchart flowchart = GetFlowchart(); executionState = ExecutionState.Executing; @@ -175,6 +174,8 @@ namespace Fungus } #endif + jumpToCommandIndex = commandIndex; + int i = 0; while (true) { @@ -248,10 +249,10 @@ namespace Fungus executionState = ExecutionState.Idle; activeCommand = null; - if (onComplete != null) - { - onComplete(); - } + if (onComplete != null) + { + onComplete(); + } } public virtual void Stop() diff --git a/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs b/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs index d766d3a3..b14f291f 100644 --- a/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs +++ b/Assets/Fungus/Flowchart/Scripts/Commands/Call.cs @@ -64,12 +64,12 @@ namespace Fungus flowchart.selectedBlock = targetBlock; } - targetBlock.Execute(onComplete); + StartCoroutine(targetBlock.Execute(0, onComplete)); } else { // Execute block in another Flowchart - targetFlowchart.ExecuteBlock(targetBlock, onComplete); + targetFlowchart.ExecuteBlock(targetBlock, 0, onComplete); } } diff --git a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs index c7e0893a..faa7003f 100644 --- a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs +++ b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs @@ -371,61 +371,50 @@ namespace Fungus } /** - * Start running another Flowchart by executing a specific child block. - * The block must be in an idle state to be executed. + * Execute a child block in the Flowchart. * You can use this method in a UI event. e.g. to handle a button click. + * Returns true if the Block started execution. */ - public virtual void ExecuteBlock(string blockName) - { - Block [] blocks = GetComponentsInChildren(); - foreach (Block block in blocks) - { - if (block.blockName == blockName) - { - ExecuteBlock(block); - } - } - } - - /** - * Sends a message to this Flowchart only. - * Any block with a matching MessageReceived event handler will start executing. - */ - public virtual void SendFungusMessage(string messageName) - { - MessageReceived[] eventHandlers = GetComponentsInChildren(); - foreach (MessageReceived eventHandler in eventHandlers) - { - eventHandler.OnSendFungusMessage(messageName); - } - } - - /** - * Sends a message to all Flowchart objects in the current scene. - * Any block with a matching MessageReceived event handler will start executing. - */ - public static void BroadcastFungusMessage(string messageName) + public virtual bool ExecuteBlock(string blockName) { - MessageReceived[] eventHandlers = GameObject.FindObjectsOfType(); - foreach (MessageReceived eventHandler in eventHandlers) - { - eventHandler.OnSendFungusMessage(messageName); - } + Block block = null; + foreach (Block b in GetComponentsInChildren()) + { + if (b.blockName == blockName) + { + block = b; + break; + } + } + + if (block == null) + { + Debug.LogError("Block " + blockName + "does not exist"); + return false; + } + + return ExecuteBlock(block); } /** - * Start executing a specific child block in the flowchart. + * Execute a child block in the flowchart. * The block must be in an idle state to be executed. + * This version provides extra options to control how the block is executed. * Returns true if the Block started execution. */ - public virtual bool ExecuteBlock(Block block, Action onComplete = null) + public virtual bool ExecuteBlock(Block block, int commandIndex = 0, Action onComplete = null) { - // Block must be a component of the Flowchart game object - if (block == null || - block.gameObject != gameObject) - { - return false; - } + if (block == null) + { + Debug.LogError("Block must not be null"); + return false; + } + + if (block.gameObject != gameObject) + { + Debug.LogError("Block must belong to the same gameobject as this Flowchart"); + return false; + } // Can't restart a running block, have to wait until it's idle again if (block.IsExecuting()) @@ -433,10 +422,10 @@ namespace Fungus return false; } - // Execute the first command in the command list - block.Execute(onComplete); + // Start executing the Block as a new coroutine + StartCoroutine(block.Execute(commandIndex, onComplete)); - return true; + return true; } /** @@ -454,6 +443,32 @@ namespace Fungus } } + /** + * Sends a message to this Flowchart only. + * Any block with a matching MessageReceived event handler will start executing. + */ + public virtual void SendFungusMessage(string messageName) + { + MessageReceived[] eventHandlers = GetComponentsInChildren(); + foreach (MessageReceived eventHandler in eventHandlers) + { + eventHandler.OnSendFungusMessage(messageName); + } + } + + /** + * Sends a message to all Flowchart objects in the current scene. + * Any block with a matching MessageReceived event handler will start executing. + */ + public static void BroadcastFungusMessage(string messageName) + { + MessageReceived[] eventHandlers = GameObject.FindObjectsOfType(); + foreach (MessageReceived eventHandler in eventHandlers) + { + eventHandler.OnSendFungusMessage(messageName); + } + } + /** * Returns a new variable key that is guaranteed not to clash with any existing variable in the list. */ @@ -590,6 +605,26 @@ namespace Fungus } } + /** + * Returns the variable with the specified key, or null if the key is not found. + * You will need to cast the returned variable to the correct sub-type. + * You can then access the variable's value using the Value property. e.g. + * BooleanVariable boolVar = flowchart.GetVariable("MyBool") as BooleanVariable; + * boolVar.Value = false; + */ + public Variable GetVariable(string key) + { + foreach (Variable variable in variables) + { + if (variable != null && variable.key == key) + { + return variable; + } + } + + return null; + } + /** * Returns the variable with the specified key, or null if the key is not found. * You can then access the variable's value using the Value property. e.g. diff --git a/Assets/Fungus/Narrative/Scripts/Commands/Say.cs b/Assets/Fungus/Narrative/Scripts/Commands/Say.cs index b0fde7f8..34f35f61 100644 --- a/Assets/Fungus/Narrative/Scripts/Commands/Say.cs +++ b/Assets/Fungus/Narrative/Scripts/Commands/Say.cs @@ -99,7 +99,7 @@ namespace Fungus string subbedText = flowchart.SubstituteVariables(displayText); - sayDialog.Say(subbedText, !extendPrevious, waitForClick, fadeWhenDone, voiceOverClip, stopVoiceover, delegate { + sayDialog.Say(subbedText, !extendPrevious, waitForClick, fadeWhenDone, stopVoiceover, voiceOverClip, delegate { Continue(); }); } diff --git a/Assets/Fungus/Narrative/Scripts/MenuDialog.cs b/Assets/Fungus/Narrative/Scripts/MenuDialog.cs index 7eeb55bd..941a93d0 100644 --- a/Assets/Fungus/Narrative/Scripts/MenuDialog.cs +++ b/Assets/Fungus/Narrative/Scripts/MenuDialog.cs @@ -13,8 +13,11 @@ namespace Fungus // Currently active Menu Dialog used to display Menu options public static MenuDialog activeMenuDialog; - protected Button[] cachedButtons; - protected Slider cachedSlider; + [NonSerialized] + public Button[] cachedButtons; + + [NonSerialized] + public Slider cachedSlider; public static MenuDialog GetMenuDialog() { @@ -139,7 +142,7 @@ namespace Fungus return addedOption; } - protected virtual void HideSayDialog() + public virtual void HideSayDialog() { SayDialog sayDialog = SayDialog.GetSayDialog(); if (sayDialog != null) @@ -150,7 +153,6 @@ namespace Fungus public virtual void ShowTimer(float duration, Block targetBlock) { - if (cachedSlider != null) { cachedSlider.gameObject.SetActive(true); diff --git a/Assets/Fungus/Narrative/Scripts/SayDialog.cs b/Assets/Fungus/Narrative/Scripts/SayDialog.cs index 3f3d8c90..ff4e0b1b 100644 --- a/Assets/Fungus/Narrative/Scripts/SayDialog.cs +++ b/Assets/Fungus/Narrative/Scripts/SayDialog.cs @@ -126,12 +126,12 @@ namespace Fungus } } - public virtual void Say(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, AudioClip voiceOverClip, bool stopVoiceover, Action onComplete) + public virtual void Say(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, bool stopVoiceover, AudioClip voiceOverClip, Action onComplete) { - StartCoroutine(SayInternal(text, clearPrevious, waitForInput, fadeWhenDone, voiceOverClip, stopVoiceover, onComplete)); + StartCoroutine(SayInternal(text, clearPrevious, waitForInput, fadeWhenDone, stopVoiceover, voiceOverClip, onComplete)); } - protected virtual IEnumerator SayInternal(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, AudioClip voiceOverClip, bool stopVoiceover, Action onComplete) + public virtual IEnumerator SayInternal(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, bool stopVoiceover, AudioClip voiceOverClip, Action onComplete) { Writer writer = GetWriter(); @@ -144,6 +144,8 @@ namespace Fungus } } + gameObject.SetActive(true); + this.fadeWhenDone = fadeWhenDone; // Voice over clip takes precedence over a character sound effect if provided @@ -158,8 +160,8 @@ namespace Fungus { soundEffectClip = speakingCharacter.soundEffect; } - writer.Write(text, clearPrevious, waitForInput, stopVoiceover, soundEffectClip, onComplete); + yield return writer.Write(text, clearPrevious, waitForInput, stopVoiceover, soundEffectClip, onComplete); } protected virtual void LateUpdate() diff --git a/Assets/Fungus/UI/Scripts/Writer.cs b/Assets/Fungus/UI/Scripts/Writer.cs index 7289f8f6..df6ad23c 100644 --- a/Assets/Fungus/UI/Scripts/Writer.cs +++ b/Assets/Fungus/UI/Scripts/Writer.cs @@ -317,7 +317,7 @@ namespace Fungus } } - public virtual void Write(string content, bool clear, bool waitForInput, bool stopAudio, AudioClip audioClip, Action onComplete) + public virtual IEnumerator Write(string content, bool clear, bool waitForInput, bool stopAudio, AudioClip audioClip, Action onComplete) { if (clear) { @@ -326,7 +326,7 @@ namespace Fungus if (!HasTextObject()) { - return; + yield break; } // If this clip is null then WriterAudio will play the default sound effect (if any) @@ -341,7 +341,9 @@ namespace Fungus TextTagParser tagParser = new TextTagParser(); List tokens = tagParser.Tokenize(tokenText); - StartCoroutine(ProcessTokens(tokens, stopAudio, onComplete)); + gameObject.SetActive(true); + + yield return StartCoroutine(ProcessTokens(tokens, stopAudio, onComplete)); } virtual protected bool CheckParamCount(List paramList, int count)