My game needs to be able to start a coroutine in a graph and yield until that coroutine is complete. None of the EventBus or CustomEvent functions which are used to start the flow return a coroutine, so this doesn’t seem possible.
Am I missing something? Is there any way to tell if a flow has finished executing?
Edit: From what I can see, my other optons are to listen for an event invoked from a graph vai the EventBus, or to query some bool/state on the blackboard.
You can try this custom node switch it to coroutine, you do need to input the coroutine.
I do not know if you mean from C# or visual scripting so this will only work with visual scripting nodes
I ran into the same problem. My initial approach was to implement a custom Unit to notify that a given GameObject has completed a trigger transition:
[TypeIcon(typeof(CustomEvent))]
[UnitSurtitle("Transition Completed")]
[UnitShortTitle("Trigger")]
[UnitCategory("Events\\MyEvents")]//Setting the path to find the node in the fuzzy finder as Events > My Events.
public class TriggerTransitionCompletedEvent : Unit
{
[DoNotSerialize]
[PortLabelHidden]
public ControlInput inputTrigger { get; private set; }
[DoNotSerialize]
[PortLabelHidden]
[NullMeansSelf]
public ValueInput target { get; private set; }
[DoNotSerialize]
[PortLabelHidden]
public ControlOutput outputTrigger { get; private set; }
protected override void Definition()
{
inputTrigger = ControlInput(nameof(inputTrigger), Trigger);
target = ValueInput<GameObject>(nameof(target), null).NullMeansSelf();
outputTrigger = ControlOutput(nameof(outputTrigger));
Succession(inputTrigger, outputTrigger);
}
private ControlOutput Trigger(Flow flow)
{
var t = flow.GetValue<GameObject>(this.target);
EventBus.Trigger<GameObject>(EventNames.TransitionCompleted, t);
return outputTrigger;
}
}
I also implemented the following class to manage the transitions through coroutines. Instead of just calling CustomEvent.Trigger(...) to trigger the transitions, I call yield return TransitionTrigger(...)
public class VisualScriptingTransitionManager : IVisualScriptingTransitionManager
{
private readonly List<GameObject> _transitioning;
public VisualScriptingTransitionManager()
{
_transitioning = new List<GameObject>();
EventBus.Register<GameObject>(EventNames.TransitionCompleted, OnTransitionCompleted);
}
public IEnumerator TransitionTrigger(GameObject target, string name, params object[] args)
{
Debug.Log($"TransitionTrigger {target.name} trigger {name}");
if (_transitioning.Contains(target)) yield break;
_transitioning.Add(target);
CustomEvent.Trigger(target, name, args);
while (_transitioning.Contains(target)) yield return null;
Debug.Log($"{target.name} transition {name} completed");
}
private void OnTransitionCompleted(GameObject obj)
{
if (_transitioning.Contains(obj)) _transitioning.Remove(obj);
}
}
This works just fine if you never trigger a transition that is not reachable from your current state. In this case you would be adding the target to _transitioning but it won’t be removed from it, being trapped in the coroutine.
Is it possible to check whether a CustomEvent.Trigger is reachable from your current state?
Yeah nice. I ended up solving this by using yield WaitUntil someBool == true and setting the bool to true on the object from the graph. The graph creates the object to begin with so it’s easy for it to just tell it to complete when the flow is complete.
It would be similar to you giving the graph a transition object through the event trigger which just has a isFinished Boolean and set function, yielding until this is true in your transition trigger routine, and in your graph, just setting it to true when your flow is complete.