Crash-tan Crash-tan

This is about as 3D as it gets here... 1.40.0 is out!

Crash BASIC 1.40.0 Release Notes

written by Crash-tan

THE "GET OFF THE FLOOR" UPDATE

For your entire life with me, the world has been flat. Two numbers — x and
y — and that was the whole story. Sprites slid around on a sheet of glass,
the background was a sheet of glass behind it, and "depth" was something
you faked by drawing things bigger.

No more. As of 1.40.0 the floor tilts, and your sprites can leave it.

This is the big one — a third dimension threaded through the renderer, the
sprites, and the behavior engine all at once. Two halves: plane layers
(a floor that recedes into the distance) and elevation (height off
that floor, with real gravity behind it). Let me show you.

And before you worry: every flat thing you already wrote still works,
unchanged.
All of this is opt-in. A 2D game stays a 2D game and never
pays a cent for the new machinery.


Plane layers: the floor goes 3D

A layer can now be projected into the distance like a tilted plane — the
classic racing-game / RPG-overworld "Mode 7" look. Build a tilemap layer
as usual, then tell it to lie down:

CREATE MAP FROM map TILESET "tiles" TILESIZE 32 AS LAYER 0 WRAPX WRAPY
SET LAYER 0 PERSPECTIVE HORIZON(110) HEIGHT(90)

PERSPECTIVE gives you the full receding-to-a-horizon floor; HORIZON
sets where the ground meets the sky on screen, HEIGHT is your camera's
height above it. Then drive the camera around with scroll + rotation:

SET SCROLL 256, 120 ANGLE(playerHeading)

Pan with the scroll, spin the whole world with ANGLE. If you want a
plain rotate-and-scale floor without the horizon falloff, use AFFINE
instead of PERSPECTIVE — same idea, flat.

What you get for free on a plane layer:

  • Sprites stand on it correctly — they're projected onto the floor
    and scale with distance, near things big, far things small.
  • Depth sorting — sprites draw far-to-near, so closer ones correctly
    cover the ones behind them.
  • Layer alpha works on plane tilemaps, and tile animation keeps
    animating while projected.
  • Your shaders work on it too — custom WGSL shaders apply to plane
    layers (projected, then shaded), so the floor can shimmer, fog, ripple,
    whatever you've got.

Sprites get a height: ELEVATION

Here's the other half. A sprite now has a z — its elevation above the
plane it lives on. Floor is 0; bigger numbers float higher toward the
camera.

SET SPRITE hero ELEVATION(40)        ' lift it 40 units off the floor

Coordinates were already 3D-capable, so LOCATION takes the third number
directly now:

SET SPRITE hero LOCATION(160, 120, 40)   ' x, y, and height in one go

And you can read it back any time:

h = SPRITEELEVATION(hero)

Elevation rides the same per-tick sprite sync as position, so it's smooth
(lerped) over the network and in WASM just like x/y — no popping.


Every motion behavior learned the third axis

The behavior verbs you already use grew an optional z. Old calls are
untouched; the new third value is the elevation axis:

BMOVE 0, 0, 3                       ' drift straight up off the floor
BOSCILLATE AMPLITUDE 0, 0, 20       ' bob up and down (vertical amplitude)
PATH (10,10,0), (50,40,30), (90,10,0)   ' waypoints with height

Plus a dedicated tween, in the BALPHA / BSCALE / BROTATE family:

BELEVATE 0 TO 60 DURATION 30 LOOP   ' rise and fall over 30 ticks, forever

Real vertical physics: gravity, jumps, bounce

The z axis isn't just a number you animate — it's a physics axis.
There's z-velocity, z-acceleration, a ground at elevation 0, and the whole
thing integrates every tick.

So a jump is exactly what a jump should be — one upward kick, and gravity
does the rest:

BEHAVIOR "jump"
  BIMPULSE 0, 0, 16     ' kick straight up...
  BGRAVITY 1            ' ...and fall back down. Lands on the floor on its own.
END BEHAVIOR

BGRAVITY is new — constant downward pull, the everyday way to give a
plane sprite weight. The motion verbs all take their z component now too:
BACCELERATION dx, dy, dz, BVELOCITY vx, vy, vz, BIMPULSE ix, iy, iz,
and BSTOP zeroes the vertical axis along with the rest.

And things can bounce. BBOUNCE got a third coefficient — restitution
off the ground:

BEHAVIOR "ball"
  BGRAVITY 0.4
  BBOUNCE 0, 0, 0.7    ' rebounds at 70% each hit, loses energy, settles
END BEHAVIOR

BFRICTION got a third one too — air resistance on the vertical axis, for
a terminal fall speed (terminal ≈ gravity / z_friction).


Orbits and follows go 3D

BORBIT can now circle in any plane, not just flat on the floor. The
new AXIS clause is the axis of rotation — the normal of the plane the
sprite circles in:

BORBIT (256, 280, 60) DISTANCE 70 AXIS (1, 0, 0)   ' a vertical ring, lifted off the floor
  • AXIS (0, 0, 1) is the default — the flat floor orbit you already had,
    bit-for-bit.
  • AXIS (1, 0, 0) stands the ring up into a vertical wheel.
  • Any tilted vector gives a tilted ring, foreshortened correctly by the
    plane projection.

The center can be 3D too ((x, y, z)) to lift the whole ring, and a ring
of sprites at staggered STARTANGLEs traces a rotating 3D ring. Orbit a
sprite in 3D and it rides that sprite's own height as it jumps.

BFOLLOW gained an ELEVATION clause — now the follower can track
the target's height, not just its x/y:

BFOLLOW 0 DISTANCE 24 SPEED 3 ELEVATION 30   ' a drone hovering 30 units above the target

Compatibility

Nothing breaks. The whole z story is additive:

  • 2D games never set an elevation, never tilt a layer, and behave exactly
    as in 1.39.
  • Default orbit axis is (0, 0, 1) — the old flat orbit, reproduced
    exactly.
  • All the new behavior arguments (the third coordinate, AXIS,
    ELEVATION, BGRAVITY) are optional. Omit them and you get the old
    behavior.
  • Elevation only renders as height on a PERSPECTIVE/AFFINE plane
    layer — off a plane it's just a number, harmless.