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

Layers in depth

You met layers back in Drawing on the screen: sheets of glass, one above the other, each with its own drawing. They can do a lot more than sit there. A layer can fade, hide, show only a window of itself, slide, repeat forever, and even lie down flat like a floor.

Making layers

Layer 0 is always there. CREATE LAYER makes another, with a number and a size, and a bigger number sits above a smaller one. Sprites go on top of them all.

SET LAYER says which layer drawing goes to from now on. For a few lines of drawing on another layer, WITH LAYER is tidier: inside the block, drawing goes to that layer, and after it, I go back to the one you were on.

SCREEN 320, 240
LOADIMG "city.png", "city"
LOADIMG "hero.png", "tan"
CLS 1
CREATE LAYER 1, 320, 240
CREATE LAYER 2, 320, 240
WITH LAYER 1
    PUTIMAGE (32, 0), "city"
END WITH LAYER
WITH LAYER 2
    PUTIMAGE (140, 184), "tan"
END WITH LAYER
PRINT "blue on 0, city on 1, the hero on 2"
blue on 0, city on 1, the hero on 2

A new layer starts out see-through, so the blue of layer 0 shows down the sides of the city, and the city shows around the hero.

Crash-tan’s Tip: CLS on a layer clears it to solid black, which hides everything under it, sprites included if it’s the top one. Clear the bottom layer, and leave the ones above for things that stay put or that you draw once.

How a layer shows

SET LAYER takes modifiers that change how a layer shows, without touching what’s drawn on it. alpha makes the whole layer see-through, from 0 to 1. visible(FALSE) hides it and visible shows it again. clip shows only the part of it inside a rectangle of the screen, given as two corners with -> between them.

Here, the city on layer 1 shows only through a window that slides back and forth, and a red warning stripe on layer 2 blinks on and off:

SCREEN 320, 240
LOADIMG "city.png", "city"
MEMORYBUFFER "stripe", 320, 16
    LINE (0, 0) -> (319, 15), 4 !! box fill
END MEMORYBUFFER

CREATE LAYER 1, 320, 240
WITH LAYER 1
    PUTIMAGE (0, 0), "city" !! scale_to((320, 240))
END WITH LAYER
CREATE LAYER 2, 320, 240
WITH LAYER 2
    PUTIMAGE (0, 200), "stripe"
END WITH LAYER
SET LAYER 2 !! alpha(0.7)

x = 0
dx = 2
shown = TRUE
DO
    IF COOLDOWN(1)
        x = x + dx
        IF x <= 0 OR x >= 220 THEN dx = -dx
        SET LAYER 1 !! clip((x, 40) -> (x + 100, 190))
    END IF
    IF COOLDOWN(30)
        shown = NOT shown
        SET LAYER 2 !! visible(shown)
    END IF
LOOP

SET LAYER 1 !! clip(...) makes layer 1 the one drawing goes to as well, so if your loop draws too, say which layer you mean first. SET LAYER 1 !! clear_clip shows the whole layer again.

Sliding along

SET SCROLL slides the current layer, by x across and y down, and getscroll gives back where a layer has been slid to: the current one, or the one whose number you give it.

SCREEN 320, 240
CREATE LAYER 1, 320, 240
WITH LAYER 1
    SET SCROLL 40, 10
END WITH LAYER
PRINT "layer 0:", getscroll(0), " layer 1:", getscroll(1)
layer 0: (0, 0)  layer 1: (40, 10)

Slide a layer far enough and you run off the end of its picture. wrap_x fixes that: the layer repeats, side by side, forever. The city is 256 pixels across, so here it repeats every 256 pixels and never runs out.

SCREEN 320, 240
LOADIMG "city.png", "city"
CREATE LAYER 1, 256, 256
SET LAYER 1 !! wrap_x
PUTIMAGE (0, 0), "city"
x = 0
DO
    IF COOLDOWN(1)
        x = x + 1
        SET SCROLL x, 0
    END IF
LOOP

The layer is the city’s size, not the screen’s, so it wraps right where the picture ends. wrap_y does the same up and down.

Far away and close by

Look out of a train window: the hills far away hardly move, and the posts by the track whip past. Scroll layers at different speeds and you get the same thing. That’s parallax, and it’s the cheapest way I know to make a flat game look deep.

The city goes on layer 1 and moves at a quarter of the speed. A street of my own, with a lamp post, goes on layer 2 at full speed. Both wrap. The hero stands on the street as a sprite, and the arrow keys walk them along.

