Coroutines
A coroutine is a script method that can pause and continue on a later frame.
script Player {
@export var HitTint Color
var base Color
var blink Coroutine
func Hurt() {
if !blink.Running() {
blink = start Blink(6)
}
}
func Blink(times int) coroutine {
sr := node.Get<SpriteRenderer>()
for i := 0; i < times; i++ {
if i%2 == 0 {
sr.Tint = HitTint
} else {
sr.Tint = base
}
yield wait(0.1)
}
sr.Tint = base
}
}
- Declaration.
coroutinefollows the signature:func Name(params) coroutine { … }. Only script methods without a result can be coroutines (AES2053).Ready,Update,FixedUpdateandReloadedcannot be coroutines (AES2056); start one from them instead. - Starting.
start Name(args)runs the coroutine at once, up to its firstyield, and returns aCoroutine. Only coroutines of the same script can be started (AES2052). Calling a coroutine like a plain function isAES2051. Starting the same coroutine twice gives two independent runs. - yield is allowed only inside a coroutine (
AES2050):
| Form | Resumes |
|---|---|
yield |
on the next frame |
yield wait(s) |
after s seconds (float) of game time, at the earliest on the next frame; paused Play does not advance it |
yield frames(n) |
after n frames (int) |
yield fixed(n) |
after n fixed steps (int), before physics |
yield c |
when coroutine c ends; it resumes in the same frame; a nil, finished or cancelled c resumes on the next frame |
A wrong argument type is AES2057.
- Order. Coroutines that are due in one frame resume in the order they were started. They run in
script.coroutines, right afterscript.update;fixedwaits run afterscript.fixed. Only coroutines that are due are visited; ten thousand sleeping coroutines cost nothing per frame. - Ownership. A coroutine belongs to the instance that started it. It is cancelled when the instance's node is destroyed, the script is removed or disabled, the instance faults, or its script changes in a hot reload. A fault inside a coroutine stops the owning instance, like a fault in
Update. A cancelled coroutine releases its wait slot immediately; it does not linger until its timer would have fired. - Handles.
c.Stop()cancels;c.Running()is false once the coroutine finished, was cancelled or faulted. The zeroCoroutineisniland never running. A handle from before a hot reload stays valid as a value but is never running again. - Budget. Each resume has its own instruction budget (§12). A loop without
yieldinside a coroutine still ends withAES6001.
Run it:
package demo
import "aego/log"
script Blink {
var blink Coroutine
func Ready() {
blink = start Run(3)
}
func Run(times int) coroutine {
for i := 0; i < times; i++ {
log.Info("blink " + string(i))
yield wait(0.1)
}
log.Info("done")
}
}