Behaviors and Patterns Guide

Behaviors and Patterns Guide

This guide introduces behaviors and patterns in Crash BASIC - a declarative system for animating and controlling hardware sprites without writing frame-by-frame logic.

What Are Behaviors?

Behaviors are named, reusable sprite animation and movement definitions. Instead of manually updating sprite positions and frames each tick, you define behaviors once and apply them to sprites. The engine handles the rest.

' Define a behavior
BEHAVIOR "wobble"
    BOSCILLATE AMPLITUDE 5, 3
END BEHAVIOR

' Apply it to a sprite
SET SPRITE 0 BEHAVIOR "wobble"

Defining Behaviors

Single Behavior Block

BEHAVIOR "name"
    ' commands go here
END BEHAVIOR

Multiple Behaviors in One Block

Use labels to define multiple behaviors together:

BEHAVIOR "left":
    BMOVE -10, 0
"right":
    BMOVE 10, 0
END BEHAVIOR

Branching at Declaration Time

IF and SELECT CASE can appear inside a BEHAVIOR (or PATTERN) block. These run once, when the block is declared — they choose which commands the behavior is built from, they do not run per tick:

BEHAVIOR "enemyMove"
    SELECT CASE difficulty
        CASE 0
            BVELOCITY -1, 0
        CASE 1
            BVELOCITY -2, 0
        CASE ELSE
            BVELOCITY -3, 0
    END SELECT
END BEHAVIOR

Use it to build difficulty tiers, platform variants, or debug builds from one definition. For logic that must run every tick, use a WHEN condition on a pattern step instead.


Movement Commands

BMOVE - Constant Movement

Moves the sprite by a fixed amount each tick.

BEHAVIOR "moveRight"
    BMOVE 2, 0    ' Move right 2 pixels per tick
END BEHAVIOR

BEHAVIOR "diagonal"
    BMOVE -1, 1   ' Move down-left
END BEHAVIOR

BVELOCITY - Continuous Velocity

Contributes a standing movement intent, not a one-shot kick. The engine zeroes the BVELOCITY contribution at the start of every tick and each active BVELOCITY command adds its value back — so several behaviors carrying BVELOCITY are additive rather than last-one-wins.

BEHAVIOR "walkLeft"
    BVELOCITY -2, 0       ' keeps moving left while active
END BEHAVIOR

BEHAVIOR "conveyor"
    BVELOCITY 1, 0        ' stacks with the above: net -1
END BEHAVIOR

Because the contribution is rebuilt every tick, it has no inertia, and three consequences follow that surprise people:

  • BFRICTION does not decay it — there is nothing accumulated to decay.
  • A solid collision does not zero it. The sprite keeps pushing against whatever blocked it for as long as the behavior is active.
  • BBOUNCE cannot rebound it. The reflection is applied and then overwritten by the constant on the next tick, so a BVELOCITY-driven sprite presses against a wall instead of bouncing off it.

For a discrete kick — a jump, dash, recoil or knockback — use BIMPULSE. It seeds the accumulated velocity once, and unlike BVELOCITY it decays under friction and can be zeroed by a collision.

The optional third component sets vertical (elevation) velocity — see BGRAVITY.

BACCELERATION - Physics

Applies continuous acceleration each tick, accumulating into the sprite's velocity. This is the momentum BFRICTION decays and BBOUNCE reflects.

BEHAVIOR "falling"
    BACCELERATION 0, 0.5  ' Gravity
END BEHAVIOR

BEHAVIOR "cannonball"
    BIMPULSE 5, -3        ' Initial launch (one-shot)
    BACCELERATION 0, 0.2  ' Gravity arc
END BEHAVIOR

BIMPULSE - One-Shot Velocity Kick

Adds (ix, iy) to the sprite's accumulated accel_velocity exactly once per behavior activation, then becomes a no-op for the rest of that activation. The seeded velocity persists in accel_velocity and decays through BFRICTION (if any) the same way BACCELERATION contributions decay.

Argument Description
ix Horizontal impulse in pixels per tick. Added to accel_velocity_x once on activation.
iy Vertical impulse in pixels per tick. Same semantics on the Y axis (positive = down).

