Skip to content

jengine-platformer

Platformers: hero feel (coyote time, jump buffering, wall jumps, dash) and level parts on the engine’s character controller.

KindProject package: linked into the builds of the projects that list it
Sourcepackages/jengine-platformer
Version0.1.0
Entry pointjengine_platformer::PlatformerPackage
Script namespacePlatformer
Listed byprojects/arcade-classics

List it in the top-level "packages" array of project.jengine:

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

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 Platformer == nil then return end.

Scene keyRust type
platformer_heroPlatformerHeropackage only: needs a v2 scene
platformer_walkerWalkerpackage only: needs a v2 scene
platformer_moverMoverpackage only: needs a v2 scene
platformer_crumbleCrumblepackage only: needs a v2 scene
platformer_springSpringpackage only: needs a v2 scene
platformer_pickupPickuppackage only: needs a v2 scene
platformer_hazardHazardpackage only: needs a v2 scene
platformer_checkpointCheckpointpackage only: needs a v2 scene
platformer_goalGoalpackage 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
Platformer.input(e, x, jump, jump_held, down, dash)plat_input
Platformer.respawn(e)plat_respawn
Platformer.freeze(e, frozen)plat_freeze
  • projects/arcade-classics/assets/scenes/hollow.scene
  • projects/arcade-classics/assets/scenes/peak1.scene
  • projects/arcade-classics/assets/scenes/peak2.scene
  • projects/arcade-classics/assets/scenes/peak3.scene
  • projects/arcade-classics/assets/scenes/rain1.scene
  • projects/arcade-classics/assets/scenes/rain2.scene
  • projects/arcade-classics/assets/scenes/rain3.scene

From packages/jengine-platformer/README.md.

A platformer hero that feels right to run and jump with, and the things a level is made of. The collision is the engine’s: everything that moves here is a kinematic body with a character_controller, and the level is a tilemap with a tilemap_collider.

Used by projects/arcade-classics (Pebble Peak). Engine Test Lab scene 81 covers the engine half.

ModuleWhat it is
heroThe feel: acceleration, coyote time, jump buffering, variable jump height, wall slides and wall jumps, an air jump, a dash, and running along slopes. A pure function of the input and the controller’s report.
libThe level’s parts and what happens when the hero meets them, the script commands, and what it publishes.

Hero::step takes the player’s intent and what the controller reported after the last physics step, and answers with the velocity to ask for next. Every rule in it is one a platformer needs to feel fair:

  • Acceleration, not instant speed, and a stronger push when turning around.
  • Coyote time (0.1 s): a jump just after running off a ledge still jumps.
  • Jump buffering (0.12 s): a jump pressed just before landing happens on landing.
  • Variable height: letting go early cuts the rise to 45%.
  • A heavier fall than the rise, and a capped fall speed.
  • Wall slides while pushing into a wall, and wall jumps off it, with a moment where the stick cannot pull you back into it.
  • One air jump and one dash, both back when you land.
  • Slopes: on the ground the hero runs along the surface, so uphill is as quick as the flat.
  • Down + jump drops through a one-way platform.

The defaults suit 32-unit tiles: a jump clears about 4 tiles of height and 6 of distance. They are all fields of Feel on the component.

ComponentIs
platformer_heroThe player. Feel, hearts, damage, knockback, death and respawn.
platformer_walkerAn enemy that patrols, turning at walls and at ledges. Stomp it from above; walk into it and you are hurt.
platformer_moverA kinematic platform that travels a path of points, back and forth or round a loop. The engine carries whoever stands on it.
platformer_crumbleA platform that shakes when stood on, falls away, and comes back.
platformer_springLaunches the hero upward.
platformer_pickupA coin, a gem or a heart, collected on touch.
platformer_hazardSpikes and the like: hurts, or kills outright.
platformer_checkpointWhere the hero comes back after dying.
platformer_goalThe end of the level.

Pickups, hazards, walkers, springs, checkpoints and goals are sensors: the hero’s controller reports them in touching without being stopped by them. Put enemies on their own collision layer and leave that layer out of the hero’s collider filter, so they never block each other (Pebble Peak uses layer 4 for them).

Death is not the end of a run: the hero loses its hearts, dies, and is put back at its last checkpoint with them all back. Falling below kill_y does the same. A game that wants lives counts the died events.

CallDoes
Platformer.input(e, x, jump, jump_held, down, dash)This frame’s input: x is -1 to 1, the rest are flags. Send it every frame.
Platformer.respawn(e)Back to the last checkpoint, healed.
Platformer.freeze(e, frozen)Stops the hero: a menu, a cutscene, the end of a level.

PlatformerState on the hero, every frame: pose (idle, run, jump, fall, wall, dash, hurt, dead, goal), facing, grounded, vx, vy, hearts, max_hearts, coins, gems, invulnerable, frozen, goal, dead, checkpoint and air_jumps.

PlatformerEvents.events on the hero: jump, air_jump, wall_jump, land (with its impact), dash, drop, collect (with item, value and where), stomp, spring, hurt, died, respawn, checkpoint, goal, and shake / crumble / restore for the crumbling platforms.

PlatformerWalker on each walker: dir and dead, for the sprite.

  • src/hero.rs, with no physics at all: acceleration and turning, coyote time and the jump buffer, the cut-short jump, wall slides and wall jumps, one air jump and one air dash, running up a slope, and dropping through.
  • tests/level.rs, on the engine’s real physics, one frame at a time in the order the runtimes run: running and jumping, collecting a coin and hitting a spring, stomping a walker and being hurt by one, walkers turning at ledges, a crumbling platform falling and coming back, riding a moving platform, dying on spikes and in a pit and coming back at the checkpoint, and the goal.