Skip to content

jengine-burnline

You are the missile: steer through a neon maze to the target before the fuel runs out, and every missile you lost flies again beside the next.

KindProject package: linked into the builds of the projects that list it
Sourcepackages/jengine-burnline
Version0.1.0
Entry pointjengine_burnline::BurnlinePackage
Script namespaceBurnline
Depends onjengine-tide
Listed byprojects/burnline

List it in the top-level "packages" array of project.jengine, together with every package it depends on: a crate dependency compiles a package in but does not register it, and packages_a_project_lists_cover_their_dependencies fails a project that lists only the outer one:

{
"packages": [
{ "name": "jengine-burnline", "source": { "type": "path", "path": "../../packages/jengine-burnline" } },
{ "name": "jengine-tide", "source": { "type": "path", "path": "../../packages/jengine-tide" } }
]
}

Then rebuild the editor viewport for the project (jengine viewport-build projects/<name>, or the editor’s Rebuild viewport banner). Native and web builds link it on their own.

A scene that uses its components must be a v2 scene ("version": 2): a v1 scene has no field for a package component and keeps it as inert custom data.

A script can check that the package is linked with if Burnline == nil then return end.

Scene keyRust type
burnlineBurnlineGamepackage only: needs a v2 scene

Commands run in every runtime and return nothing; a package publishes what scripts read onto components (see the notes below). The flat name also works.

CallFlat name
Burnline.play(e, level)burnline_play
Burnline.idle(e, level)burnline_idle
Burnline.pause(e, on)burnline_pause
Burnline.demo(e, on)burnline_demo
Burnline.launch(e)burnline_launch
Burnline.retry(e)burnline_retry
Burnline.restart(e)burnline_restart
Burnline.steer(e, dir)burnline_steer
  • projects/burnline/assets/scenes/play.scene

From packages/jengine-burnline/README.md.

Burnline: you are the missile. It flies at one speed, so the only verb is steer. Get it through a neon maze to the target before the fuel runs out, and every missile you lost flies again beside the next one. They break the gates they broke before and draw the fire they drew, so a level is a sequence of missiles: one opens the way, the next goes through. The game is projects/burnline.

The earlier missiles are simulated again, not played back. A run is a pure function of the level and every attempt’s steering, one value per fixed step at 120 Hz (sim::Run). Nothing reads the clock or a random number, so the same inputs give the same run bit for bit. A ghost therefore ends exactly where it ended, unless the new missile changed the level first (killed the turret that shot it, broke a gate it hit). Then the ghost flies on into the level as it now is, which a recording could not do.

Walls are lines, and collide as lines. A missile is a circle swept along its step against every segment (geom::sweep_hit). That is exact at any speed, with no thin collider to tunnel through, so the package needs no physics world.

A level proves itself. Each level carries the author’s routes, one per missile. The autopilot (pilot) flies them with the player’s own steering (left, right or straight, a value a step). Winning on the last route proves the level can be beaten, and that run’s time is the author time shown in the HUD. It is computed when the level loads, so moving a wall can never leave it stale.

Several launchers. Missile n leaves from launcher n, and every missile past the last leaves from the last. A short route to a gate from one launcher and the long way round from the next means the second missile never has to fly a frame behind its ghost. With one shared launcher, a keyboard-flown second missile reached the gate first.

The warping grid behind the arena is jengine-tide’s storm lattice, used unchanged. A project listing this package lists jengine-tide too.

"burnline": { "art": "textures/burnline", "level": 1 }

art is the folder the package’s textures are in (line, spark, glow, missile, turret, launcher, target, white, all .png, drawn white and tinted). level is the level shown before anything is played.

The package reads the keys itself, from the project’s input actions: steer_left, steer_right, launch (on the launcher it launches; after a miss it readies the next missile; after a win it starts over) and restart (start over with no ghosts).

CallDoes
Burnline.play(e, level)open a level (1-based), its missile on the launcher
Burnline.idle(e, level)show a level’s empty arena
Burnline.demo(e, on)the autopilot flies the author routes, launching and retrying by itself (the menu’s background, tests, screenshots)
Burnline.pause(e, on)stop or resume the run
Burnline.launch(e) / Burnline.retry(e) / Burnline.restart(e)what the keys do, for a script or touch controls
Burnline.steer(e, dir)steer this frame (1 left, -1 right), on top of the keys

BurnlineState: ready, phase (idle, ready, flying, won, lost), level, levels, name, names (every level’s name, |-separated), theme, author (seconds, or -1), time, attempt, ghosts, fuel (0 to 1), end (how the live missile ended: wall, gate, turret, beam, fuel, target), gates and turrets (how many still stand), the live missile’s x, y and heading, and adv (which way the author’s route would steer now).

BurnlineEvents, this frame’s: list (names: launch, explode, explode_live, gate, turret, beam, won, lost), won_time, lost (the end’s name) and explosions.

Levels are JSON in levels/, compiled in (level::LEVELS). Each has walls (polylines, closed ones optionally hatched), gates (segments a blast breaks), turrets (fire a beam at the nearest missile they hold in sight for lock seconds), launchers, a target, a fuel time and the author routes. A walls- and-paths picture of every level is two commands:

BURNLINE_DUMP=<dir>/levels.json cargo test -p jengine-burnline dump_author_runs -- --ignored
python projects/burnline/tools/plot_levels.py <dir>/levels.json <dir>
  • every_shipped_level_is_won_by_its_author_routes: every level is beaten, on its last route and not before.
  • the_same_inputs_give_the_same_run_bit_for_bit, and the_author_run_replays_as_ghosts_exactly: a ghost ends where it ended.
  • an_earlier_missile_breaks_the_gate_for_the_next, a_turret_shoots_down_what_it_holds_in_sight, a_fast_circle_does_not_pass_through_a_thin_wall, and the hatching’s concave case.
  • tests/burnline_scene.rs plays the shipped scene through the game’s own Lua with arrow keys: the menu, four levels, a best time saved, and Gatekeeper’s second missile through the gate its ghost breaks again.