🎮ArcadeLab

Retro Zombie Survival Arcade

by TurboMaker33
285 lines9.7 KB
▶ Play
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Retro Zombie Survival Arcade</title>
    <style>
        * {
            box-sizing: border-box;
            user-select: none;
        }
        body {
            margin: 0;
            padding: 0;
            background: #111;
            color: #fff;
            font-family: 'Courier New', Courier, monospace;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            overflow: hidden;
        }
        #game-container {
            position: relative;
            width: 800px;
            height: 400px;
            background: linear-gradient(to bottom, #1a0b2e, #11051c, #05010a);
            border: 4px solid #333;
            box-shadow: 0 0 20px rgba(255, 0, 0, 0.3);
            overflow: hidden;
        }
        canvas {
            display: block;
            width: 100%;
            height: 100%;
        }
        .ui-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            padding: 15px;
        }
        .hud-top {
            display: flex;
            justify-content: space-between;
            font-size: 18px;
            font-weight: bold;
            text-shadow: 2px 2px #000;
        }
        #health-bar-container {
            width: 150px;
            height: 15px;
            background: #441111;
            border: 2px solid #ff3333;
            margin-top: 5px;
        }
        #health-bar {
            width: 100%;
            height: 100%;
            background: #ff3333;
            transition: width 0.1s ease;
        }
        .score-color { color: #00ffcc; }
        .wave-color { color: #ffcc00; }
        .ammo-color { color: #ff9900; }
        
        .screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(10, 5, 15, 0.85);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            backdrop-filter: blur(4px);
            z-index: 10;
            text-align: center;
        }
        .hidden {
            display: none !important;
        }
        h1 {
            font-size: 42px;
            margin: 0 0 10px 0;
            color: #ff3333;
            text-shadow: 3px 3px #000, 0 0 10px rgba(255,51,51,0.5);
            letter-spacing: 2px;
        }
        p {
            font-size: 14px;
            margin: 5px 0 20px 0;
            color: #bbb;
        }
        button {
            background: #ff3333;
            color: white;
            border: none;
            padding: 12px 30px;
            font-size: 18px;
            font-family: inherit;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 4px #990000;
            transition: background 0.1s;
            pointer-events: auto;
        }
        button:hover {
            background: #ff5555;
        }
        button:active {
            transform: translateY(4px);
            box-shadow: 0 0 #990000;
        }
        .controls-hint {
            margin-top: 25px;
            font-size: 12px;
            color: #888;
            border-top: 1px solid #333;
            padding-top: 15px;
            width: 80%;
        }
        .controls-grid {
            display: flex;
            justify-content: space-around;
            margin-top: 10px;
        }
        .control-item {
            background: #222;
            padding: 5px 10px;
            border-radius: 4px;
            border: 1px solid #444;
        }
    </style>
</head>
<body>

    <div id="game-container">
        <!-- Canvas for rendering physics/graphics -->
        <canvas id="gameCanvas" width="800" height="400"></canvas>

        <!-- Heads Up Display Layer -->
        <div class="ui-layer">
            <div class="hud-top">
                <div>
                    <div>VITAL SIGNS</div>
                    <div id="health-bar-container"><div id="health-bar"></div></div>
                </div>
                <div>
                    <div>SCORE</div>
                    <div id="score-display" class="score-color">000000</div>
                </div>
                <div>
                    <div>WAVE</div>
                    <div id="wave-display" class="wave-color" style="text-align: right;">1</div>
                </div>
                <div>
                    <div>MUNITIONS</div>
                    <div id="ammo-display" class="ammo-color" style="text-align: right;">30 / ∞</div>
                </div>
            </div>
            <div></div> <!-- Spacer -->
        </div>

        <!-- Start/Menu Screen -->
        <div id="start-screen" class="screen">
            <h1>OUTBREAK: ARCADE</h1>
            <p>Slay the endless dynamic horde. Survive the tactical decay.</p>
            <button id="start-btn">ENGAGE PROTOCOL</button>
            <div class="controls-hint">
                <div class="controls-grid">
                    <div class="control-item">← / A : Move Left</div>
                    <div class="control-item">→ / D : Move Right</div>
                    <div class="control-item">SPACE / W : Jump</div>
                    <div class="control-item">CLICK : Fire Weapon</div>
                </div>
            </div>
        </div>

        <!-- Game Over Screen -->
        <div id="gameover-screen" class="screen hidden">
            <h1>OUTPOST OVERRUN</h1>
            <p id="final-stats">You survived 0 waves with a score of 0.</p>
            <button id="restart-btn">REDEPLOY</button>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        // Target UI Elements
        const startScreen = document.getElementById('start-screen');
        const gameoverScreen = document.getElementById('gameover-screen');
        const startBtn = document.getElementById('start-btn');
        const restartBtn = document.getElementById('restart-btn');
        const healthBar = document.getElementById('health-bar');
        const scoreDisplay = document.getElementById('score-display');
        const waveDisplay = document.getElementById('wave-display');
        const ammoDisplay = document.getElementById('ammo-display');

        // Game State Core Variables
        let gameState = 'MENU'; // MENU, PLAYING, GAMEOVER
        let score = 0;
        let wave = 1;
        let keys = {};
        let mouse = { x: 0, y: 0, isDown: false };

        // Entity Lists
        let player;
        let zombies = [];
        let bullets = [];
        let particles = [];
        let drops = [];

        // Environment Variables
        const groundY = 340;
        const gravity = 0.6;

        // Wave Management Systems
        let waveTimer = 0;
        let zombiesSpawnedThisWave = 0;
        let totalZombiesForWave = 5;
        let spawnInterval = 120; // Frames between spawns

        // Audio Synth Helper Function (Web Audio API Retro Sound Effects Engine)
        const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
        function playLaserSound(type) {
            if (!audioCtx) return;
            const osc = audioCtx.createOscillator();
            const gain = audioCtx.createGain();
            osc.connect(gain);
            gain.connect(audioCtx.destination);

            if (type === 'shoot') {
                osc.type = 'sawtooth';
                osc.frequency.setValueAtTime(400, audioCtx.currentTime);
                osc.frequency.exponentialRampToValueAtTime(80, audioCtx.currentTime + 0.15);
                gain.gain.setValueAtTime(0.1, audioCtx.currentTime);
                gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.15);
                osc.start(); osc.stop(audioCtx.currentTime + 0.15);
            } else if (type === 'hit') {
                osc.type = 'triangle';
                osc.frequency.setValueAtTime(120, audioCtx.currentTime);
                osc.frequency.linearRampToValueAtTime(30, audioCtx.currentTime + 0.1);
                gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
                gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.1);
                osc.start(); osc.stop(audioCtx.currentTime + 0.1);
            } else if (type === 'death') {
                osc.type = 'sawtooth';
                osc.frequency.setValueAtTime(100, audioCtx.currentTime);
                osc.frequency.linearRampToValueAtTime(10, audioCtx.currentTime + 0.4);
                gain.gain.setValueAtTime(0.3, audioCtx.currentTime);
                gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.4);
                osc.start(); osc.stop(audioCtx.currentTime + 0.4);
            } else if (type === 'powerup') {
                osc.type = 'sine';
                osc.frequency.setValueAtTime(200, audioCtx.currentTime);
                osc.frequency.linearRampToValueAtTime(600, audioCtx.currentTime + 0.2);
                gain.gain.setValueAtTime(0.15, audioCtx.currentTime);
                gain.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 0.2);
                osc.start(); osc.stop(audioCtx.currentTime + 0.2);
            }
        }

        // Entity Classes Definitions
        class Player {
            constructor() {
                this.x = 400;
                this.y = groundY - 40;
                this.width = 24;
                this.height = 40;
                this.vx = 0;
                this.vy = 0;
                this.speed = 4.5;

Game Source: Retro Zombie Survival Arcade

Creator: TurboMaker33

Libraries: none

Complexity: complex (285 lines, 9.7 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: retro-zombie-survival-arcade-turbomaker33" to link back to the original. Then publish at arcadelab.ai/publish.