像素塔防游戏:像素守卫者

像素塔防游戏:像素守卫者

下面是一个完整的像素风格塔防游戏HTML实现。玩家需要在地图上建造防御塔来阻止敌人到达终点。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>像素塔防:像素守卫者</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Press Start 2P', cursive, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1a1a2e, #16213e);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            color: #fff;
            overflow-x: hidden;
        }
        
        header {
            text-align: center;
            margin-bottom: 20px;
            width: 100%;
            padding: 15px;
            background: rgba(0, 0, 0, 0.6);
            border-radius: 10px;
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.5);
            border: 2px solid #00ffff;
        }
        
        h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
            color: #ffd700;
            text-shadow: 0 0 10px rgba(255, 215, 0, 0.7);
            letter-spacing: 2px;
        }
        
        .subtitle {
            font-size: 1.2rem;
            color: #00ffff;
            margin-bottom: 15px;
        }
        
        .game-container {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 20px;
            max-width: 1200px;
            width: 100%;
        }
        
        .game-info {
            background: rgba(0, 0, 0, 0.7);
            border-radius: 10px;
            padding: 20px;
            width: 300px;
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.3);
            border: 2px solid #00ffaa;
        }
        
        .stats {
            margin-bottom: 20px;
            padding-bottom: 15px;
            border-bottom: 2px solid #444;
        }
        
        .stat {
            display: flex;
            justify-content: space-between;
            margin: 10px 0;
            font-size: 0.9rem;
        }
        
        .stat-value {
            color: #ffd700;
        }
        
        .towers {
            margin-bottom: 20px;
        }
        
        h2 {
            font-size: 1.3rem;
            color: #00ffff;
            margin-bottom: 15px;
            text-align: center;
        }
        
        .tower-list {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
        }
        
        .tower {
            background: rgba(40, 40, 60, 0.8);
            border-radius: 8px;
            padding: 12px;
            text-align: center;
            cursor: pointer;
            transition: all 0.3s ease;
            border: 2px solid #555;
        }
        
        .tower:hover {
            transform: translateY(-5px);
            background: rgba(60, 60, 100, 0.8);
            border-color: #00ffff;
            box-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
        }
        
        .tower.selected {
            border-color: #ffd700;
            background: rgba(80, 60, 20, 0.8);
            box-shadow: 0 0 15px rgba(255, 215, 0, 0.7);
        }
        
        .tower-icon {
            width: 50px;
            height: 50px;
            margin: 0 auto 10px;
            background: #333;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 1.8rem;
        }
        
        .tower-name {
            font-size: 0.85rem;
            margin-bottom: 5px;
            color: #ffd700;
        }
        
        .tower-cost {
            font-size: 0.8rem;
            color: #00ffaa;
        }
        
        .controls {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }
        
        button {
            background: linear-gradient(to bottom, #ff6b6b, #c0392b);
            border: none;
            border-radius: 5px;
            color: white;
            padding: 12px;
            font-size: 1rem;
            cursor: pointer;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 1px;
            box-shadow: 0 5px 0 #8c1c13;
        }
        
        button:hover {
            background: linear-gradient(to bottom, #ff8e8e, #e74c3c);
            transform: translateY(-2px);
        }
        
        button:active {
            transform: translateY(5px);
            box-shadow: 0 0 0 #8c1c13;
        }
        
        #start-btn {
            background: linear-gradient(to bottom, #4cd964, #27ae60);
            box-shadow: 0 5px 0 #1e8449;
        }
        
        #start-btn:hover {
            background: linear-gradient(to bottom, #5ef97a, #2ecc71);
        }
        
        .game-board {
            position: relative;
            background: rgba(0, 0, 0, 0.8);
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 0 20px rgba(0, 255, 255, 0.4);
            border: 3px solid #00ffff;
        }
        
        #game-canvas {
            display: block;
        }
        
        .instructions {
            margin-top: 20px;
            background: rgba(0, 0, 0, 0.6);
            border-radius: 10px;
            padding: 20px;
            width: 100%;
            max-width: 900px;
            border: 2px solid #ff6b6b;
        }
        
        .instructions h2 {
            color: #ff6b6b;
            text-align: center;
            margin-bottom: 15px;
        }
        
        .instructions p {
            margin-bottom: 10px;
            line-height: 1.6;
        }
        
        .instructions ul {
            padding-left: 25px;
            margin: 15px 0;
        }
        
        .instructions li {
            margin-bottom: 8px;
            color: #aaffaa;
        }
        
        .key {
            display: inline-block;
            background: rgba(255, 255, 255, 0.2);
            padding: 2px 8px;
            border-radius: 4px;
            font-family: monospace;
            margin: 0 3px;
        }
        
        footer {
            margin-top: 20px;
            text-align: center;
            color: #aaa;
            font-size: 0.8rem;
            padding: 10px;
        }
        
        @media (max-width: 900px) {
            .game-container {
                flex-direction: column;
                align-items: center;
            }
            
            .game-info {
                width: 100%;
                max-width: 600px;
            }
        }
        
        .wave-indicator {
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 15px;
            gap: 10px;
        }
        
        .wave-dot {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            background: #444;
        }
        
        .wave-dot.active {
            background: #ffd700;
            box-shadow: 0 0 8px #ffd700;
        }
    </style>
    <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
</head>
<body>
    <header>
        <h1>像素塔防:像素守卫者</h1>
        <div class="subtitle">建造防御塔,消灭入侵的敌人!</div>
    </header>
    
    <div class="game-container">
        <div class="game-info">
            <div class="stats">
                <h2>游戏状态</h2>
                <div class="stat">
                    <span>金币:</span>
                    <span id="gold" class="stat-value">200</span>
                </div>
                <div class="stat">
                    <span>生命值:</span>
                    <span id="lives" class="stat-value">20</span>
                </div>
                <div class="stat">
                    <span>波数:</span>
                    <span id="wave" class="stat-value">0/10</span>
                </div>
                <div class="stat">
                    <span>敌人数量:</span>
                    <span id="enemies" class="stat-value">0</span>
                </div>
                <div class="stat">
                    <span>分数:</span>
                    <span id="score" class="stat-value">0</span>
                </div>
            </div>
            
            <div class="towers">
                <h2>选择防御塔</h2>
                <div class="tower-list">
                    <div class="tower" data-type="basic" data-cost="50">
                        <div class="tower-icon">🔫</div>
                        <div class="tower-name">基础炮塔</div>
                        <div class="tower-cost">$50</div>
                    </div>
                    <div class="tower" data-type="sniper" data-cost="100">
                        <div class="tower-icon">🎯</div>
                        <div class="tower-name">狙击塔</div>
                        <div class="tower-cost">$100</div>
                    </div>
                    <div class="tower" data-type="cannon" data-cost="150">
                        <div class="tower-icon">💣</div>
                        <div class="tower-name">加农炮</div>
                        <div class="tower-cost">$150</div>
                    </div>
                    <div class="tower" data-type="ice" data-cost="120">
                        <div class="tower-icon">❄️</div>
                        <div class="tower-name">冰冻塔</div>
                        <div class="tower-cost">$120</div>
                    </div>
                </div>
            </div>
            
            <div class="controls">
                <button id="start-btn">开始游戏</button>
                <button id="upgrade-btn">升级防御塔 ($100)</button>
                <button id="sell-btn">出售防御塔</button>
                <button id="pause-btn">暂停游戏</button>
            </div>
            
            <div class="wave-indicator">
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
                <div class="wave-dot"></div>
            </div>
        </div>
        
        <div class="game-board">
            <canvas id="game-canvas" width="600" height="600"></canvas>
        </div>
    </div>
    
    <div class="instructions">
        <h2>游戏指南</h2>
        <p>欢迎来到像素塔防!你的任务是阻止敌人穿过地图到达终点。</p>
        <ul>
            <li>选择左侧的防御塔类型,然后点击地图上的空地建造</li>
            <li>每种防御塔都有不同的特性:基础炮塔射速快,狙击塔射程远,加农炮伤害高,冰冻塔减速敌人</li>
            <li>消灭敌人获得金币,用于建造或升级防御塔</li>
            <li>如果敌人到达终点,你将失去生命值</li>
            <li>成功抵御10波敌人即可获胜!</li>
        </ul>
        <p><strong>提示:</strong> 合理搭配不同防御塔,在敌人路径的关键位置建造防御塔,及时升级强力防御塔!</p>
    </div>
    
    <footer>
        &copy; 2023 像素塔防游戏 | 使用HTML5 Canvas和JavaScript构建
    </footer>

    <script>
        // 获取Canvas元素和上下文
        const canvas = document.getElementById('game-canvas');
        const ctx = canvas.getContext('2d');
        
        // 游戏状态
        const gameState = {
            gold: 200,
            lives: 20,
            wave: 0,
            enemies: 0,
            score: 0,
            gameStarted: false,
            gameOver: false,
            gameWon: false,
            selectedTower: null,
            selectedTowerType: null,
            towers: [],
            enemiesList: [],
            bullets: [],
            particles: [],
            path: [
                {x: 0, y: 300}, {x: 200, y: 300}, {x: 200, y: 100}, 
                {x: 400, y: 100}, {x: 400, y: 300}, {x: 600, y: 300}
            ],
            lastSpawn: 0,
            spawnInterval: 1000,
            enemyCount: 0,
            maxWave: 10
        };
        
        // 防御塔类型
        const towerTypes = {
            basic: {
                name: "基础炮塔",
                cost: 50,
                range: 100,
                damage: 10,
                fireRate: 800,
                color: "#3498db",
                bulletColor: "#2980b9"
            },
            sniper: {
                name: "狙击塔",
                cost: 100,
                range: 200,
                damage: 30,
                fireRate: 1500,
                color: "#9b59b6",
                bulletColor: "#8e44ad"
            },
            cannon: {
                name: "加农炮",
                cost: 150,
                range: 80,
                damage: 50,
                fireRate: 2000,
                color: "#e74c3c",
                bulletColor: "#c0392b"
            },
            ice: {
                name: "冰冻塔",
                cost: 120,
                range: 120,
                damage: 5,
                fireRate: 1000,
                color: "#1abc9c",
                bulletColor: "#16a085",
                slow: 0.5
            }
        };
        
        // 敌人类型
        const enemyTypes = [
            {name: "普通敌人", health: 50, speed: 1.5, color: "#e74c3c", reward: 10},
            {name: "快速敌人", health: 30, speed: 3, color: "#3498db", reward: 15},
            {name: "重型敌人", health: 150, speed: 0.8, color: "#f39c12", reward: 25},
            {name: "飞行敌人", health: 80, speed: 2, color: "#9b59b6", reward: 20}
        ];
        
        // 防御塔类
        class Tower {
            constructor(x, y, type) {
                this.x = x;
                this.y = y;
                this.type = type;
                this.level = 1;
                this.range = towerTypes[type].range;
                this.damage = towerTypes[type].damage;
                this.fireRate = towerTypes[type].fireRate;
                this.lastShot = 0;
                this.color = towerTypes[type].color;
                this.bulletColor = towerTypes[type].bulletColor;
                this.slow = towerTypes[type].slow || 0;
            }
            
            draw() {
                // 绘制炮塔底座
                ctx.fillStyle = "#2c3e50";
                ctx.beginPath();
                ctx.arc(this.x, this.y, 20, 0, Math.PI * 2);
                ctx.fill();
                
                // 绘制炮塔主体
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(this.x, this.y, 15, 0, Math.PI * 2);
                ctx.fill();
                
                // 绘制炮管
                ctx.strokeStyle = "#34495e";
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.moveTo(this.x, this.y);
                ctx.lineTo(this.x + 20, this.y);
                ctx.stroke();
                
                // 绘制等级
                ctx.fillStyle = "#ffffff";
                ctx.font = "bold 12px Arial";
                ctx.textAlign = "center";
                ctx.fillText("Lv." + this.level, this.x, this.y + 5);
                
                // 如果选中则绘制范围
                if (gameState.selectedTower === this) {
                    ctx.strokeStyle = "rgba(255, 255, 255, 0.3)";
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, this.range, 0, Math.PI * 2);
                    ctx.stroke();
                }
            }
            
            update() {
                // 寻找目标
                let target = null;
                let minDist = this.range;
                
                for (let enemy of gameState.enemiesList) {
                    const dx = enemy.x - this.x;
                    const dy = enemy.y - this.y;
                    const dist = Math.sqrt(dx * dx + dy * dy);
                    
                    if (dist < minDist) {
                        minDist = dist;
                        target = enemy;
                    }
                }
                
                // 射击
                if (target && Date.now() - this.lastShot > this.fireRate) {
                    gameState.bullets.push(new Bullet(
                        this.x, 
                        this.y, 
                        target, 
                        this.damage, 
                        this.bulletColor,
                        this.slow
                    ));
                    this.lastShot = Date.now();
                }
            }
            
            upgrade() {
                this.level++;
                this.damage = Math.floor(this.damage * 1.5);
                this.range = Math.floor(this.range * 1.1);
                this.fireRate = Math.floor(this.fireRate * 0.9);
            }
        }
        
        // 敌人类
        class Enemy {
            constructor(type) {
                this.type = type;
                this.health = enemyTypes[type].health;
                this.maxHealth = enemyTypes[type].health;
                this.speed = enemyTypes[type].speed;
                this.color = enemyTypes[type].color;
                this.reward = enemyTypes[type].reward;
                this.pathIndex = 0;
                this.x = gameState.path[0].x;
                this.y = gameState.path[0].y;
                this.slow = 1; // 减速系数 (1=正常)
                this.slowTimer = 0;
            }
            
            draw() {
                // 绘制敌人身体
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(this.x, this.y, 15, 0, Math.PI * 2);
                ctx.fill();
                
                // 绘制敌人眼睛
                ctx.fillStyle = "#ffffff";
                ctx.beginPath();
                ctx.arc(this.x - 5, this.y - 5, 4, 0, Math.PI * 2);
                ctx.arc(this.x + 5, this.y - 5, 4, 0, Math.PI * 2);
                ctx.fill();
                
                // 绘制血条
                const barWidth = 30;
                const barHeight = 5;
                const healthPercent = this.health / this.maxHealth;
                
                ctx.fillStyle = "#444";
                ctx.fillRect(this.x - barWidth/2, this.y - 30, barWidth, barHeight);
                
                ctx.fillStyle = healthPercent > 0.5 ? "#2ecc71" : healthPercent > 0.25 ? "#f1c40f" : "#e74c3c";
                ctx.fillRect(this.x - barWidth/2, this.y - 30, barWidth * healthPercent, barHeight);
            }
            
            update() {
                // 应用减速效果
                if (this.slowTimer > 0) {
                    this.slowTimer--;
                } else {
                    this.slow = 1;
                }
                
                // 沿路径移动
                if (this.pathIndex < gameState.path.length - 1) {
                    const targetX = gameState.path[this.pathIndex + 1].x;
                    const targetY = gameState.path[this.pathIndex + 1].y;
                    
                    const dx = targetX - this.x;
                    const dy = targetY - this.y;
                    const dist = Math.sqrt(dx * dx + dy * dy);
                    
                    if (dist < 2) {
                        this.pathIndex++;
                    } else {
                        this.x += (dx / dist) * this.speed * this.slow;
                        this.y += (dy / dist) * this.speed * this.slow;
                    }
                } else {
                    // 到达终点
                    gameState.lives--;
                    updateStats();
                    removeEnemy(this);
                    
                    if (gameState.lives <= 0) {
                        gameState.gameOver = true;
                    }
                }
            }
            
            takeDamage(damage) {
                this.health -= damage;
                if (this.health <= 0) {
                    gameState.gold += this.reward;
                    gameState.score += this.reward * 10;
                    updateStats();
                    createParticles(this.x, this.y, this.color);
                    removeEnemy(this);
                }
            }
            
            applySlow(slowFactor, duration) {
                this.slow = slowFactor;
                this.slowTimer = duration;
            }
        }
        
        // 子弹类
        class Bullet {
            constructor(x, y, target, damage, color, slow) {
                this.x = x;
                this.y = y;
                this.target = target;
                this.damage = damage;
                this.color = color;
                this.speed = 5;
                this.slow = slow;
            }
            
            draw() {
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(this.x, this.y, 5, 0, Math.PI * 2);
                ctx.fill();
            }
            
            update() {
                // 移动子弹
                const dx = this.target.x - this.x;
                const dy = this.target.y - this.y;
                const dist = Math.sqrt(dx * dx + dy * dy);
                
                if (dist < this.speed) {
                    // 击中目标
                    this.target.takeDamage(this.damage);
                    
                    // 应用减速效果
                    if (this.slow > 0) {
                        this.target.applySlow(this.slow, 100);
                    }
                    
                    createParticles(this.target.x, this.target.y, this.color);
                    return false; // 标记为待删除
                } else {
                    // 继续移动
                    this.x += (dx / dist) * this.speed;
                    this.y += (dy / dist) * this.speed;
                    return true; // 子弹继续存在
                }
            }
        }
        
        // 粒子效果类
        class Particle {
            constructor(x, y, color) {
                this.x = x;
                this.y = y;
                this.color = color;
                this.size = Math.random() * 5 + 2;
                this.speedX = Math.random() * 3 - 1.5;
                this.speedY = Math.random() * 3 - 1.5;
                this.life = 30;
            }
            
            draw() {
                ctx.fillStyle = this.color;
                ctx.globalAlpha = this.life / 30;
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                ctx.fill();
                ctx.globalAlpha = 1;
            }
            
            update() {
                this.x += this.speedX;
                this.y += this.speedY;
                this.life--;
                return this.life > 0;
            }
        }
        
        // 初始化游戏
        function initGame() {
            gameState.gold = 200;
            gameState.lives = 20;
            gameState.wave = 0;
            gameState.enemies = 0;
            gameState.score = 0;
            gameState.gameStarted = false;
            gameState.gameOver = false;
            gameState.gameWon = false;
            gameState.selectedTower = null;
            gameState.towers = [];
            gameState.enemiesList = [];
            gameState.bullets = [];
            gameState.particles = [];
            gameState.enemyCount = 0;
            
            updateStats();
            updateWaveDots();
            
            // 重置按钮状态
            document.getElementById('start-btn').textContent = "开始游戏";
        }
        
        // 更新游戏状态显示
        function updateStats() {
            document.getElementById('gold').textContent = gameState.gold;
            document.getElementById('lives').textContent = gameState.lives;
            document.getElementById('wave').textContent = `${gameState.wave}/${gameState.maxWave}`;
            document.getElementById('enemies').textContent = gameState.enemiesList.length;
            document.getElementById('score').textContent = gameState.score;
        }
        
        // 更新波数指示器
        function updateWaveDots() {
            const dots = document.querySelectorAll('.wave-dot');
            dots.forEach((dot, index) => {
                if (index < gameState.wave) {
                    dot.classList.add('active');
                } else {
                    dot.classList.remove('active');
                }
            });
        }
        
        // 创建粒子效果
        function createParticles(x, y, color) {
            for (let i = 0; i < 10; i++) {
                gameState.particles.push(new Particle(x, y, color));
            }
        }
        
        // 移除敌人
        function removeEnemy(enemy) {
            const index = gameState.enemiesList.indexOf(enemy);
            if (index !== -1) {
                gameState.enemiesList.splice(index, 1);
            }
        }
        
        // 生成敌人
        function spawnEnemy() {
            if (gameState.enemyCount > 0 && Date.now() - gameState.lastSpawn > gameState.spawnInterval) {
                // 根据波数选择敌人类型
                let type = 0;
                if (gameState.wave > 3) type = Math.floor(Math.random() * 2);
                if (gameState.wave > 6) type = Math.floor(Math.random() * 3);
                if (gameState.wave > 8) type = Math.floor(Math.random() * 4);
                
                gameState.enemiesList.push(new Enemy(type));
                gameState.enemyCount--;
                gameState.lastSpawn = Date.now();
            }
            
            // 如果所有敌人都已生成且没有剩余敌人,进入下一波
            if (gameState.enemyCount === 0 && gameState.enemiesList.length === 0 && gameState.gameStarted) {
                gameState.wave++;
                updateStats();
                updateWaveDots();
                
                if (gameState.wave > gameState.maxWave) {
                    gameState.gameWon = true;
                } else {
                    // 设置下一波敌人数量
                    gameState.enemyCount = 5 + gameState.wave * 3;
                    gameState.spawnInterval = 1000 - Math.min(800, gameState.wave * 70);
                }
            }
        }
        
        // 绘制游戏场景
        function drawGame() {
            // 绘制背景
            ctx.fillStyle = "#2c3e50";
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // 绘制路径
            ctx.strokeStyle = "#7f8c8d";
            ctx.lineWidth = 40;
            ctx.lineCap = "round";
            ctx.beginPath();
            ctx.moveTo(gameState.path[0].x, gameState.path[0].y);
            
            for (let i = 1; i < gameState.path.length; i++) {
                ctx.lineTo(gameState.path[i].x, gameState.path[i].y);
            }
            
            ctx.stroke();
            
            // 绘制起点和终点
            ctx.fillStyle = "#27ae60";
            ctx.beginPath();
            ctx.arc(gameState.path[0].x, gameState.path[0].y, 20, 0, Math.PI * 2);
            ctx.fill();
            
            ctx.fillStyle = "#c0392b";
            ctx.beginPath();
            ctx.arc(gameState.path[gameState.path.length - 1].x, 
                   gameState.path[gameState.path.length - 1].y, 20, 0, Math.PI * 2);
            ctx.fill();
            
            // 绘制敌人
            for (let enemy of gameState.enemiesList) {
                enemy.draw();
            }
            
            // 绘制子弹
            for (let bullet of gameState.bullets) {
                bullet.draw();
            }
            
            // 绘制粒子
            for (let particle of gameState.particles) {
                particle.draw();
            }
            
            // 绘制防御塔
            for (let tower of gameState.towers) {
                tower.draw();
            }
            
            // 绘制游戏状态
            if (!gameState.gameStarted) {
                ctx.fillStyle = "rgba(0, 0, 0, 0.7)";
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                
                ctx.fillStyle = "#ffffff";
                ctx.font = "bold 36px 'Press Start 2P'";
                ctx.textAlign = "center";
                ctx.fillText("像素塔防", canvas.width/2, canvas.height/2 - 40);
                
                ctx.font = "bold 24px 'Press Start 2P'";
                ctx.fillText("点击'开始游戏'按钮", canvas.width/2, canvas.height/2 + 20);
                ctx.fillText("开始你的防御战!", canvas.width/2, canvas.height/2 + 60);
            }
            
            if (gameState.gameOver) {
                ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                
                ctx.fillStyle = "#e74c3c";
                ctx.font = "bold 36px 'Press Start 2P'";
                ctx.textAlign = "center";
                ctx.fillText("游戏结束", canvas.width/2, canvas.height/2 - 40);
                
                ctx.fillStyle = "#ffffff";
                ctx.font = "bold 24px 'Press Start 2P'";
                ctx.fillText(`最终分数: ${gameState.score}`, canvas.width/2, canvas.height/2 + 20);
                ctx.fillText("点击'开始游戏'重新开始", canvas.width/2, canvas.height/2 + 60);
            }
            
            if (gameState.gameWon) {
                ctx.fillStyle = "rgba(0, 0, 0, 0.8)";
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                
                ctx.fillStyle = "#2ecc71";
                ctx.font = "bold 36px 'Press Start 2P'";
                ctx.textAlign = "center";
                ctx.fillText("胜利!", canvas.width/2, canvas.height/2 - 40);
                
                ctx.fillStyle = "#ffffff";
                ctx.font = "bold 24px 'Press Start 2P'";
                ctx.fillText(`最终分数: ${gameState.score}`, canvas.width/2, canvas.height/2 + 20);
                ctx.fillText("成功抵御了所有敌人!", canvas.width/2, canvas.height/2 + 60);
            }
        }
        
        // 更新游戏状态
        function updateGame() {
            if (!gameState.gameStarted || gameState.gameOver || gameState.gameWon) return;
            
            // 生成敌人
            spawnEnemy();
            
            // 更新敌人
            for (let enemy of gameState.enemiesList) {
                enemy.update();
            }
            
            // 更新防御塔
            for (let tower of gameState.towers) {
                tower.update();
            }
            
            // 更新子弹
            for (let i = gameState.bullets.length - 1; i >= 0; i--) {
                if (!gameState.bullets[i].update()) {
                    gameState.bullets.splice(i, 1);
                }
            }
            
            // 更新粒子
            for (let i = gameState.particles.length - 1; i >= 0; i--) {
                if (!gameState.particles[i].update()) {
                    gameState.particles.splice(i, 1);
                }
            }
        }
        
        // 游戏主循环
        function gameLoop() {
            drawGame();
            updateGame();
            requestAnimationFrame(gameLoop);
        }
        
        // 事件监听器
        document.querySelectorAll('.tower').forEach(tower => {
            tower.addEventListener('click', () => {
                // 移除之前的选择
                document.querySelectorAll('.tower').forEach(t => {
                    t.classList.remove('selected');
                });
                
                // 设置新选择
                tower.classList.add('selected');
                gameState.selectedTowerType = tower.dataset.type;
            });
        });
        
        canvas.addEventListener('click', (e) => {
            if (!gameState.gameStarted || gameState.gameOver || gameState.gameWon) return;
            
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            // 检查是否点击了防御塔
            for (let tower of gameState.towers) {
                const dx = tower.x - x;
                const dy = tower.y - y;
                const dist = Math.sqrt(dx * dx + dy * dy);
                
                if (dist < 20) {
                    gameState.selectedTower = tower;
                    return;
                }
            }
            
            // 如果没有选择防御塔类型,返回
            if (!gameState.selectedTowerType) return;
            
            // 检查是否在路径上
            let onPath = false;
            ctx.lineWidth = 50;
            for (let i = 0; i < gameState.path.length - 1; i++) {
                const p1 = gameState.path[i];
                const p2 = gameState.path[i + 1];
                
                // 简化检查 - 在实际游戏中需要更精确的碰撞检测
                if (Math.abs(x - p1.x) < 30 && Math.abs(y - p1.y) < 30) onPath = true;
                if (Math.abs(x - p2.x) < 30 && Math.abs(y - p2.y) < 30) onPath = true;
            }
            
            // 检查是否在防御塔上
            let onTower = false;
            for (let tower of gameState.towers) {
                const dx = tower.x - x;
                const dy = tower.y - y;
                const dist = Math.sqrt(dx * dx + dy * dy);
                
                if (dist < 30) {
                    onTower = true;
                    break;
                }
            }
            
            // 如果不在路径上且不在其他防御塔上,并且有足够金币,则建造防御塔
            if (!onPath && !onTower && gameState.gold >= towerTypes[gameState.selectedTowerType].cost) {
                gameState.towers.push(new Tower(x, y, gameState.selectedTowerType));
                gameState.gold -= towerTypes[gameState.selectedTowerType].cost;
                updateStats();
            }
            
            // 取消选择防御塔
            gameState.selectedTower = null;
        });
        
        document.getElementById('start-btn').addEventListener('click', () => {
            if (gameState.gameOver || gameState.gameWon) {
                initGame();
                return;
            }
            
            if (!gameState.gameStarted) {
                gameState.gameStarted = true;
                gameState.wave = 1;
                gameState.enemyCount = 8;
                document.getElementById('start-btn').textContent = "重新开始";
                updateStats();
                updateWaveDots();
            }
        });
        
        document.getElementById('upgrade-btn').addEventListener('click', () => {
            if (gameState.selectedTower && gameState.gold >= 100) {
                gameState.selectedTower.upgrade();
                gameState.gold -= 100;
                updateStats();
            }
        });
        
        document.getElementById('sell-btn').addEventListener('click', () => {
            if (gameState.selectedTower) {
                const index = gameState.towers.indexOf(gameState.selectedTower);
                if (index !== -1) {
                    gameState.gold += Math.floor(towerTypes[gameState.selectedTower.type].cost * 0.7);
                    gameState.towers.splice(index, 1);
                    gameState.selectedTower = null;
                    updateStats();
                }
            }
        });
        
        document.getElementById('pause-btn').addEventListener('click', () => {
            gameState.gameStarted = !gameState.gameStarted;
            document.getElementById('pause-btn').textContent = 
                gameState.gameStarted ? "暂停游戏" : "继续游戏";
        });
        
        // 启动游戏
        initGame();
        gameLoop();
    </script>
