Description

Arcade-style vertical shooter built with Phaser 3, featuring dynamic scaling, pooled enemies and bullets, touch and keyboard controls, power-ups, and leaderboard-ready gameplay.

Prompt

Build a 1942-style vertical scrolling shooter using Phaser 3. TECHNICAL SETUP: - Use Phaser.Physics.ARCADE (no gravity). - Load Phaser 3.80.1 from CDN: https://cdn.jsdelivr.net/npm/phaser@3.80.1/dist/phaser.min.js (script tag in index.html). - Enable pixelArt: true, roundPixels: true. - All assets generated programmatically using Phaser.Graphics at runtime — NO external image files. - Use Object Pooling for bullets and enemies. - Enable multi-touch: input: { activePointers: 3 } in Phaser config. RESOLUTION & SCALING (CRITICAL): Detect mobile vs desktop via user agent regex: /Mobi|Android|iPhone|iPad|iPod/i MOBILE resolution: - Use window.visualViewport (or window.innerWidth/innerHeight fallback) for accurate dimensions that account for the iOS Safari URL bar. - Canvas aspect ratio = actual screen aspect ratio (NOT forced 3:4). This means on tall phones (~9:19.5), the game world is simply taller — more ocean visible. - Render size = screenW × dpr (capped at 1800px width). - Scale mode: Phaser.Scale.ENVELOP with CENTER_BOTH. - CSS: use 100dvh (NOT 100vh) for the game container height. DESKTOP resolution: - Fixed 3:4 aspect ratio (base 600×800). - Render size based on fitting height: fitW = innerHeight × (600/800), capped at innerWidth, scaled by dpr (max 1800px). - Scale mode: Phaser.Scale.FIT with CENTER_BOTH. Scale factor: S = actualCanvasWidth / 600. Apply S to ALL positions, velocities, sprite scales, font sizes, and collision bounds throughout the entire game. Use helper methods: - gw(): game width - gh(): game height - cx(): center X (gw/2) - sc(v): scales a value by S - fs(v): returns scaled font size string (Math.round(v * S) + 'px') CSS for game container: * { margin: 0; padding: 0; box-sizing: border-box; } html, body { width: 100%; height: 100dvh; overflow: hidden; background: #000; } #game-container { width: 100vw; height: 100dvh; position: fixed; top: 0; left: 0; overflow: hidden; } canvas { display: block; touch-action: none; margin: 0 auto; } Background color: #1e4e8e (Deep Ocean Blue). SOUND (Web Audio API): Create a SoundManager class. CRITICAL: Do NOT init AudioContext during create(). Defer ALL sound initialization to the first user gesture using native DOM events (touchstart, touchend, mousedown, keydown on document). iOS Safari requires AudioContext creation inside a direct user gesture handler. SoundManager methods: - init(): Create AudioContext + master gain (0.3 volume). Guard against double-init. - resume(): If no ctx, call init(). If ctx is suspended, resume it. - shoot(): High-pass filtered noise burst (0.06s, 3000Hz highpass). - enemyHit(): Low triangle wave tone (150Hz, 0.1s). - explode(): White noise with exponential decay (0.4s). - bigExplode(): Low-pass filtered noise (0.7s, 100Hz lowpass). - powerup(): Ascending major arpeggio — 4 tones [523, 659, 784, 1047] Hz, each 0.15s sine, 60ms apart. - loop(): Bandpass filtered whooshing noise (0.3s, 800Hz bandpass). - startBGM(): setInterval every 500ms playing a low noise burst (0.05s, 200Hz lowpass). - stopBGM(): clear the interval. SPRITE GENERATION (BootScene): Generate all textures in a BootScene using Phaser.Graphics before starting GameScene: Player (P-38 Lightning, 40×40): - Silver/grey twin-boom design with two parallel engine booms, nacelles, propeller discs. - Center fuselage with detailed cockpit canopy (blue glass with glint highlight). - Swept wings with US star markings (white circle + blue center). - Tail fins, panel lines, exhaust glow (orange tint at rear). - Physics hitbox: 12×12 centered at offset (14,14) — "shmup hitbox" for fair dodging. Enemy Fighter (Zero, 28×28): - Green tapered fuselage with nose cone. - Wings with rising sun markings (red circles with inner orange glow). - Yellow propeller bar, rudder, cockpit detail (blue canopy). - 15% spawn as red variants that drop powerups. Enemy Bomber (72×56): - Dark green, twin engine nacelles with yellow propeller discs. - Detailed cockpit with glass sections (blue). - Wings with rising sun markings. Bomb bay hint (dark underside). - Twin vertical stabilizers. 10 HP. Player Bullet (4×10): Yellow/orange rounded capsule with gradient highlight and bright tip. Enemy Bullet (8×8): Red orb with orange ring and white center glow. Explosion Particles: 5 types — particle_orange (0xff8800), particle_yellow (0xffff00), particle_white (0xffffff), particle_red (0xff2200), particle_smoke (0x444444). Each 4×4 solid squares. Powerup "POW" (24×24): Red rounded square with outer glow, white "P" letter, highlight strip. Life Icon (12×10): Tiny P-38 silhouette — twin booms, center fuselage, wings, cockpit dot. Ocean Tile (64×64): Deep blue with color variation between halves. Wave crests (lighter blue horizontal lines), foam highlights, darker trough areas. 4 Island Types: - island1 (200×200): Large tropical — shallow water ring (semi-transparent blue ellipse), sandy beach, green jungle interior with dark patches, mountain triangle with highlight. - island2 (120×120): Small atoll — sandy ring with interior lagoon, scattered vegetation. - island3 (150×100): Rocky island — grey/brown terrain, sparse green, cliff highlight. - island4 (40×40): Tiny reef dot — circular with shallow water, sand, small green center. Ocean Decorations: - cloud_shadow (130×65): Dark semi-transparent elliptical shadow (multiple overlapping ellipses). - foam (50×20): White semi-transparent wake patch. - crate (8×8): Brown wooden debris with plank lines. 3 Enemy Naval Ships (drawn horizontally, bow pointing left): - Destroyer (100×24, HP 25, 1000 pts): Grey hull with pointed bow triangle, stern block, superstructure with bridge tower, 3 gun turrets with barrel rectangles, deck detail lines, wake. - Battleship (120×28, HP 50, 2500 pts): Larger hull, pagoda-style bridge tower (layered rectangles), triple-mount main gun turrets front/rear, secondary gun turrets on sides. - Aircraft Carrier (160×40, HP 80, 5000 pts): Wide hull with flight deck overlay, runway markings (dashed white center line, yellow angled deck lines), island superstructure offset to one side with radar mast, 3 tiny aircraft silhouettes on deck, AA gun circles at corners. PLAYER CONTROLS: Keyboard: - Arrow Keys / WASD: Movement at speed 300 (scaled by S). - SPACE: Shoot. Cooldown 150ms. - Z / Shift: Loop barrel roll. Touch/Mobile (CRITICAL — relative movement, not teleport): - On pointerdown: record the offset between finger position and player position (touchOffX = pointer.x - player.x, touchOffY = pointer.y - player.y). Do NOT move the player on pointerdown. - On pointermove: move player to (pointer.x - touchOffX, pointer.y - touchOffY), clamped within bounds. This makes the plane follow finger movement 1:1 without teleporting. - On pointerup: stop touching. - Auto-fire continuously while touching. - Two-finger tap triggers loop (check pointer1.isDown && pointer2.isDown, or touches.length >= 2). Player bounds: Clamp within sc(20) to gw()-sc(20) horizontally, sc(40) to gh()-sc(20) vertically. WEAPONS: - Default (level 1): Double stream — one bullet from each wing boom. - Upgraded (level 2+): Quad-shot — 4 bullets spread. - Bullet speed: 550 (scaled by S), moving upward. - Cooldown: 150ms. "LOOP" BARREL ROLL: - Keyboard: Z or Shift. Mobile: two-finger tap. - Animates scaleX/scaleY via tweens to simulate a 3D flip (~600ms total). - Player is invincible during loop animation. - 3-second cooldown shown by a bar in the HUD. ENEMY AI & WAVE MANAGER: Wave Manager spawns enemy patterns every 2500ms (adjusted by difficulty): 1. Formation V: 5 fighters spawn at top-center, fan out in V shape with staggered timing. 2. Kamikaze: Single fighter aims directly at player's current position at high speed. 3. Bomber: Spawns at top, moves slowly down, fires aimed bullets at player every 1.2 seconds. Difficulty scales every 5000 points: difficulty = 1 + floor(score / 5000) * 0.3. At difficulty > 1.5, 30% chance of bonus kamikaze after each wave. Enemy Ships: - Spawn every 12-20 seconds at random X above screen. - Scroll down at 0.8-1.3 speed (scaled by S). - All ships fire aimed bullets at player every 1.5 seconds. - Carriers fire 3-bullet spread (center + 30px left/right offset). - HP damage: flash white on hit. Alpha reduces proportionally (0.5 + 0.5 × hp/maxHp). Smoke particles when HP < 50%. - Destruction: 5-stage explosion sequence (one every 150ms at random offsets), big explosion sound. Score popup. 50% chance to drop powerup. COLLISION: - Player Bullet → Enemy: Flash white. Fighters: 1 hit kill. Bombers: 10 hits. Ships: per HP. On death: explosion particles + score popup (+100/+500/ship values). - Enemy/Bullet → Player: If not looping/invincible, player explodes, loses 1 life, respawns after 1s with 2s invincibility flicker. - Red fighter kills drop powerups. POWERUPS: - "POW" falls at speed 100 (scaled by S). - First pickup: Upgrade to Quad-Shot. - Second pickup: Clears all enemy bullets on screen. SCENERY SPAWNING: Every 3 seconds: - 35%: Random island type at random X, alpha 0.5-0.7, scale 0.5-1.2×. - 15%: Floating crate, scale 1-2×. - 20%: Cluster of 2-4 tiny reef dots. - 30%: Nothing (open ocean). Cloud shadows: every 4-8 seconds, scale 0.8-2.0×, drift down at 1.0-1.5 speed. Foam: every 2-5 seconds, scale 0.5-1.5×, drift at 2× speed. All scenery destroyed when off-screen below. HUD (Top Bar): - Black rectangle, full width, sc(44) tall, 0.85 alpha, depth 100. - Left: "SCORE: 0" (white, Courier New monospace, fs(14)), depth 101. - Right: "HI: 20000" (yellow, same font), origin(1,0), depth 101. - Center: Life icons (mini P-38 sprites) — dynamically centered based on lives count. Calculate total width = lives × sc(18), startX = cx() - totalW/2 + sc(9). - Loop cooldown bar: Below score text inside HUD area (barH - sc(6)). Width sc(80), height sc(5). Cyan when ready, grey when cooling. "LOOP" label to the left. EXPLOSIONS & SCORE POPUPS: Explosions: Burst of 12 particles (random from 5 particle types). Each tweens outward at random angle with random speed, fading alpha and scale to 0 over 300-600ms. Smoky variant uses smoke/orange/red textures. Score popups: Text showing "+100"/"+500"/etc at kill position. Tweens upward sc(40) pixels while fading out over 800ms. White text with black stroke, depth 50. GAME OVER & LEADERBOARD (MOBILE-FRIENDLY): On death with 0 lives: 1. Dark overlay (0.7 alpha black). 2. "GAME OVER" (red, large font, centered). 3. Final score (yellow, centered). 4. "ENTER YOUR NAME" prompt. 5. Name display text (starts as "___"). 6. TAP-BASED LETTER PICKER GRID (critical for mobile): - A-Z letters arranged in a grid (9 columns). - Each letter is a tappable rectangle (sc(28) × sc(24)) with the letter text centered. - DEL button (1.5× width, red) at the end for backspace. - Max 8 characters, uppercase only. - Grid starts at sc(280) Y position. - Also support keyboard input (keydown events) for desktop. 7. Leaderboard display below the grid (starting at sc(380)): - "── TOP SCORES ──" heading (yellow). - Ranked list with rank, name (padded to 8), score (padded to 7). - Top 1: gold, top 2-3: light grey, rest: dark grey. 8. "[ SUBMIT SCORE ]" button (green) and "[ PLAY AGAIN ]" button (white/grey). After submit: - Call backend async, show "SAVING..." on button. - Show final leaderboard screen with "SCORE SAVED!" heading. - Player's entry highlighted in cyan with flash animation (alpha tween 0.5→1, 3 repeats). - Full leaderboard with rank, name, score, date. Column header row. - "[ PLAY AGAIN ]" button + "SPACE or TAP to play" hint. BACKEND (Shared Leaderboard API): GET /api/leaderboard: - db.list('leaderboard', { limit: 50 }) - Sort by score descending, return top 10. POST /api/leaderboard: - Receives { name: string, score: number }. - Clean name: uppercase, alphanumeric only, max 8 chars, default "ACE". - db.add to 'leaderboard' table with { name, score, date }. - Trim table to top 50 entries (delete excess). - Return top 10. Frontend calls via: import { api } from '@appdeploy/client' - api.get('/api/leaderboard') on game start to load hi-score. - api.post('/api/leaderboard', { name, score }) on submit. - Cache leaderboard in a module-level variable. RESTART: On restart: Reset score, lives (3), gun level, flags. Disable all bullets/enemies/powerups. Reposition player to cx(), gh() - sc(80). Refresh hi-score from cached leaderboard. Update HUD texts. Remove all keyboard listeners and re-add them fresh. KEY IMPLEMENTATION NOTES: 1. Player spawn position: gh() - sc(80), NOT a percentage of height (since height varies by device). 2. All off-screen cleanup uses gw()/gh(), never hardcoded values. 3. All velocities multiplied by S. 4. All font sizes use fs() helper. 5. All positions use sc() helper. 6. Ship physics bodies need physics.add.overlap registration for bullet collision. 7. Ocean TileSprite scrolls tilePositionY -= 2 per frame. 8. Phaser loaded via a script tag in index.html, declared as "declare const Phaser: any" in TypeScript.

Live App

https://v2.appdeploy.ai/app/630ea6d8880f476e9c/