BIMPULSE is the right primitive for discrete kicks of momentum — jumps, dashes, recoil, knockback. To re-fire, the behavior must be deactivated and re-activated (typically driven from a pattern step or a WHEN trigger). On reactivation a fresh internal state is built and the impulse fires again.

' Classic jump — impulse fires once, gravity pulls back
BEHAVIOR "jump"
    BIMPULSE 0, -8
    BACCELERATION 0, 0.5
END BEHAVIOR

' Dash with friction settle — impulse, then ice-style decay
BEHAVIOR "dashRight"
    BIMPULSE 6, 0
    BFRICTION 0.1, 0
END BEHAVIOR

' Pattern-driven recoil — re-fires on every pattern reactivation
PATTERN "shoot"
    BEHAVIOR "recoil" DURATION 8
    BEHAVIOR "idle"   DURATION 12
END PATTERN

BEHAVIOR "recoil"
    BIMPULSE -2, 0
    BFRICTION 0.2, 0
END BEHAVIOR

How BIMPULSE fits with the other velocity primitives:

Command Cadence Where it lands Decays via BFRICTION?
BMOVE every tick direct position translation n/a — no velocity
BVELOCITY every tick overwrites bvelocity no — bvelocity is reset each tick
BIMPULSE once per activation adds to accel_velocity yes
BACCELERATION every tick adds to accel_velocity yes

Both axes accept VARIANCE for per-instance jitter and support @paramName=default parameter references for pattern-driven values.

BFRICTION - Universal Velocity Decay

Universally decays the sprite's accumulated accel_velocity every tick, regardless of collisions. Per-axis: 0 = frictionless, 1 = instant stop, in between = exponential decay (e.g. 0.1 = lose 10% per tick). Combines with BACCELERATION for terminal velocity behaviour — equilibrium ≈ acceleration / friction.

Argument Description
x_friction Decay coefficient on X axis. 0 = no decay, 1 = instant stop.
y_friction Decay coefficient on Y axis. Same scale.
' Air-resistance falling object — converges to terminal velocity ≈ 10
BEHAVIOR "airDrop"
    BACCELERATION 0, 1.0
    BFRICTION 0, 0.1
END BEHAVIOR

' Ice puck — slows naturally on both axes after a hit
BEHAVIOR "icePuck"
    BFRICTION 0.04, 0.04
END BEHAVIOR

BFRICTION does not affect BVELOCITY (which is reset and re-derived each tick) or BMOVE (constant-motion intent). It only decays the persistent accel_velocity accumulator. VARIANCE on each axis gives per-instance jitter — useful for swarms that need slightly different settle behaviour.

BBOUNCE - Collision Reflection

Makes the sprite bounce off solid boundaries on collision instead of being stopped flat. Each axis has its own restitution coefficient — 0 absorbs all energy (sprite stops dead), 1 is perfect elastic (no energy loss), in between loses a fraction per hit. Both BVELOCITY contributions and accumulated BACCELERATION are reflected together.

Argument Description
x_restitution Bounce coefficient on X axis (LEFT/RIGHT walls). 0 = absorb, 1 = perfect.
y_restitution Bounce coefficient on Y axis (TOP/BOTTOM walls). Same scale.

For SLOPE boundaries, the velocity is reflected along the slope's normal vector and scaled by the average of x_restitution and y_restitution — so a ball hitting a 45° SE slope from above bounces cleanly up and to the right.

BEHAVIOR "rubberBall"
    BBOUNCE 0.9, 0.9
    BVELOCITY 5, 0
    BACCELERATION 0, 0.4   ' Gravity
END BEHAVIOR

BEHAVIOR "basketball"
    BBOUNCE 0.7, 0         ' Rolls along floor, no Y bounce
    BVELOCITY 4, 0
END BEHAVIOR

VARIANCE on each restitution gives natural-feeling jitter, useful for swarms of bouncing particles:

BEHAVIOR "sparkBounce"
    BBOUNCE 0.85 VARIANCE(-0.1, 0.05), 0.85 VARIANCE(-0.1, 0.05)
    BVELOCITY 4 VARIANCE(-3, 3), -6 VARIANCE(-2, 2)
    BACCELERATION 0, 0.3
