CrashNet Server 1.45.0 Release Notes

Crash BASIC 1.45.0 Release Notes

~written by Crash-tan~

THE “LET ASEPRITE DO THE WORK” RELEASE

You already draw your animations in Aseprite. You set the timing on the timeline. You drag a slice box around the hitbox. Then you’d come over to Crash BASIC and… re-type all of it by hand — a FRAMERATE number you eyeballed, a BBOX you measured with your finger on the screen.

Not anymore. 1.45.0 teaches LOADIMG to read the parts of an .ase file it used to throw away, and gives ANIMATE two new words so the animation just uses them.


FRAMERATE OFSPRITE — your timeline timing, honored

Aseprite lets you give every frame its own duration. A long pose, three quick in-between frames, a long pose again. Until now Crash BASIC ignored that completely — ANIMATE only knew one speed for the whole loop.

LOADIMG "hero.ase", "HERO" AS SPRITESHEET(32, 32)

BEHAVIOR "walk"
    ANIMATE "HERO", 0 TO 7 FRAMERATE OFSPRITE
END BEHAVIOR

FRAMERATE OFSPRITE says “use the durations baked into the file.” Frame 0 holds for however long you set it in Aseprite, frame 1 for its own time, and so on — variable per frame, exactly as authored. Re-time the animation in Aseprite, re-export, and your game’s playback updates with it. No magic number to keep in sync.

It needs a real Aseprite load. Point FRAMERATE OFSPRITE at a plain PNG sprite sheet (which carries no per-frame durations) and you halt with a clear message telling you why — not a silently frozen sprite.


AUTOBBOX — the hitbox follows the animation

Draw a slice in Aseprite, animate it across your frames (it’s keyframed, so a punch frame gets a wider box, a crouch frame a shorter one), and AUTOBBOX applies it to the sprite automatically as the animation plays:

LOADIMG "hero.ase", "HERO" AS SPRITESHEET(32, 32)

BEHAVIOR "attack"
    ANIMATE "HERO", 0 TO 5 AUTOBBOX FRAMERATE OFSPRITE
END BEHAVIOR

Every time the animation advances, the bounding box updates to match the slice on that frame. It feeds straight into the existing collision system — boundary pushback, sprite-to-sprite, SPRITECOLLISION(), SPRITETOUCHING$() — so your hitbox is whatever you drew, when you drew it.

AUTOBBOX is independent of FRAMERATE OFSPRITE; combine it with either that or a fixed fps:

ANIMATE "HERO", 0 TO 5 AUTOBBOX FRAMERATE 12   ' fixed speed, animated hitbox

Bare AUTOBBOX uses the file’s first slice. If your file has several slices and the first isn’t the one you want, name it:

ANIMATE "HERO", 0 TO 5 AUTOBBOX "body" FRAMERATE OFSPRITE

A frame that no slice key covers simply leaves the box where it was. Ask for AUTOBBOX on an image with no slices (or a name that doesn’t exist) and you halt loud, with the available slice names listed.


More than one slice? Query the rest by name

A sprite has a single collision box, so AUTOBBOX drives one slice. But an .ase can hold several named slices at once — a body, a sword, a feet point — and you can read any of them on demand for your own (manual) hit checks:

' World-space box of a named slice at the sprite's CURRENT frame:
sword = SPRITEBBOX(player, "sword")     ' (x1,y1)-(x2,y2) in world pixels
body  = SPRITEBBOX(player)              ' no name = the active collision box

' Relative-0-1 box of a slice on a specific frame, no sprite needed:
b = IMAGEBBOX("HERO", "feet", 3)
SET SPRITE 0 BBOX b

SPRITEBBOX(id, name$) gives you world coordinates (sprite position + scale applied), ready to test against other things. IMAGEBBOX(image$, name$, frame) gives the relative box straight from the file. Name a slice that isn’t there and you halt loud, with the available names listed.


LOADIMG … SLICES boxes() — the rectangles, in your hands

Want the slice boxes for yourself instead of (or in addition to) the automatic hookup? Add a SLICES clause and LOADIMG fills an array:

LOADIMG "hero.ase", "HERO" AS SPRITESHEET(32, 32) SLICES boxes()

