Motion control programs
Motion control programs are short programs that determine sprite motion in various simple ways. Motion control programs are written in a tiny custom language, and are generally no more than a few instructions long. They give sprites a small amount of autonomy, separate from the scripting language level, to give vastly improved performance when dealing with a great number of sprites. They can be used to create particle systems, environmental effects, and the like.
Before reading on, you'll want to take a look at the spark demo. The spark demo comes pre-built for both Linux and Windows:
Please note that to run the Linux executable, you will need SDL, SDL_mixer, and SDL_image installed on your computer.
Working with motion control programs
There's not much to using motion control programs: any sprite can have a motion control program assigned to it, and the program can be executed at any time.
Loading
Loading and running motion control programs is pretty simple. To load a program, use the sprite load-program (in C, sprite_load_program()) command. If there are any problems with the program, such as a syntax error, the command will return an error.
Running
Running a program can be done one of two ways, either a single sprite's motion control program by way of motion single (in C, motion_exec_single()) or the motion control programs for all of the sprites in a given sprite list with motion list (in C, motion_exec_list()).
The language
The motion control language consists of a few types of instructions, which operate on various sprite properties. Any given motion-control program can access the properties only of its own sprite, with one exception: when a motion control program clones a sprite, it then acts on the clone's properties, rather than the original sprite.
The sprite properties
The sprite properties which can be read or altered by a motion control program are: xpos, ypos, xvel, yvel, frame, tick. xpos and ypos refer to the sprite position. xvel and yvel are the sprite's current velocity. frame is the sprite's current frame. tick is an internal counter that is incremented automatically once each time the motion-control program is run.
The instructions
This is a complete list of the instructions available to motion control programs. These fit into three categories: arithmetic instructions, conditional-exit instructions, and sprite/list manipulation instructions.
set var, var/immediate
add var, var/immediate
jitter var, immediate
ce-lt immediate
ce-gt immediate
ce-jitter immediate
clone id
l-add id
l-remove id
destroy
Arithmetic instructions
These are the arithmetic instructions. They each take two arguments, the left-hand side always a named variable, the right-hand side either a named variable or an immediate integer value.
set var, var/immediate
add var, var/immediate
jitter var, immediate
Set
The set instruction assigns the right-hand variable or immediate integer to the variable named on the left-hand side. For example, set tick, 0 will zero out the sprite's tick counter.
Add
The add instruction adds the value of the right-hand side, either the contents of the variable or the immediate integer, to the left-hand variable. So, add ypos,yvel will adjust the sprite's position by its velocity.
Jitter
The jitter instruction adds a random amount between the negative immediate and the immediate to the left-hand variable. So the code, jitter ypos, 4 will adjust a sprite's vertical position up or down anywhere from -4 to 4 pixels.
Conditional instructions
These are the conditional instructions. If the condition is met, they exit the motion control program immediately, and no further instructions in the program are processed. They all take a single argument, an immediate integer value.
ce-lt immediate
ce-gt immediate
ce-jitter immediate
Ce-lt
Ce-lt is “conditional exit if tick counter is less than the given immediate”. This is useful for letting a sprite run for a while, and then removing it from play. For example,
add xpos,xvel
ce-lt 50
l-remove sprite list
destroy
will let the sprite continue to run for 50 ticks. After 50 ticks, the sprite removes itself from its sprite list and then removes itself from play.
Ce-gt
Ce-gt is “conditional exit if tick counter is greater than the given immediate”. This is useful for letting a sprite adjust its motion for several ticks and then cease adjustment, or to let a sprite create new sprites only for a short while.
Ce-jitter
Ce-jitter is “conditional exit if a random number between 0 and the given immediate is boolean true (i.e. not zero)”. So, as an example, ce-jitter 4 will test a random number between 0 and 4, and if it is non-zero, the motion control program will exit immediately. This is useful for allowing a sprite to execute the motion control program only a small part of the time, at random.
Sprite and list manipulations
These are the instructions used to create new sprites and add them to sprite lists, and remove current sprites from play. Some of these are pretty much only useful in conjunction with one other.
clone id
l-add id
l-remove id
destroy
Clone
This creates a new copy of the sprite given by id. When this instruction is run, the motion program continues to run, but now runs in the context of the cloned sprite. Any arithmetic instructions will operate on the clone, and not the original sprite.
L-add
This adds the current sprite to the list given by id.
L-remove
This removes the current sprite from the list given by id.
Destroy
This destroys the current sprite. Note that it does not remove the sprite from any sprite lists, so that must be done before it is called.
The end-of-code instruction
The instruction eoc marks the end of the motion control program. Nothing after this instruction will be executed. It's not necessary to include, because the brick engine will automatically append it to any program when the program is parsed and loaded.
The spark demo examined
The spark demo displays a small fountain, which emits a stream of colored sparks. The demo shows off the motion control code by creating a moving display, where sprites are created and destroyed, without any code to control these sprites at the scripting level.
There are seven sprites created by the game script: the cannon, a spark generator for each color, and a “prototype” spark (i.e. a sprite that is used to make copies, but is itself never altered) for each color. The cannon is just a decoration and does nothing. The generators use a motion program to clone the sparks, give them a random velocity, and add them to the list. The cloned sparks have a motion program to update the position and velocity and remove themselves from the playfield after a number of frames has passed.
The generators
The program for each spark generator is simple:
ce-jitter 3
clone prototype-id
l-add sprite-list-id
jitter xvel, 4
jitter yvel, 3
The generator program has a conditional exit, ce-jitter, so that it only runs every few frames, reducing the overall number of sparks generated. When the generator program does run in full, it's pretty simple: clone the prototype spark, add it to the list, and randomize its x and y velocities.
The sparks
The program for each spark is also pretty simple:
add xpos,xvel
add ypos,yvel
add yvel,1
ce-lt 24
l-remove sprite-list-id
destroy
The spark program first updates the sprite's position by adding to the position the sprite's current velocity. The program then increases the y velocity by 1, to give a nice arc to the motion, a poor-man's gravity effect. The program has a conditional exit, ce-lt, if fewer than 24 ticks have passed, so that the spark has a reasonable lifetime. Once the sprite has run for 24 ticks, the last two commands are run, and the sprite is removed from the sprite list and destroyed.
Running the motion control programs
The generator sprites are not part of any sprite list, so their programs are run individually, with calls to motion single (in C, motion_exec_single()), at the top of the main game loop. The sparks are part of the sprite list, though, so their programs are all run at once with the motion list (in C, motion_exec_list()) command.