Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bumping into things

I keep track of which sprites overlap which, every tick, so you don’t have to check every pair yourself. When two start to touch, I tell each one, and when they come apart, I tell them that too.

Walls

A boundary is a rectangle that’s part of the level: a floor, a wall, the edge of the screen. BOUNDARY ADD gives it a name and two corners with -> between them. A solid sprite can’t go through a solid boundary; with enclosure, it can’t get out of one.

SCREEN 320, 240
MEMORYBUFFER "ball", 12, 12
    CIRCLE (6, 6), 5, 14, 14
END MEMORYBUFFER

BOUNDARY ADD "box", (20, 20) -> (300, 220) !! solid enclosure
LINE (20, 20) -> (299, 219), 8 !! box

BEHAVIOR "fly"
    IMPULSE 3, 2
    BOUNCE 1, 1
END BEHAVIOR

ENABLE SPRITE 0
SET SPRITE 0 !! image("ball") x(100) y(60) solid behavior("fly")
SHOW SPRITE 0
PAUSE

IMPULSE 3, 2 is a push, once, when the behavior starts, and the ball keeps the speed it was given. BOUNCE 1, 1 turns it around when it runs into something solid, and keeps all of its speed: BOUNCE 0.8, 0.8 would lose a fifth of it at every bounce.

Crash-tan’s Tip: VELOCITY sets the speed again every tick, so a sprite with VELOCITY can’t be turned around by a bounce. For things that bounce, push them with IMPULSE.

Finding out

ONCOLLISION, inside a behavior, runs when a sprite with that behavior touches something. It’s given who it is (me), what it touched (other, a sprite’s number, or -1 for a boundary), the other thing’s tag (other_tag), and for a boundary, which edge of it was hit. It runs on my tick, beside your program, so here it only counts, and the loop does the drawing.

SCREEN 320, 240
MEMORYBUFFER "ball", 12, 12
    CIRCLE (6, 6), 5, 15, 15
END MEMORYBUFFER

BOUNDARY ADD "box", (0, 0) -> (320, 240) !! solid enclosure
hits = 0
last = ""

BEHAVIOR "fly"
    IMPULSE 4, 3
    BOUNCE 1, 1
    ONCOLLISION
        hits = hits + 1
        last = edge
    END ONCOLLISION
END BEHAVIOR

ENABLE SPRITE 0
SET SPRITE 0 !! image("ball") x(160) y(120) solid behavior("fly")
SHOW SPRITE 0
DO
    IF COOLDOWN(1)
        FRAME
            CLS
            LOCATE 1, 1
            PRINT "hits:", hits, "  last edge:", last
        END FRAME
    END IF
LOOP

Sprites touching sprites

Two sprites don’t have to be solid to touch. I tell them whenever they overlap. AFTERCOLLISION runs when they come apart again.

SCREEN 320, 240
MEMORYBUFFER "blue", 16, 16
    LINE (0, 0) -> (15, 15), 9 !! box fill
END MEMORYBUFFER
MEMORYBUFFER "red", 16, 16
    LINE (0, 0) -> (15, 15), 12 !! box fill
END MEMORYBUFFER
TOSPRITESHEET "block", ["blue", "red"]

BEHAVIOR "slide"
    VELOCITY PARAM("vx", 1), 0
    ONCOLLISION
        IF other >= 0 THEN SET SPRITE me !! frame(1)
    END ONCOLLISION
    AFTERCOLLISION
        IF other >= 0 THEN SET SPRITE me !! frame(0)
    END AFTERCOLLISION
END BEHAVIOR

ENABLE SPRITE 0
SET SPRITE 0 !! image("block") frame(0) x(20) y(112)
    !! behavior("slide") behavior_params({vx: 1})
SHOW SPRITE 0
ENABLE SPRITE 1
SET SPRITE 1 !! image("block") frame(0) x(284) y(112)
    !! behavior("slide") behavior_params({vx: -1})
SHOW SPRITE 1
PAUSE

The blocks are blue, turn red while they overlap, and go blue again once they’ve passed through each other.

Crash-tan’s Tip: Being shown and being solid have nothing to do with touching. A hidden sprite still touches things, and a sprite that isn’t solid still hears about every overlap. Solid only means it can’t go through.

Asking instead

Sometimes you just want to know, right now, from your own loop. spritetouching(0, "TOP") says whether sprite 0 is up against the top of a boundary (standing on a floor, say), and gives the boundary’s tag, or "". point_in_box(x, y, left, top, width, height) asks whether a point is inside a box, which is handy for clicking on things.

SCREEN 320, 240
DO
    IF COOLDOWN(1)
        over = point_in_box(mousex, mousey, 110, 90, 100, 60)
        shade = 9
        IF over THEN shade = 12
        MEMORYBUFFER "button"
            LINE (110, 90) -> (210, 150), shade !! box fill
        END MEMORYBUFFER
        FRAME
            CLS
            PUTIMAGE (0, 0), "button"
        END FRAME
    END IF
LOOP