' boxes(frame) is a (x1,y1)-(x2,y2) Range in relative 0–1 coordinates,
' one entry per frame — keyframes already expanded.
SET SPRITE 0, 100, 100, "HERO"
SET SPRITE 0 BBOX boxes(2)        ' use frame 2's slice as the hitbox

Each element is a Range in relative 0–1 coordinates, ready to drop straight into the new range form of BBOX (below). The array is always dense and frame-indexable — frames with no slice fall back to the full frame (0,0)-(1,1) — so boxes(anyFrame) is always valid.

SLICES is Aseprite-only. Use it on a PNG, or on an .ase with no slices, and you get a loud error rather than a quietly empty array.


TAG("name") — load just one animation

An .ase usually holds every animation in one file — idle, run, jump, all on the same timeline, separated by Aseprite tags. LOADIMG … TAG("name") pulls out just one tag’s frames:

LOADIMG "hero.ase", "HERO_RUN" TAG("run")

BEHAVIOR "running"
    ANIMATE "HERO_RUN", 0 TO 5 FRAMERATE OFSPRITE
END BEHAVIOR

Only the run tag’s frames are loaded, re-indexed from 0 — so ANIMATE … 0 TO 5 just plays the run, no offset math. The per-frame durations and slice boxes come along narrowed to that tag, so FRAMERATE OFSPRITE and AUTOBBOX keep working on it. An .ase already implies a sprite sheet, so you don’t even need AS SPRITESHEET — though you can still add SLICES to grab the tag’s hitboxes.

Want several animations? Load the file once per tag, under different names:

LOADIMG "hero.ase", "HERO_IDLE" TAG("idle")
LOADIMG "hero.ase", "HERO_RUN"  TAG("run")
LOADIMG "hero.ase", "HERO_JUMP" TAG("jump")

Tag names match case-insensitively. Ask for a tag that isn’t in the file (or put TAG on a plain PNG) and you halt loud, with the available tag names listed.


BBOX now takes a Range too

To make those slice rectangles pluggable, SET SPRITE … BBOX learned a second form. Alongside the classic four numbers, you can now hand it a single Range value:

SET SPRITE 0 BBOX(0.2, 0.2, 0.8, 0.8)   ' the form you already know
SET SPRITE 0 BBOX boxes(curFrame)        ' new: a relative-0–1 Range value

Both mean the same thing — a relative-0–1 collision box. The range form just lets you pass one you already have (from SLICES, or built yourself) without unpacking it into four arguments.

While we were in there, range values can now hold fractional coordinates. A range literal like (0.1, 0.2)-(0.8, 0.9) keeps its decimals instead of truncating to whole numbers. Whole-number ranges are completely unchanged — they print and step over the integer grid exactly as before.


Solid boundaries are solid again

Two collision bugs that let a sprite slip through a SOLID boundary are fixed:

Sliding along walls and ceilings is unchanged — only the pass-straight-through cases got closed.


Multiplayer

All of this works the same in single-player and in CrashNet. The Aseprite per-frame durations and slice boxes are read on every interpreter when the file loads, so FRAMERATE OFSPRITE timing and AUTOBBOX hitboxes resolve identically on the server and on each client. Nothing new crosses the wire; just call LOADIMG once at the top of your program as always.


Also in 1.45.0 — arrays, sharper edges, a few new words

The headline is Aseprite, but a batch of language polish rode along.

REDIM keeps your data now

REDIM used to quietly throw away everything in the array and hand you a fresh zero-filled one. Now it preserves what fits: grow an array and your existing elements stay put (the new slots default-fill); shrink it and the elements that remain are kept. There’s no PRESERVE keyword to remember — preserving is just what REDIM does. (Want a clean slate? That’s what DIM and ERASE are for.)

PUSH / POP / QUEUE / DEQUEUE are now explicitly 1-D list operations. Point one at a multi-dimensional array and you get a clear error instead of an array whose shape quietly stops matching its contents.

POLYGON takes an array of points

POLYGON (and its UV clause) already accepted a MUTATION. Now it also takes a plain array of points — coordinate values (x, y), objects with .x / .y, or an N×2 numeric array — so you can build the geometry however is convenient and hand it straight in.

A few new (and newly-documented) functions

Errors where there used to be silence

A few operations that used to fail quietly now stop with a clear message:

Small behavior fixes


Compatibility notes


Draw it once. Let the file remember the timing and the hitbox. Go make a game.

— Crash-tan