webdevpuneet.com

Pixel Platformer Game: 3 Levels, Enemies & Checkpoints

Pixel Platformer Game · Games · Plain HTML, CSS & JS · Live preview

CategoryGames

For supporters

Source Code

Want the source code?

Play the game for free. Become a WebDevPuneet supporter to unlock the complete HTML, CSS and JavaScript source code, the exports (HTML, React, Vue, Angular, Tailwind) and Fork.

Play freeSource code: Patreon

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Three complete levels with different themes (day, sunset, night), parallax mountains, clouds, a sun or a moon with stars
Tile-grid collision resolved one axis at a time, with one-way planks, solid bricks and spikes
Coyote time, jump buffering and variable jump height for a platformer that feels fair
Stompable mushroom walkers that turn at walls and edges, plus sine-wave bats
Springs, checkpoints, 3 lives, score, level bonus and a best score saved in localStorage
Pixel sprites drawn from character strings: no images to load, with animated running, jumping and squash and stretch
Particles, floating score text, screen shake and a level-intro banner
Synthesised sound effects with the Web Audio API and a mute button, no audio files
Fixed 1/60 s timestep, an eased follow-camera with look-ahead, and Pointer Events touch controls plus keyboard

About this UI Snippet

Pixel Platformer: Tile Levels, Stomping Enemies and Game Feel on Canvas

Screenshot of the Pixel Platformer Game snippet rendered live

A platformer is the classic proving ground for 2D game programming because a small game has to get several hard things right at once: gravity and collision against a tile map, enemies that can be stomped, a camera that follows the player through a level wider than the screen, and the many small touches that make a jump feel good. This snippet is a complete three-level pixel platformer on a single HTML5 <canvas>, with no libraries and no image files: the sprites are drawn from strings of characters, the sound is synthesised with the Web Audio API, and the levels are plain data. It plays with the arrow keys or A / D and Space, and with an on-screen ◀ ▶ D-pad and JUMP button on a phone.

Levels as data, tiles as a grid

Each level is an object listing ground stretches, one-way planks, brick blocks, spike runs, coins, walkers, bats, springs, checkpoints and the goal flag, all in tile coordinates. buildLevel() turns that into a two-dimensional grid of tile types, and everything else (collision, drawing, enemy edge detection) asks the grid with one function, tileAt(column, row). Adding a fourth level means adding one more object to the LEVELS array. The three included levels (Green Hills, Sunset Ridge and Midnight Run) change the colour theme, the sky, the parallax mountains and the difficulty, and the third adds a moon and stars.

Collision that resolves one axis at a time

The player moves horizontally first and is pushed out of any solid tile it overlaps, then moves vertically and is resolved the same way. Resolving one axis at a time is what stops a character from snagging on the seams between tiles. Planks are one-way: they only catch the player when falling and when the bottom edge was above the plank on the previous step, so you can jump up through a plank and land on it from above. Spikes use a hitbox smaller than their tile so near misses feel fair.

Game feel: coyote time, jump buffering and variable jump height

Three small rules separate a platformer that feels fair from one that feels stiff. *Coyote time* lets you still jump for a few frames after running off a ledge. *Jump buffering* remembers a jump press made a few frames before landing, so you never lose a jump by pressing slightly early. *Variable jump height* cuts the upward speed when you release the button, so a tap is a hop and holding the button is a full jump. Landing and jumping also squash and stretch the sprite, and dust, coin sparkles and a short screen shake give each action weight.

Enemies you can stomp

Mushroom walkers patrol the ground and turn around at walls and at the edge of a platform by checking the tile ahead and below them. Bats fly a sine-wave path. Both are defeated by landing on them from above, which bounces you up, and both cost a life if you touch them from the side, followed by a short blinking invulnerability so one mistake is not a chain of deaths. Springs launch you high, and checkpoint flags set where you restart after a fall or a spike.

A fixed timestep, a smooth camera and a synthesised soundtrack