</body>
</html>

游戏特点与功能

这个像素塔防游戏具有以下丰富功能:

  1. 多种防御塔类型

    • 基础炮塔:平衡的伤害和射速
    • 狙击塔:远射程、高伤害但射速慢
    • 加农炮:高伤害但射速慢、射程短
    • 冰冻塔:减速敌人
  2. 多样化的敌人

    • 普通敌人:标准属性
    • 快速敌人:移动速度快但生命值低
    • 重型敌人:生命值高但移动速度慢
    • 飞行敌人:平衡型敌人
  3. 游戏系统

    • 资源管理:使用金币建造和升级防御塔
    • 生命系统:敌人到达终点会减少生命值
    • 分数系统:击败敌人获得分数
    • 波数系统:10波逐渐增强的敌人攻击
  4. 视觉效果

    • 像素风格的游戏界面
    • 粒子爆炸效果
    • 动态血条显示
    • 防御塔攻击特效
  5. 用户界面

    • 清晰的游戏状态显示
    • 防御塔选择面板
    • 波数进度指示器
    • 游戏指南和操作说明

游戏玩法指南

  1. 点击"开始游戏"按钮开始游戏
  2. 在左侧面板选择防御塔类型
  3. 点击地图上的空地建造防御塔
  4. 防御塔会自动攻击范围内的敌人
  5. 使用金币建造更多防御塔或升级现有防御塔
  6. 抵御10波敌人攻击即可获胜
  7. 如果敌人到达终点,生命值降为0则游戏结束

游戏采用了响应式设计,可以在各种设备上流畅运行。祝你游戏愉快!

相关推荐
哈__3 小时前
MongoDB 平替新方案:金仓多模数据库驱动电子证照国产化落地
数据库·1024程序员节
奈斯ing3 小时前
【prometheus+Grafana篇】避坑指南:实践中常见问题与解决方案总结整理(持续更新...)
运维·grafana·prometheus·1024程序员节
ʚ希希ɞ ྀ3 小时前
跳跃游戏||----超全写详细解
1024程序员节
wjt1020203 小时前
YOLO5目标检测(续)
1024程序员节
努力学习的小廉3 小时前
我爱学算法之—— 分治-归并
c++·算法·1024程序员节
、、、、南山小雨、、、、3 小时前
pytorch下对各种超参调整效果
1024程序员节
风清再凯3 小时前
02_prometheus监控&Grafana展示
prometheus·1024程序员节
心灵宝贝3 小时前
申威服务器安装Java11(swjdk-11u-9.ky10.sw_64.rpm)详细操作步骤(附安装包)
1024程序员节
傻童:CPU3 小时前
C语言需要掌握的基础知识点之链表
c语言·1024程序员节