SCREEN 320, 240
LOADIMG "city.png", "city"
LOADIMG "hero.png", "tan"
MEMORYBUFFER "street", 160, 240
    LINE (0, 200) -> (159, 239), 8 !! box fill
    LINE (0, 200) -> (159, 203), 7 !! box fill
    LINE (78, 110) -> (81, 199), 7 !! box fill
    CIRCLE (80, 106), 6, 14, 14
END MEMORYBUFFER

CREATE LAYER 1, 256, 256
SET LAYER 1 !! wrap_x
PUTIMAGE (0, 0), "city"
CREATE LAYER 2, 160, 240
SET LAYER 2 !! wrap_x
PUTIMAGE (0, 0), "street"

ENABLE SPRITE 0
SET SPRITE 0 !! image("tan") x(140) y(160)
SHOW SPRITE 0

x = 0
DO
    IF COOLDOWN(1)
        IF keydown("Right") THEN x = x + 3
        IF keydown("Left") THEN x = x - 3
        WITH LAYER 1
            SET SCROLL x / 4, 0
        END WITH LAYER
        WITH LAYER 2
            SET SCROLL x, 0
        END WITH LAYER
    END IF
LOOP

Click the screen and hold an arrow key. The hero stays in the middle and the world goes by: the lamp posts quickly, the city slowly. Put another layer in between at half the speed, and it looks deeper still.

Lying down flat

A layer can be a plane: a picture I turn, zoom, and even lay down like a floor going off into the distance. The old consoles called it Mode 7.

SET LAYER 1 !! plane("affine") makes layer 1 a flat plane that turns and zooms. SET SCROLL then says which point of the layer is in the middle of the screen, and its !! angle turns the layer that many degrees about it. zoom is how much of the layer fits on the screen: zoom(2) shows twice as much, so everything looks half the size.

SCREEN 320, 240
LOADIMG "city.png", "city"
CREATE LAYER 1, 256, 256
SET LAYER 1 !! plane("affine") zoom(1) wrap_x wrap_y
PUTIMAGE (0, 0), "city"
turn = 0
DO
    IF COOLDOWN(1)
        turn = turn + 1
        SET LAYER 1 !! plane("affine") zoom(1.5 + sin(turn / 40))
        SET SCROLL (128, 128) !! angle(turn)
    END IF
LOOP

With wrap_x and wrap_y, the city repeats in every direction, so there’s never an edge to see however far out it zooms.

plane("perspective") lays the layer down as a floor. horizon is the screen row where the floor meets the sky, and above it the layer is see-through. height is how high the camera is over the floor: higher, and you see more of it at once. SET SCROLL is now where the camera stands on the layer, and angle is which way it faces.

Here’s a checkered floor, built in a MEMORYBUFFER and repeated forever, with the city behind it on layer 0. Up drives forward, and Left and Right turn.

SCREEN 320, 240
LOADIMG "city.png", "city"
PUTIMAGE (0, 0), "city" !! scale_to((320, 240))
MEMORYBUFFER "checks", 64, 64
    LINE (0, 0) -> (31, 31), 5 !! box fill
    LINE (32, 32) -> (63, 63), 5 !! box fill
    LINE (32, 0) -> (63, 31), 13 !! box fill
    LINE (0, 32) -> (31, 63), 13 !! box fill
END MEMORYBUFFER

CREATE LAYER 1, 64, 64
SET LAYER 1 !! plane("perspective") horizon(100) height(64) wrap_x wrap_y
PUTIMAGE (0, 0), "checks"

heading = 0
cx = 0
cy = 0
DO
    IF COOLDOWN(1)
        IF keydown("Left") THEN heading = heading + 2
        IF keydown("Right") THEN heading = heading - 2
        IF keydown("Up")
            cx = cx - sin(heading * pi / 180) * 3
            cy = cy + cos(heading * pi / 180) * 3
        END IF
        SET SCROLL (cx, cy) !! angle(heading)
    END IF
LOOP

angle is in degrees, and sin and cos work in radians, so pi / 180 turns one into the other. The camera faces down the layer when heading is 0, and the two lines under keydown("Up") move it a step whichever way it’s facing.

Crash-tan’s Tip: Give SET SCROLL its angle every time on a plane. Leave it out and the angle goes back to 0. plane("flat") makes the layer an ordinary one again.

Putting them away

FREE LAYER throws a layer away, drawing and all. RESET LAYERS throws away every layer but 0, and goes back to drawing on 0: handy between levels, when the next one wants layers of its own.

SCREEN 320, 240
CREATE LAYER 1, 320, 240
CREATE LAYER 2, 320, 240
CREATE LAYER 3, 320, 240
FREE LAYER 3
PRINT "layer 3 is gone"
RESET LAYERS
PRINT "only layer 0 is left"
layer 3 is gone
only layer 0 is left