The simulation advances in fixed 1/60-second steps drained from an accumulator, so jump height and run speed are identical on a 60Hz or a 144Hz display and fast falls cannot tunnel through thin planks. The camera eases toward the player with a little look-ahead and is clamped to the level. Sound effects (jump, coin, stomp, hurt, spring, checkpoint and a short win jingle) are generated with oscillators, with a mute button, and your best score is kept in localStorage.

Step by step

How to Use

  1. 1
    Start the gamePress Start (or Enter). You begin level 1 with 3 lives, and a banner shows the level name.
  2. 2
    Run and jumpUse the arrow keys or A / D to run, and Space, the up arrow or W to jump; on a phone use the ◀ ▶ buttons and JUMP. Hold jump for a full jump and tap it for a hop.
  3. 3
    Stomp enemiesLand on a mushroom or a bat to defeat it and bounce. Touching one from the side costs a life, followed by a short moment of invulnerability.
  4. 4
    Collect coins and use checkpointsEach coin is worth 10 points and stomps are worth 50. Passing a checkpoint flag turns it green and sets where you restart after a fall or a spike.
  5. 5
    Reach the flagThe goal flag ends the level. You get a bonus for finishing quickly and for every coin collected, then move on to the next of the three levels.
  6. 6
    Edit the levelsThe LEVELS array near the top of the JS holds every level as data in tile coordinates. Move planks, add spikes or enemies, or add a new level object, and tune GRAV, RUN and JUMP_V to change how the game feels.

Real-world uses

Common Use Cases

Learning platformer game feel
Coyote time, jump buffering and variable jump height are each a few lines here and easy to switch off one by one, so you can feel exactly what they change.
A tile-based level format to build on
Levels are plain data turned into a grid, so adding moving platforms, new enemy types, doors or a level editor builds on the same structure.
Mobile platformer control template
The held run buttons and the discrete, buffered JUMP button, all wired with Pointer Events, are a reusable control scheme for any touch action game.
An instantly playable browser-game demo
With no assets to load the game starts immediately, which makes it a strong embeddable demo for a games site, a portfolio or a landing page.
An interactive 404 page or loading screen
The game has no network dependency, so it works as a distraction on an error page, like the Maze Runner Arrow-Key Game.
Pixel art without image files
Sprites stored as arrays of strings and drawn with fillRect are a tiny, editable way to do pixel art in a canvas game, and the palette can be swapped in one object.
Related: Rock Paper Scissors vs Computer
See the Rock Paper Scissors vs Computer for a related games pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Coyote time gives you a few frames after you walk off a ledge during which a jump still works, and jump buffering remembers a jump pressed a few frames before you land and fires it on touchdown. Both are set by two constants, COYOTE and BUFFER, near the top of the JS. They make the game forgive timing the player could not reasonably see, and setting either to 0 shows how stiff the game feels without it.

Jumping sets a strong upward speed, and while the jump button is held the character rises fully. If the button is released while still moving up faster than JUMP_CUT, the upward speed is clamped to that value, so a quick tap gives a small hop and holding gives a full jump. Bounces from springs and stomps set a flag that skips the clamp.

A variable step lets a fast-falling character move past a thin plank between two frames, and it makes jump height depend on the frame rate. The loop adds the elapsed time to an accumulator and runs update() once for every 1/60 of a second in it, so the game behaves the same on a 60Hz and a 144Hz display, while drawing still happens once per frame.

Each level in the LEVELS array lists ground stretches as [from, to] columns, planks as [column, row, length], bricks as [column, row, width, height], spikes, coins, walkers (column), bats ([column, row]), springs, checkpoints and the flag column. Row 13 is the ground surface. Keep gaps under about 5 tiles or add a plank over them, because a jump covers about 6 tiles.

The sprites are arrays of strings where each character is a colour from the PAL object, drawn as 2x2 squares with fillRect, and flipped by mirroring the column. The sounds are short oscillator tones with a falling or rising frequency, made with the Web Audio API the first time one plays, so there are no image or audio files, and the mute button simply skips them.