This site is currently in read-only mode during migration to a new platform.
You cannot post questions, answers or comments, as they would be lost during the migration otherwise.
+1 vote

I am trying to program turn-based system, and was thinking on some kind of chain of functions with yield, to ensure that everything is resolved one after another.
But then I realised I don't understand some very fundamental rule about code :

if I do :

func foo():
      for x in soldiers:
             x.resolve()

than every soldier executes its resolve function independently, fastest code is resolved first.

But what would happen if I do :

func foo():
      var whatever
      for x in soldiers:
             whatever = x.resolve()

Does this mean that loop is now waiting for each soldier to return its resolve function ??
If so, I would need no yields in my design

Godot version 3.5
in Engine by (8,188 points)

1 Answer

0 votes

So whenever you yield() inside of a function you drop out of that function call and return to the caller in the stack with a return type of GDFunctionState or something along those lines. Any yield() calls in x.resolve() would explain the behavior your are experiencing.

You could still have yields in your design. A quick solution that I came up with would be to register a stack of units to act with a turn manager and have a lock on the turn manager that each unit grabs when they start to act. Inside of _process() for the turn manager you check to see if the lock is locked - if it is do nothing otherwise make the next unit in the stack act.

Let me know if that makes sense or if you need further explanations on anything.

by (3,906 points)

Thank You, these ideas are definetely interesting to consider :)
However I wanted to know if I assign a function result to a variable, like in my example, wouldn't it have the same result as yielding ?
Take a look :

func foo():
      var whatever
      for x in soldiers:
             whatever = x.resolve()

Imagine that every x node has very different code in resolve() function, so each x require various time to be finished.
var whatever is introduced in higher scope then for loop. Its value is made dependant on each iterated element of the loop. So this should force each resolvecoroutine to be resolved one after another, independently of their individual resolution speed, am I not right ?

whatever will just be assigned the GDScriptFunctionState that yield() passes back in x.resolve() then on the next loop it will be overwritten with the new GDScriptFunctionState from the next x.resolve(). https://docs.godotengine.org/en/stable/classes/[email protected]?highlight=yiel#class-gdscript-method-yield

I think to achieve the turn queue system you desire you'll need to have a manager that waits until each unit's turn is completely over then lets the next unit start their turn.

I remember being just as confused as you were because my function was returning a boolean that I tested with if(variable) and I was confused why it was returning true when there as no way for it to possibly return true then I realized that variable was being assigned a GDScriptFunctionState instead of a boolean.

I should note that Yield is going away with godot 4.

But there is no yield in my example, no yield inside corroutines also ! :)
so whatever won't be assigned frozen function state. It should be assigned returning result of each of these coroutines instead. One after the other.
As opposed to if I would just do

for x in soldiers:
       x.resolve()

wchi would resolve all soldiers in order depending on their code complication

Am I getting this part wrong ?

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.