END BEHAVIOR

When BBOUNCE is not in any active behavior, sprites use the default zero-on-block behavior (accel_velocity in the blocked direction is zeroed; BVELOCITY persists). Activating BBOUNCE swaps that for the reflection above; deactivating the behavior clears the bounce profile.

BGRAVITY - Vertical Pull

Sprites have a third axis: ELEVATION, their height above the layer. BGRAVITY strength accelerates a sprite back toward the floor every tick — sugar for the vertical part of BACCELERATION 0, 0, -strength. Use a positive strength.

BEHAVIOR "hop"
    BIMPULSE 0, 0, 16     ' kick upward (third component is z)
    BGRAVITY 1            ' pull back to the ground
    BBOUNCE 0, 0, 0.4     ' keep 40% on landing
END BEHAVIOR

Elevation is only rendered on an AFFINE or PERSPECTIVE plane layer, where the sprite rides toward the camera eye-height and foreshortens with distance. On a flat layer the physics still runs but you will not see it, which is why 2D platformers do their jumping on screen Y instead.

BFRICTION's optional third coefficient decays vertical speed — air resistance, or a terminal fall speed of roughly gravity / z_friction. Read the live height with SPRITEELEVATION(id), which is what a WHEN condition uses for landing detection.

BELEVATE - Height Animation

Tweens elevation from one height to another, mirroring BALPHA/BSCALE/BROTATE. This is a scripted lift rather than physics — no gravity involved.

BEHAVIOR "rise"
    BELEVATE 0 TO 32 DURATION 30
END BEHAVIOR

BEHAVIOR "fall"
    BELEVATE 32 TO 0 DURATION 30
END BEHAVIOR

' Sequence them in a looping PATTERN for a continuous hover
PATTERN "hover" LOOP
    "rise"
    "fall"
END PATTERN

PATH - Waypoint Movement

Moves the sprite along a series of waypoints.

Modifier Description
ABSOLUTE Use screen coordinates (default is relative to starting position)
SPEED n Pixels per tick (default: 1)
LOOP Repeat indefinitely
PINGPONG Reverse at endpoints instead of jumping back
BEHAVIOR "bounce"
    PATH (0,0), (0,-20), (0,0) SPEED 3 LOOP
END BEHAVIOR

BEHAVIOR "patrol"
    PATH ABSOLUTE (100,100), (200,100) SPEED 2 LOOP PINGPONG
END BEHAVIOR

BEHAVIOR "square"
    PATH (0,0), (50,0), (50,50), (0,50) LOOP
END BEHAVIOR

BFOLLOW - Follow Another Sprite

Makes the sprite follow a target sprite, maintaining minimum distance.

BEHAVIOR "followPlayer"
    BFOLLOW 0 DISTANCE 40 SPEED 2
END BEHAVIOR

BEHAVIOR "companion"
    BFOLLOW 0 DISTANCE 24 SPEED 1.5
    ANIMATE "pet", 0, 1, 2, 3 FRAMERATE 10
END BEHAVIOR

BORBIT - Orbital Movement

Makes the sprite orbit around a fixed point or another sprite.

' Orbit around a coordinate
BEHAVIOR "orbitCenter"
    BORBIT (160, 120) DISTANCE 50
END BEHAVIOR

' Orbit around sprite 0
BEHAVIOR "satellite"
    BORBIT SPRITE 0 DISTANCE 30 SPEED 2
END BEHAVIOR

' Counterclockwise orbit
BEHAVIOR "shield"
    BORBIT SPRITE 0 DISTANCE 32 SPEED 8 COUNTERCLOCKWISE
END BEHAVIOR

' Spiral inward
BEHAVIOR "spiral"
    BORBIT (160, 120) DISTANCE 80 DECAY 0.5
END BEHAVIOR

BOSCILLATE - Smooth Oscillation

Creates smooth back-and-forth movement around the starting position using a sine wave.

