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.
| Kind | Project package: linked into the builds of the projects that list it |
| Source | packages/jengine-burnline |
| Version | 0.1.0 |
| Entry point | jengine_burnline::BurnlinePackage |
| Script namespace | Burnline |
| Depends on | jengine-tide |
| Listed by | projects/burnline |
Using it
Section titled “Using it”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.
Components
Section titled “Components”| Scene key | Rust type | |
|---|---|---|
burnline | BurnlineGame | package only: needs a v2 scene |
Script commands
Section titled “Script commands”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.
| Call | Flat 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 |
Scenes that use it
Section titled “Scenes that use it”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.
Why it is built this way
Section titled “Why it is built this way”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.
Component ("version": 2 scenes)
Section titled “Component ("version": 2 scenes)”"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).
Script commands
Section titled “Script commands”| Call | Does |
|---|---|
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 |
What scripts read
Section titled “What scripts read”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
Section titled “Levels”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 -- --ignoredpython projects/burnline/tools/plot_levels.py <dir>/levels.json <dir>What the tests prove
Section titled “What the tests prove”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, andthe_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.rsplays 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.