I’m writing a system that executes a series of actions sequentially, and I’ve chosen to use Coroutines as my mechanism for pausing the execution of certain commands. The way I’ve done this is by implementing a base Action class which has an execute function as follows:
public virtual IEnumerator Execute()
{
yield break;
}
The different types of actions then override the Execute function, introducing any delays as necessary. I play the sequence of Actions as follows:
foreach(Action action in actions)
{
yield return StartCoroutine(action.Execute());
}
The problem I’m currently having is that certain Actions should execute without pausing. Previously, I’d (mistakenly?) used “yield break;” to break out of the Coroutine without pausing, but I’m just now noticing that Actions that just have that “yield break;” at the end still introduce an undesired frame long pause.
How exactly would I write an “empty” function that returns IEnumerator, by which I mean a function that does nothing and does not cause a frame pause?
A while back, someone on the forums wrote a class called TaskManager that, if I’m understanding you, will take a lot of the pain out of what you’re trying to do. The class wraps around the Coroutine concept and allows you to create coroutines that you’ll run later - is that roughly what you want to do?
I’ve never seen a way to do that. (But I’ve been known to miss stuff…)
The way I’d do it is to create another logic layer; allow the class with the maybe-coroutine to declare the function with two different return values, and have some variable to indicate which to use. Messy and prone to programmer error, but since calling yield at all introduces a frame drop, I don’t know another way to do it.
class What {
IEnumerator F() {
yield break;
}
void F() {
}
bool FYields;
}
...
if ( what.FYields ) {
yield return what.F();
} else {
what.F();
}
Fwiw, I got around to doing this later down the road. My requirements made use of attributes necessary, so I used reflection to locate them in the assembly. Since I was already using reflection, I just invoked the method. If the return type was an IEnumerator I simply walked the dog. Figured I’d add a solution here in case it helps others.
GetParameters is a method in that class that returns an object array containing parameters that the methods will expect. Though it might not make sense out of context, I’m including it as an example.
object[] GetParameters(MethodInfo method)
{
object[] parameters = null;
FailureCallbackModes failMode = IsFailureCallbackSupported(method);
if (failMode != FailureCallbackModes.None)
parameters = new object[1];
switch (failMode)
{
case FailureCallbackModes.Action:
parameters[0] = failDelegate;
break;
case FailureCallbackModes.Message:
parameters[0] = failWithMessageDelegate;
break;
}
return parameters;
}
FailureCallbackModes IsFailureCallbackSupported(MethodInfo method)
{
ParameterInfo parameter = method.GetParameters().FirstOrDefault();
if (parameter != null)
{
if (parameter.ParameterType.Equals(typeof(Action)))
return FailureCallbackModes.Action;
if (parameter.ParameterType.Equals(typeof(Action<string>)))
return FailureCallbackModes.Message;
}
return FailureCallbackModes.None;
}
Hi, do you think using enum with “while switch” to manage the corroutine would help you? I use this system for my enemies AI, but also when I need to do cutscenes, like running secuencial behaviours. Each secuencia behaviour is being managed by a function, by adding some scripting in that function you control when it goes to the next step.
Some example;
private enum State
{
Sequence1,
Sequence2,
Sequence3,
Sequence4,
Sequence5,
Sequence6
}
private State state;
private IEnumerator SequenceExample ()
{
while (_alive)
{
switch (state)
{
case State.Sequence1:
Sequence1();
break;
case State.Sequence2:
Sequence2();
break;
case State.Sequence3:
Sequence3();
break;
case State.Sequence4:
Sequence4();
break;
case State.Sequence5:
Sequence5();
break;
case State.Sequence6:
Sequence6();
break;
}
yield return null;
}
}
void Sequence1 ()
{
// whatever code you need to run, once conditions set that sequence is over, then;
if (condition == true) //or whatever you need
{
state = Sequence.State.Sequence2; //this will bring you to step / sequence2
}
void Sequence2 ()
{
// whatever code you need to run, once conditions set that sequence is over, then;
if (condition == true) //or whatever you need
{
state = Sequence.State.Sequence3; //this will bring you to step / sequence3
}
etc
Another option is to use the enum and while switch with functions marked as enumerator; you can use courotine enum-while switch system with functions that you could add yield return WaitForSecond (x) on those that you need pause and dont add it to those steps/functions you dont want to do a pause.