webdevpuneet.com

Tank Arena Game — HTML Canvas Top-Down Shooter in JS

Tank Arena 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, 7 days free), 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

Hull and turret aim
Independent rotation with shortest-angle easing, driven by keyboard, mouse or twin touch sticks, plus a raycast laser sight.
Ricocheting shells
Sub-stepped bullets bounce once off steel and the edge by comparing tile coordinates, damage bricks, cancel each other and have fading trails.
Destructible arena
Steel, cracking brick and crates, generated as mirrored layouts and validated with a flood fill so every spawn is reachable.
Four enemy types with real AI
Scout, gunner, heavy and boss tanks keep a preferred range, strafe, lead their shots and path around walls with a breadth-first flow field.
Power-ups and combos
Repair, rapid fire, shield and triple spread drops, plus a kill-chain multiplier up to x4 with floating score popups.
Waves and bosses
Formula-driven waves with a spawn queue, warning rings, a cap of six enemies at once and a boss every fifth wave.
Persistent ground layer
Tracks, scorch marks and rubble are painted once onto an off-screen canvas, which keeps the battlefield detailed and cheap to draw.
Sound, pause and mobile
Web Audio effects with a saved mute, auto-pause on blur, scroll-safe keys, devicePixelRatio rendering and a saved high score.

About this UI Snippet

Tank Arena — A Top-Down Tank Shooter with Ricochets, Enemy Pathfinding, Power-Ups and Twin-Stick Controls

Screenshot of the Tank Arena Game snippet rendered live

Top-down tank battles are a classic because the rules are instantly readable: drive, aim, shoot, use cover. This snippet builds a complete, polished one on a single HTML5 <canvas>: a destructible arena, free 360° aiming, shells that ricochet, four enemy types that navigate around walls and lead their shots, power-ups, a boss every fifth wave, combo scoring, synthesized sound and mouse, keyboard or twin-stick touch input.

Drive, aim and fire independently

The tank has a hull and a turret that rotate separately, like a real twin-stick game. WASD or the arrow keys (or the left stick) drive the hull, which turns smoothly toward the direction of travel with angDiff, a shortest-angle helper that avoids spinning the long way round. The turret eases toward the mouse position, the right stick, or the hull direction if no aim input exists, so the game is playable with a keyboard alone. A dashed laser sight is raycast from the barrel to the first wall, which shows exactly where a ricochet will start.

A tile arena that is fair and destructible

The map is a 16×16 grid with steel (indestructible), brick (three hits, with cracks that grow as it takes damage) and crates (one hit, 60% chance of a power-up). Every wave generates a new layout on the left half and mirrors it, so neither side has an advantage, then a flood fill checks that every enemy spawn can still reach the player and regenerates the map if steel has walled anything off. Movement collision is circle-versus-rectangle using the nearest point on each tile, resolved one axis at a time so tanks slide along walls instead of sticking.

Shells that ricochet, with sub-stepping

Shells move in sub-steps of about 4 px so a fast bullet can never tunnel through a wall. When a shell enters a solid tile the code compares the previous and current tile coordinates to decide which axis to flip, so it bounces off steel and the arena edge exactly once; hitting a brick damages it and ends the shell. Opposing shells cancel each other on contact, and friendly fire is off. Each shell draws a short fading trail and a glow.

Enemies that find their way

Scouts are fast and fragile, gunners are balanced, heavies carry five hits and fire two-shell bursts, and the boss fires a five-shell fan. Every tank runs the same loop. If it has a clear line (a raycast through the grid) it holds a preferred range, closing in when far, backing off when near and strafing in between. If the player is hidden it follows a breadth-first flow field, a distance map from the player's tile that is rebuilt every 0.35 seconds or when a wall breaks, always stepping to the neighbour with the lowest distance. Shots lead the target using distance / bulletSpeed and the player's velocity, fire only when the barrel is within about 20° of the target, and a small stuck detector nudges a tank that stops making progress.

Waves, power-ups and combos

Waves are generated from a formula (more gunners, then scouts, then heavies, and a boss on every fifth wave) and enemies are released through a spawn queue with a short warning ring, capped at six alive at a time. Power-ups drop from some kills and crates: repair, rapid fire, shield and triple spread. Kills within three seconds of each other build a combo multiplier up to x4.

Juice, sound and mobile support