Modifier Description
AMPLITUDE x, y Maximum displacement in pixels
SPEED n Degrees per tick (default: 6, full cycle ~60 ticks)
DECAY n Reduce amplitude each tick (settles to start)
PHASE n Initial sine angle in radians (default 0; supports VARIANCE for per-instance scatter)
PERSISTENT Keep final position when behavior ends
BEHAVIOR "hover"
    BOSCILLATE AMPLITUDE 0, 8   ' Vertical bob
END BEHAVIOR

BEHAVIOR "sway"
    BOSCILLATE AMPLITUDE 15, 0 SPEED 3
END BEHAVIOR

BEHAVIOR "landing"
    BOSCILLATE AMPLITUDE 0, 15 SPEED 10 DECAY 0.4
END BEHAVIOR

Initial phase. The default starting phase is 0 — every instance assigned this behavior begins synchronized at the wave origin. To scatter starting phases across many sprites or mutation points (so a swarm of bobbers doesn't move in lockstep), use PHASE with VARIANCE:

BEHAVIOR "swarmBob"
    BOSCILLATE AMPLITUDE 0, 8 SPEED 4 PHASE 0 VARIANCE(0, 6.28)
END BEHAVIOR

VARIANCE(0, 6.28) covers a full 2π cycle, so each instance gets a uniformly random offset.

Phase carryover between behaviors. When a sprite transitions from one BOSCILLATE behavior directly into another, the new behavior automatically inherits the previous behavior's current phase — the wave continues smoothly across the join with no visual jerk. The carryover applies for one transition only: if you switch through a non-oscillating behavior in between, the chain breaks and the next BOSCILLATE starts fresh at phase 0 (or its explicit PHASE override). An explicit PHASE on the new behavior always wins over an inherited value.

' These two idles share momentum across the swap — no twitch.
BEHAVIOR "idleSlow"
    BOSCILLATE AMPLITUDE 0, 6 SPEED 3
END BEHAVIOR
BEHAVIOR "idleFast"
    BOSCILLATE AMPLITUDE 0, 6 SPEED 8
END BEHAVIOR

BSHAKE - Random Shake

Creates random jittering for damage feedback or tremor effects.

BEHAVIOR "damaged"
    BSHAKE AMPLITUDE 4
    BBLINK 5
END BEHAVIOR

BEHAVIOR "unstable"
    BSHAKE AMPLITUDE 2
END BEHAVIOR

Visual Commands

ANIMATE - Frame Animation

Cycles through sprite sheet frames.

' Use all frames from sprite sheet
BEHAVIOR "idle"
    ANIMATE "player" FRAMERATE 10
END BEHAVIOR

' Specific frames
BEHAVIOR "walk"
    ANIMATE "player", 0, 1, 2, 3 FRAMERATE 10
END BEHAVIOR

' Frame range (0 TO 18 expands to 0, 1, 2, ..., 18)
BEHAVIOR "run"
    ANIMATE "player", 0 TO 18 FRAMERATE 15
END BEHAVIOR

Aseprite Timing and Hitboxes

An .ase/.aseprite file carries per-frame durations and per-frame slice geometry, and two clauses put them to work:

' Play at the per-frame timings authored on the Aseprite timeline
BEHAVIOR "run"
    ANIMATE "heroRun", 0 TO 7 FRAMERATE OFSPRITE
END BEHAVIOR

' AUTOBBOX drives the hitbox from the file's slice, per frame
BEHAVIOR "attack"
    ANIMATE "heroAttack", 0 TO 5 AUTOBBOX FRAMERATE OFSPRITE
END BEHAVIOR

FRAMERATE OFSPRITE means re-timing an animation is a save in Aseprite, not a code change. AUTOBBOX means a sword swing whose hitbox only extends on the frames where the blade is out becomes an animator decision instead of a table of magic numbers.

EVENTSON - Frame Events

Trigger events when specific frames are displayed:

BEHAVIOR "walk"
    ANIMATE "player", 0, 1, 2, 3 EVENTSON(1, 3) FRAMERATE 10
END BEHAVIOR

SUB OnWalkFrame(sprite_id, frame)
    IF frame = 1 THEN PLAYWAV "step1"
    IF frame = 3 THEN PLAYWAV "step2"
END SUB

CALL EVENT OnWalkFrame() AS "PLAYER_FRAME"

Event names are derived from the image name: ANIMATE "player" fires events named PLAYER_FRAME.

BALPHA - Transparency Animation

BEHAVIOR "fadeIn"
    BALPHA 0 TO 1 DURATION 30
END BEHAVIOR

BEHAVIOR "pulse"
    BALPHA 1 TO 0.3 DURATION 15 LOOP
END BEHAVIOR

BSCALE - Scale Animation

BEHAVIOR "grow"
    BSCALE 1, 1 TO 2, 2 DURATION 30
END BEHAVIOR

BEHAVIOR "breathe"
    BSCALE 1, 1 TO 1.2, 1.2 DURATION 10 LOOP
END BEHAVIOR

BROTATE - Rotation Animation

Two modes: absolute (FROM TO) and relative (single value from current angle).

' Absolute: spin from 0 to 360
BEHAVIOR "spin"
    BROTATE 0 TO 360 DURATION 60 LOOP
END BEHAVIOR

' Relative: rotate 360 degrees from current
BEHAVIOR "spinRelative"
    BROTATE 360 DURATION 60 LOOP
END BEHAVIOR

' With custom origin (center)
BEHAVIOR "spinCenter"
    BORIGIN 0.5, 0.5
    BROTATE 0 TO 360 DURATION 60 LOOP
END BEHAVIOR

BORIGIN - Anchor Point

Sets the sprite's anchor/pivot point using normalized coordinates (0-1).

Value Position
0, 0 Top-left (default)
0.5, 0.5 Center
1, 1 Bottom-right
BEHAVIOR "centerSpin"
    BORIGIN 0.5, 0.5
    BROTATE 0 TO 360 DURATION 60 LOOP
END BEHAVIOR
BEHAVIOR "invincible"
    BBLINK 4   ' Toggle every 4 ticks
END BEHAVIOR

BIMAGE - Change Sprite Texture

BEHAVIOR "powered"
    BIMAGE "playerPowered"
    BSCALE 1, 1 TO 1.2, 1.2 DURATION 30 LOOP
END BEHAVIOR

BSHADER - Animated Shader Effects

Animates a shader parameter over time. Auto-attaches the shader when behavior activates.

BEHAVIOR "dissolve"
    BSHADER "Dissolve" @progress=0 TO 1 DURATION 60
END BEHAVIOR

BEHAVIOR "glow"
    BSHADER "Glow" @intensity=0.5 TO 1.0 DURATION 30 LOOP
END BEHAVIOR

Collision Handlers

A behavior can react to being hit, with inline BASIC that runs when a contact happens. Both blocks are edge-triggered — once per contact, not once per tick.

DIM dx AS INTEGER
dx = -1

BEHAVIOR "patrol"
    BVELOCITY @vx = 0, @vy = 0

    ONCOLLISION
        ' Before resolution: impact_vx / impact_vy still hold the speed we hit at
        IF tag_b$ = "spikes" THEN CALL Damage(index_a)
    END ONCOLLISION

    AFTERCOLLISION
        ' After resolution: the engine has already stopped us. Turn around.
        dx = dx * -1
        SET SPRITE index_a BEHAVIOR "patrol", @vx = dx, @vy = 0
    END AFTERCOLLISION
END BEHAVIOR

When each one runs. A tick goes contact -> resolution -> next tick. ONCOLLISION runs on contact, before resolution, so it sees the velocity you struck at — the value resolution is about to zero or reflect. AFTERCOLLISION runs between resolution and the next tick, once the engine has stopped or bounced you, which makes it the place to decide what to do about the hit.

A solid contact always resolves, so both land on the tick of the hit and AFTERCOLLISION does not wait for you to move away. That matters because BVELOCITY never stops pressing — a sprite held against a wall would otherwise never separate. A ghost contact has no resolution to follow, so its AFTERCOLLISION waits for the overlap to end.

The scoped values, describing the contact as it began:

Value Meaning
index_a the sprite whose behavior this is
index_b the other sprite, or -1 for a boundary
tag_a$ / tag_b$ the two tags (tag_b$ is the boundary tag when index_b = -1)
edge$ which face was contacted
impact_vx / impact_vy velocity at impact, pre-resolution

Rules:

  • Declare persistent variables outside the block. A handler body scopes like a SUB, so assigning an undeclared name creates a local that vanishes on return — hence dx above.
  • No blocking statements. PAUSE, DELAY, DELAY UNTIL and YIELD are rejected at definition time; a handler runs on the behavior tick loop and would freeze every sprite in the game.
  • Changes take effect next tick — swapping behavior, GHOST, SOLID.
  • Boundary contacts key on the tag, not the segment, so a wall of ten "wall" pieces is one surface and sliding across seams does not re-fire.
  • Both sprites fire in a sprite-to-sprite hit, each seeing itself as index_a — including a stationary sprite that something ran into.

Re-issuing a behavior with different @params rebuilds it, which is how the turn-around above works. Re-issuing with the same params is deliberately a no-op, so a DO loop can re-assert a behavior every frame without restarting BMOVE timing or re-rolling VARIANCE.


Applying Behaviors to Sprites

Adding Behaviors

SET SPRITE 0 BEHAVIOR "walkRight"
SET SPRITE 0 BEHAVIOR "fadeIn"   ' Multiple behaviors stack

Removing Behaviors

SET SPRITE 0 BEHAVIOR DELETE "fadeIn"   ' Remove specific
SET SPRITE 0 BEHAVIOR NONE              ' Clear all

Checking Behaviors

IF HASBEHAVIOR(0, "walkRight") THEN PRINT "Walking"

' Get all active behaviors
behaviors$ = SPRITEBEHAVIORS$(0)   ' Returns "WALKRIGHT,FADEIN"

Combining Multiple Behaviors

Multiple behaviors can be active simultaneously and their effects combine:

BEHAVIOR "walkRight"
    ANIMATE "player", 0, 1, 2, 3 FRAMERATE 10
    BMOVE 2, 0
END BEHAVIOR

BEHAVIOR "bobbing"
    BOSCILLATE AMPLITUDE 0, 3
END BEHAVIOR

' Apply both - sprite walks right while bobbing
SET SPRITE 0 BEHAVIOR "walkRight"
SET SPRITE 0 BEHAVIOR "bobbing"

INCLUDES - Composing at Definition Time

Rather than applying several behaviors to every sprite, compose them once into one:

BEHAVIOR "bobbing"
    BOSCILLATE AMPLITUDE 0, 3
END BEHAVIOR

BEHAVIOR "walkRight" INCLUDES("bobbing")
    ANIMATE "player", 0, 1, 2, 3 FRAMERATE 10
    BMOVE 2, 0
END BEHAVIOR

SET SPRITE 0 BEHAVIOR "walkRight"   ' bobs too

The included behavior's commands are folded in, and collision handlers stack: every inherited ONCOLLISION runs, in composition order.


Parameterized Behaviors

Use @paramName=default syntax to create reusable behaviors with variable values:

BEHAVIOR "moveToPoint"
    BMOVE @targetX=0, @targetY=0
END BEHAVIOR

' Use with overrides (evaluated at assignment time)
SET SPRITE 0 BEHAVIOR "moveToPoint", @targetX=100, @targetY=playerY

' Use with defaults
SET SPRITE 1 BEHAVIOR "moveToPoint"

Variance - Randomized Values

Add randomness to behavior values using VARIANCE or VARIANCEINT:

BEHAVIOR "randomVelocity"
    BVELOCITY 5 VARIANCE(-2, 2), 0   ' X velocity: 3 to 7
END BEHAVIOR

BEHAVIOR "randomDirection"
    BMOVE 0 VARIANCEINT(-1, 1, NONZERO), 0 VARIANCEINT(-1, 1, NONZERO)
END BEHAVIOR

BEHAVIOR "variedAnimation"
    ANIMATE "sprite", 1, 2 FRAMERATE 10 VARIANCE(2, 3)
END BEHAVIOR

Patterns - Sequencing Behaviors

Patterns orchestrate behaviors over time, creating complex animation sequences.

Basic Pattern

PATTERN "walkCycle" LOOP
    "walkRight" DURATION 120
    "idle" DURATION 60
END PATTERN

SET SPRITE 0 PATTERN "walkCycle"

Step Modes

Mode Description
DURATION ticks Run behavior for fixed time
(no modifier) Completion mode - wait for behavior to finish
WHEN condition Active while condition is true
' Completion mode - waits for fadeOut to finish
PATTERN "fadeAndDie"
    "fadeOut"
    DISABLE
END PATTERN

' Conditional - responds to input
PATTERN "playerControl" LOOP
    "idle"
    "walkRight" WHEN KEYDOWN("RIGHT")
    "walkLeft" WHEN KEYDOWN("LEFT")
END PATTERN

Pattern Commands

Commands that affect the sprite directly:

Command Description
SHOW Make sprite visible
HIDE Make sprite invisible
DISABLE Remove/destroy the sprite
SOLID Enable collision
GHOST Disable collision
FADE [SPEED n] Fade alpha to 0
RETAG "tag" Change sprite tag
GOTOPATTERN "name" Switch to another pattern
BEVENT "name" Fire a custom event
PATTERN "death"
    GHOST                ' Stop collisions
    "hit" DURATION 10
    "fall"               ' Completion mode
    FADE SPEED 2
    DISABLE              ' Remove sprite
END PATTERN

PATTERN "transform"
    RETAG "powered"
    GOTOPATTERN "powerMode"
END PATTERN

Commands with WHEN

Commands can have conditions too:

PATTERN "enemy" LOOP
    "patrol"
    DISABLE WHEN health <= 0
END PATTERN

Techniques and Recipes

Walking Character

BEHAVIOR "walkRight"
    ANIMATE "player", 0, 1, 2, 3 FRAMERATE 10
    BMOVE 2, 0
END BEHAVIOR

BEHAVIOR "walkLeft"
    ANIMATE "player", 0, 1, 2, 3 FRAMERATE 10
    BMOVE -2, 0
    BFLIPX ON
END BEHAVIOR

BEHAVIOR "idle"
    ANIMATE "player", 0, 1 FRAMERATE 5
END BEHAVIOR

PATTERN "playerMovement" LOOP
    "idle"
    "walkRight" WHEN KEYDOWN("RIGHT")
    "walkLeft" WHEN KEYDOWN("LEFT")
END PATTERN

Jumping with Gravity

BEHAVIOR "jump"
    BIMPULSE 0, -8        ' one-shot kick; BVELOCITY would push up forever
    BACCELERATION 0, 0.5
END BEHAVIOR

BEHAVIOR "falling"
    BACCELERATION 0, 0.5
END BEHAVIOR

On a plane layer, where sprites have real height, this is BIMPULSE 0, 0, 16 plus BGRAVITY 1 instead — the jump happens on the elevation axis rather than on screen Y.

Floating Collectible

BEHAVIOR "float"
    ANIMATE "coin", 0, 1, 2, 3 FRAMERATE 8
    BOSCILLATE AMPLITUDE 0, 8
END BEHAVIOR

BEHAVIOR "collected"
    BSCALE 1, 1 TO 1.5, 1.5 DURATION 15
    BALPHA 1 TO 0 DURATION 15
END BEHAVIOR

PATTERN "coin"
    "float"
    "collected" WHEN collected
    DISABLE
END PATTERN

Enemy Patrol

BEHAVIOR "patrolRight"
    ANIMATE "enemy", 0, 1, 2, 3 FRAMERATE 8
    BMOVE 1, 0
END BEHAVIOR

BEHAVIOR "patrolLeft"
    ANIMATE "enemy", 0, 1, 2, 3 FRAMERATE 8
    BMOVE -1, 0
    BFLIPX ON
END BEHAVIOR

PATTERN "patrol" LOOP
    "patrolRight" DURATION 120
    "patrolLeft" DURATION 120
END PATTERN

Timed patrol is fine for open ground. If the enemy should turn around when it actually hits something rather than on a stopwatch, drive it from the collision instead:

DIM edx AS INTEGER
edx = -1

BEHAVIOR "patrolBounce"
    ANIMATE "enemy", 0, 1, 2, 3 FRAMERATE 8
    BVELOCITY @vx = 0, @vy = 0

    AFTERCOLLISION
        edx = edx * -1
        SET SPRITE index_a BEHAVIOR "patrolBounce", @vx = edx, @vy = 0
    END AFTERCOLLISION
END BEHAVIOR

Orbiting Shields

BEHAVIOR "orbitShield"
    BORBIT SPRITE 0 DISTANCE 32 SPEED 5
    BROTATE 360 DURATION 60 LOOP
END BEHAVIOR

' Create 3 shields at different starting angles
FOR i = 0 TO 2
    SET SPRITE 10 + i, SPRITEX(0), SPRITEY(0), "shield"
    SET SPRITE 10 + i BEHAVIOR "orbitShield"
NEXT i

Death Animation

BEHAVIOR "deathSpin"
    BORIGIN 0.5, 0.5
    BROTATE 0 TO 720 DURATION 60
    BSCALE 1, 1 TO 0, 0 DURATION 60
    BALPHA 1 TO 0 DURATION 60
END BEHAVIOR

PATTERN "die"
    GHOST
    "deathSpin"
    DISABLE
END PATTERN

Damage Feedback

BEHAVIOR "hit"
    BSHAKE AMPLITUDE 4
    BBLINK 5
END BEHAVIOR

' Apply temporarily
SET SPRITE 0 BEHAVIOR "hit"
' Remove after delay (in your game loop)
IF hitTimer > 30 THEN SET SPRITE 0 BEHAVIOR DELETE "hit"

Screen Shake (Using Camera Sprite)

BEHAVIOR "screenShake"
    BSHAKE AMPLITUDE 8
END BEHAVIOR

' Apply to a "camera" sprite that offsets all rendering
SET SPRITE 255 BEHAVIOR "screenShake"

Saving and Loading Behaviors

Behaviors and patterns can be serialized to JSON and loaded back, so you can author them once and reuse them across projects:

SAVE BEHAVIOR "walkCycle" TO "walk.json"
LOAD BEHAVIOR "walk.json"

SAVE PATTERN "patrol" TO "patrol.json"
LOAD PATTERN "patrol.json"

A saved behavior is written in its resolved form — declaration-time IF/SELECT already flattened away — while @param defaults and VARIANCE are preserved. A saved pattern keeps its steps, runtime WHEN conditions, durations and LOOP flag.

Loading registers everything in the file under its saved name; re-loading a name that already exists overwrites it, exactly as re-declaring the block would. Saving an undefined name, or loading a missing or malformed file, is a loud runtime error rather than a silent partial load.

For a whole parented sprite tree plus the behaviors it uses, see SAVE RIG / LOAD RIG.


Attribute Persistence

When behaviors are deactivated, some attributes revert while others persist:

Reverts Persists
Visibility (BBLINK restores visible) Position (BMOVE, PATH, etc.)
Velocity (BVELOCITY zeros out) Alpha (BALPHA final value)
Shaders (BSHADER removes shader) Scale (BSCALE final value)
Rotation (BROTATE final angle)
Flip state (BFLIPX/BFLIPY)
Image/Frame (ANIMATE, BIMAGE)
Origin (BORIGIN)

Special case: BACCELERATION velocity persists when a single behavior is deactivated but clears when ALL behaviors are cleared with BEHAVIOR NONE.


Summary

  • Behaviors define reusable animation and movement logic
  • Multiple behaviors can be active simultaneously and combine
  • Parameters make behaviors flexible and reusable
  • Variance adds controlled randomness
  • Patterns sequence behaviors over time with transitions and conditions
  • Use DURATION for timed steps, WHEN for conditional steps, or omit modifiers for completion mode
  • INCLUDES composes behaviors at definition time; declaration-time IF/SELECT CASE picks which commands a behavior is built from
  • ONCOLLISION / AFTERCOLLISION let a behavior react to being hit — before and after the engine resolves the contact
  • BVELOCITY is continuous, BIMPULSE is a one-shot kick — reach for BIMPULSE for jumps, dashes and knockback
  • SAVE / LOAD BEHAVIOR (and PATTERN, and RIG) move authored motion between projects