jengine-tanks
Toy tanks: shells that ricochet off walls, mines that blow cork, tanks that aim by the rebound and dodge, a campaign of missions each proved by a bot, and versus rounds - one fixed-step sim for a local game and a server room.
| Kind | Project package: linked into the builds of the projects that list it |
| Source | packages/jengine-tanks |
| Version | 0.1.0 |
| Entry point | jengine_tanks::TanksPackage |
| Script namespace | Tanks |
| Listed by | projects/shooter-classics |
Using it
Section titled “Using it”List it in the top-level "packages" array of project.jengine:
{ "packages": [ { "name": "jengine-tanks", "source": { "type": "path", "path": "../../packages/jengine-tanks" } } ]}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 Tanks == nil then return end.
Components
Section titled “Components”| Scene key | Rust type | |
|---|---|---|
tanks_battle | TanksBattle | 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 |
|---|---|
Tanks.setup(e, setup) | tanks_setup |
Tanks.retry(e) | tanks_retry |
Tanks.control(e, seat, mx, my, aim, fire, mine) | tanks_control |
Tanks.auto(e, seat, on) | tanks_auto |
Tanks.speed(e, x) | tanks_speed |
Scenes that use it
Section titled “Scenes that use it”projects/shooter-classics/assets/scenes/tanks.scene
From packages/jengine-tanks/README.md.
Wii Play Tanks’ rules as one deterministic fixed-step simulation: tanks on a
tabletop of wooden and cork blocks and holes, shells that ricochet, mines
that blow cork apart, and bots that aim by the rebound - tracing shots off
the walls through the very step a shell flies by - and step out of a shell’s
way. One copy of the rules runs a local game (through the tanks_battle
component and Tanks.* commands) and a server room (which owns a
sim::Battle outright), so a versus round online is the round at home.
Used by Shooter Classics’ TOY TANKS (projects/shooter-classics, the
tanks scene) and its online versus room
(projects/shooter-classics/server/games/tanks).
| Module | What it is |
|---|---|
map | The table: an ASCII drawing (. floor, # wood, x cork, o hole, 1-4 people, a letter per enemy kind), the world geometry, pushing a tank’s circle out of what it cannot enter. |
sim | Battle: tanks, shells, mines, events, one 1/60 s step at a time - a campaign mission (people against the table) or a versus round (everyone against everyone). Body::substep is the one place a shell’s flight is worked out. |
ai | Brain: rebound aiming over the shell step (a straight line to each enemy, and for a kind that looks round walls a fan of angles all the way round, against where each enemy will be when the shell arrives), dodging, mine avoidance, goal cells and breadth-first paths, at three levels. The same brain is a person’s advisor: what the attract demo drives and a test pilot presses. |
content | The ten kinds of tank, the campaign’s 24 missions and four versus arenas. |
The rules
Section titled “The rules”- A tank drives the way the stick points, turning its hull first (either end leads); the turret aims on its own. Blocks, holes, the table’s rim and other tanks stop it.
- A shell flies straight and flips the component of its velocity that crossed into a wall; each kind has a number of bounces (a person’s shells one, teal and black rockets none, green rockets two), and the next wall spends it. A shell fired point-blank into a block is spent at the muzzle. Two shells that meet cancel. One shell kills any tank it touches - its own too.
- A person has at most five shells in flight and two mines down. A mine arms once its layer has driven clear, then goes off half a second after any tank comes near, at the end of a twelve-second fuse, or when a shell hits it. Its blast kills tanks, spends shells, sets off other mines and breaks cork.
- A mission is cleared when every enemy is destroyed and failed when every
person’s tank is. A retry (
Tanks.retry) keeps the destroyed enemies destroyed, as the original does. A versus round ends when one team (or none) is left.
The kinds
Section titled “The kinds”| Kind | Letter | Moves | Shell | Notes |
|---|---|---|---|---|
| brown | b | never | 1 bounce, slow | turns its turret slowly, aims only straight |
| ash | a | slowly | 1 bounce | looks one wall round |
| teal | t | slowly | fast rocket, no bounce | |
| yellow | y | quickly | 1 bounce | lays mines |
| pink | p | slowly | 1 bounce | three shells, fast reload |
| green | g | never | fast rocket, 2 bounces | the sniper: looks two walls round, precise |
| violet | v | quickly | 1 bounce | five shells, mines, dodges well |
| white | w | yes | 1 bounce | invisible - seen only when it fires (and by its treads) |
| black | k | fastest | fast rocket | dodges almost everything, leads its aim |
Component ("version": 2 scenes)
Section titled “Component ("version": 2 scenes)”tanks_battle on one entity: mode ("mission" or "versus"), mission
(0-based), arena (versus, 0-based), people (1, or 2 for co-op), level
(1 rookie, 2 veteran, 3 ace), bots (versus: one per seat, true for a bot),
auto (the people’s seats driven by their advisors - an attract demo),
advise (publish the advisor’s keys for each person), speed, seed,
dead (mission starts already destroyed).
Script commands
Section titled “Script commands”| Call | Does |
|---|---|
Tanks.setup(e, table) | change any field above and start that battle (dead is forgotten unless the table names it) |
Tanks.retry(e) | the same mission again, its destroyed tanks left out |
Tanks.control(e, seat, mx, my, aim, fire, mine) | a person’s stick (-1..1, y up), turret aim (radians) and presses - a press waits for the next step |
Tanks.auto(e, seat, on) | hand a person’s seat to its advisor, or take it back |
Tanks.speed(e, x) | run at x times speed |
What scripts read
Section titled “What scripts read”TanksState, every frame -phase(intro,fight,over),intro(the countdown),result(cleared,failed,win,draw),winner,name,left(enemies),rev(which build this state is from - wait for it to change after a setup),mission,missions,mode,level, and the compact listsBattle::viewwrites, the same a server room sends:tanks[x, y, heading, turret, alive, visible, kind, team, seat, ready],shells[id, x, y, vx, vy, rocket, bounces_left],mines[id, x, y, blink, fuse, armed](fusethe seconds left - what a mine’s countdown is drawn from). Withadvise,adviceper person:{ seat, keys, aim, ax, ay }-keysthe lettersW A S D(stick),F(fire),M(mine),ax, aya world point to aim at.TanksArena, when a battle starts or a block breaks -cols,rows,cell,cells(ASCII rows),name,rev.TanksEvents.events, this frame’s:go,fire(x, y, a, tank, rocket),bounce,puff,clash,kill(tank, by, x, y, kind, how, seat, anddx, dy: the way the blow drove it, for debris to fly),mine,arm(a mine’s layer has driven clear),boom,cork(c, r, x, y),over(result, winner). Events only describe - nothing in the rules reads them.
What the tests prove
Section titled “What the tests prove”cargo test -p jengine-tanks: the geometry (cells, push-out, a shell’s
bounce and its spending), the rules (a shell kills its own tank after a
bounce, shells cancel, a mine arms and breaks cork, a retry keeps the dead
dead), that the AI’s traced line is the line a real shell flies, that the
three levels rank in versus, and that every campaign mission is cleared by
the advisor playing the person’s seat within the lives the campaign gives.
The sim uses the platform’s sin/cos, so it is deterministic on one machine
(a room is authoritative, so nothing compares two machines’ bits).