Tracks, scorch marks and brick rubble are painted onto a persistent off-screen ground canvas instead of being redrawn, so they cost almost nothing. Muzzle flashes, sparks, smoke, shockwave rings, screen shake and a red hit flash sell every impact. Sound effects are synthesized with the Web Audio API, with a saved mute toggle, and the game pauses on blur or a hidden tab. Touch players get two on-screen sticks built from Pointer Events, with the aim stick firing automatically while it is pushed. The canvas is scaled by devicePixelRatio for sharp lines, and prefers-reduced-motion disables screen shake. For more canvas games see the Dodge the falling blocks game and the Asteroids Blaster game.

Step by step

How to Use

  1. 1
    DeployClick "Deploy" (or press Enter or Space). The title screen shows tanks idling in a freshly generated arena. Wave 1 starts with a banner and a short spawn warning for each enemy.
  2. 2
    Drive and aimDrive with WASD or the arrow keys and aim with the mouse. The turret follows the crosshair and a dashed laser shows where your shell will go. On a phone use the left stick to drive and the right stick to aim.
  3. 3
    Fire and use ricochetsHold the mouse button or Space (the right stick fires automatically). Shells bounce once off steel and the arena edge, so you can hit tanks hiding behind cover. Enemy shells ricochet too.
  4. 4
    Break cover and collect power-upsBricks crack after three hits and crates break in one, sometimes dropping a power-up: repair, rapid fire, shield or triple spread. Drive over them to collect them.
  5. 5
    Chain killsDestroy tanks within three seconds of each other to raise the combo multiplier up to x4. Heavy tanks need five hits, and every fifth wave brings a boss.
  6. 6
    Pause, mute and beat your bestP or Esc pauses and M mutes. You have five armour pips. Your best score is saved in localStorage under tank-arena-best.

Real-world uses

Common Use Cases

Twin-stick touch control template
The two Pointer Event sticks (move and aim-and-fire) are a reusable pattern for any top-down shooter on mobile. Compare with the thumb controls in the Asteroids Blaster game.
Teaching game AI basics
Line-of-sight raycasts, a breadth-first flow field, preferred-range steering, strafing and target leading are the foundations of simple enemy AI, shown in a small readable codebase.
Starting point for a bigger shooter
The tile grid, circle-versus-tile collision and wave spawner extend to more enemy types, mines, turrets, upgrades or two-player modes without touching the main loop.
Instantly playable arcade demo
A self-contained shooter with no assets starts immediately, a strong embeddable demo for a games portal, blog or landing page. For a quieter puzzle try the Maze runner game.
Interactive 404 or loading filler
With no network dependency it makes an engaging distraction on an error page, like the Dodge the falling blocks game.
Canvas techniques reference
A persistent ground layer, glow, particles, screen shake and procedural map generation with mirroring and validation are reusable in any 2D canvas scene.

Got questions?

Frequently Asked Questions

A breadth-first search starts from the player's tile and gives every reachable tile its distance from the player. Each hidden enemy steps toward the neighbouring tile with the smallest distance. The map is rebuilt every 0.35 seconds, or immediately when a brick breaks, so enemies route around walls and through new gaps.

Shells move in sub-steps of about 4 px. When a step lands inside a steel tile, the code compares the previous and current tile coordinates: if the column changed it flips the horizontal speed, if the row changed it flips the vertical speed. A shell may bounce once, and bricks absorb it instead.

The generator builds one half and mirrors it, then runs a flood fill from the player's start to every enemy spawn with only steel counted as blocking. If anything is sealed off it throws the layout away and tries again, up to 30 times.

They estimate the shell's travel time as distance divided by shell speed, add the player's current velocity multiplied by that time to the player's position, and aim at that point. Each shot also gets a small random error, larger for scouts.

Each stick is an element with a knob. On pointerdown it captures the pointer, and on every move it converts the offset from the centre into a vector clamped to the stick radius. The left stick feeds the driving vector, and the right stick sets the aim angle and fires while pushed past 30%.

Drawing them every frame would cost more as they accumulate. Painting each mark once onto an off-screen canvas and copying that canvas under the scene each frame keeps the cost flat, and the layer is cleared when a new wave builds a new map.

Yes. The best score is stored in localStorage under tank-arena-best and read on load, wrapped in try/catch so the game still runs where storage is blocked.

Render the canvas and overlays, create the context in a mount effect and run the requestAnimationFrame loop there, keeping game state in refs. Cancel the loop and remove the key, pointer and visibility listeners in the cleanup. Use the export buttons on this page for the markup and styles.