Loops
Command Loops can help manage the complexity of the logic for your units. They allow you to run complicated lists of commands and switch between them easily when situations change.
You can create your own commands, or you can call any of the
built-in Enu commands like forward
, back
, turn
,
sleep
, etc.
A Command Loop always has one and only one active command, which it will call
repeatedly until you switch to some other command. The default command is
nil
. The first thing a loop must do is switch from nil
to another command,
using the little switch arrow ->
.
loop:
nil -> forward
# I'll go forward forever!
The little switch arrow (->
) will switch from the command on the left to the
command on the right if it's encountered and the left command has just
completed. If the loop goes through and no switches match, the command will be
run again.
We can control which switches get run by putting them in if
statements.
loop:
nil -> forward
if player.far:
forward -> back
if player.near:
back -> forward
In the above example, the loop immediately switches to forward
, and will go
forward indefinitely until one of the conditions is met and the command is
switched to something else. If the player gets too far away (more than 100m) and
the command is forward
, the command will be switched to back
. If the player
is near (5m) and the command is back
, it will switch to forward
. However, if
the player is near and the command is forward
, nothing will change. The
if player.near
statement will be true, but back -> forward
is ignored, since
the current command isn't back
.
If you want your loop to end at some point, you can switch back to nil
:
loop:
# Some commands can take parameters.
nil -> forward(10)
forward -> nil
# I'll run `forward(10)` a single time, then stop and end
# the loop.
Let's look at something more complicated and introduce the big switch arrow
(==>
) and switch blocks.
- wander:
speed = 1
forward 5..10
turn -45..45
- charge:
speed = 5
turn player
forward 1
- flee:
speed = 3
turn -player
forward 1
- attack:
player.bounce 5
turn 360
var health = 3
loop:
nil -> wander
if 1 in 50:
# When each `wander` command finishes there's a 1 in 50
# (2%) chance of our unit getting a sudden burst of
# energy and switching to the `charge` command.
# Otherwise we just keep wandering.
wander -> charge
if health == 0:
# We died. Exit the loop. We want this to happen
# immediately, not after the command finishes, so we
# use the big switch arrow. We use the special `any`
# command to say that this should happen regardless of
# the running command.
any ==> nil
if player.hit:
# If the player touches us while we're wandering, we
# flee. We want it to happen the instant the player
# touches us, not when our current `wander` is done, so
# we use the big switch arrow.
wander ==> flee:
# This is a switch block. If the command switches
# here, the switch block will also run once.
health -= 1
# if the player touches us while we're charging, we
# attack immediately.
charge ==> attack
if player.far:
# If the player is far and we're fleeing, go back to
# wandering
flee -> wander
# Switch to wander when our attack is done. We always
# want this to happen, so it isn't in a conditional. It
# only does anything if the current command is `attack`,
# and we only do it when the attack is done becuase we're
# using the little switch arrow.
attack -> wander
Note for Nimions
Command Loops are state machines, and any proc can be a state. If the proc has a return value it will be discarded.