坦克大战案例

wen java案例 3

我来为你实现一个完整的坦克大战游戏案例,使用HTML5 Canvas和JavaScript。

坦克大战案例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">坦克大战</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        body {
            background-color: #1a1a1a;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            font-family: 'Arial', sans-serif;
        }
        #gameContainer {
            background-color: #333;
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
        }
        canvas {
            border: 2px solid #444;
            background: #000;
            display: block;
            cursor: crosshair;
        }
        #gameInfo {
            color: white;
            margin-top: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        #score {
            font-size: 18px;
            background: #444;
            padding: 5px 15px;
            border-radius: 20px;
        }
        .btn {
            background: #e74c3c;
            color: white;
            border: none;
            padding: 8px 20px;
            border-radius: 20px;
            cursor: pointer;
            font-size: 16px;
            transition: background 0.3s;
        }
        .btn:hover {
            background: #c0392b;
        }
        .btn:active {
            transform: scale(0.95);
        }
        #controls {
            color: #888;
            font-size: 12px;
            margin-top: 10px;
        }
        #gameOver {
            color: #e74c3c;
            font-weight: bold;
            font-size: 14px;
        }
    </style>
</head>
<body>
    <div id="gameContainer">
        <canvas id="gameCanvas"></canvas>
        <div id="gameInfo">
            <span id="score">得分: 0</span>
            <button id="restartBtn" class="btn">重新开始</button>
            <span id="gameOver"></span>
        </div>
        <div id="controls">
            <p>WASD / 方向键: 移动 | 鼠标: 瞄准 | 左键: 射击 | P: 暂停</p>
        </div>
    </div>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const scoreElement = document.getElementById('score');
        const restartBtn = document.getElementById('restartBtn');
        const gameOverElement = document.getElementById('gameOver');
        // 游戏配置
        const GRID_SIZE = 30;
        canvas.width = 900;
        canvas.height = 600;
        // 游戏状态
        let score = 0;
        let gameRunning = true;
        let paused = false;
        let lastTime = 0;
        // 玩家坦克
        const player = {
            x: canvas.width / 2,
            y: canvas.height - 50,
            width: 40,
            height: 40,
            speed: 200,
            angle: -Math.PI / 2,
            cooldown: 0,
            maxCooldown: 0.2
        };
        // 敌人数组
        let enemies = [];
        // 子弹数组
        let bullets = [];
        // 障碍物数组
        const obstacles = [];
        // 粒子效果
        let particles = [];
        // 生成障碍物
        function generateObstacles() {
            obstacles.length = 0;
            // 第一排
            for (let i = 1; i < 5; i++) {
                obstacles.push({
                    x: i * 150,
                    y: 150,
                    width: GRID_SIZE,
                    height: GRID_SIZE
                });
            }
            // 第二排
            for (let i = 1; i < 5; i++) {
                obstacles.push({
                    x: i * 150,
                    y: 150,
                    width: GRID_SIZE,
                    height: GRID_SIZE
                });
            }
            // 中间障碍
            obstacles.push({ x: 420, y: 250, width: 60, height: 60 });
            obstacles.push({ x: 420, y: 350, width: 60, height: 60 });
            // 侧面障碍
            for (let i = 0; i < 3; i++) {
                obstacles.push({
                    x: 150,
                    y: 200 + i * 80,
                    width: GRID_SIZE,
                    height: GRID_SIZE
                });
                obstacles.push({
                    x: canvas.width - 180,
                    y: 200 + i * 80,
                    width: GRID_SIZE,
                    height: GRID_SIZE
                });
            }
        }
        // 生成敌人
        function spawnEnemy() {
            const enemy = {
                x: Math.random() * (canvas.width - 40) + 20,
                y: 0,
                width: 36,
                height: 36,
                speed: 60 + Math.random() * 80,
                angle: Math.PI / 2,
                pattern: Math.floor(Math.random() * 2),
                changeTimer: 0,
                cooldown: 1 + Math.random() * 2
            };
            // 避免生成在障碍物中
            const maxAttempts = 10;
            for (let i = 0; i < maxAttempts; i++) {
                let collision = false;
                for (const obstacle of obstacles) {
                    if (checkCollision(enemy, obstacle)) {
                        collision = true;
                        break;
                    }
                }
                if (!collision) break;
                enemy.x = Math.random() * (canvas.width - 40) + 20;
                enemy.y = 0;
            }
            enemies.push(enemy);
        }
        // 碰撞检测
        function checkCollision(rect1, rect2) {
            return rect1.x < rect2.x + rect2.width &&
                   rect1.x + rect1.width > rect2.x &&
                   rect1.y < rect2.y + rect2.height &&
                   rect1.y + rect1.height > rect2.y;
        }
        // 键盘控制
        const keys = {};
        document.addEventListener('keydown', (e) => {
            keys[e.key.toLowerCase()] = true;
            if (e.key === 'p' || e.key === 'P') {
                paused = !paused;
                if (!paused) lastTime = performance.now();
            }
        });
        document.addEventListener('keyup', (e) => {
            keys[e.key.toLowerCase()] = false;
        });
        // 鼠标控制
        let mouseX = player.x;
        let mouseY = player.y - 100;
        let mouseDown = false;
        canvas.addEventListener('mousemove', (e) => {
            const rect = canvas.getBoundingClientRect();
            mouseX = e.clientX - rect.left;
            mouseY = e.clientY - rect.top;
        });
        canvas.addEventListener('mousedown', (e) => {
            if (e.button === 0) {
                mouseDown = true;
                shoot();
            }
        });
        canvas.addEventListener('mouseup', (e) => {
            if (e.button === 0) {
                mouseDown = false;
            }
        });
        // 射击
        function shoot() {
            if (player.cooldown <= 0 && gameRunning && !paused) {
                const speed = 400;
                bullets.push({
                    x: player.x + player.width / 2,
                    y: player.y + player.height / 2,
                    vx: Math.cos(player.angle) * speed,
                    vy: Math.sin(player.angle) * speed,
                    isPlayer: true,
                    damage: 1
                });
                player.cooldown = player.maxCooldown;
                // 粒子效果
                for (let i = 0; i < 5; i++) {
                    particles.push({
                        x: player.x + player.width / 2,
                        y: player.y + player.height / 2,
                        vx: Math.cos(player.angle) * 100 + (Math.random() - 0.5) * 100,
                        vy: Math.sin(player.angle) * 100 + (Math.random() - 0.5) * 100,
                        life: 0.2,
                        color: '#FFD700'
                    });
                }
            }
        }
        // 敌人射击
        function enemyShoot(enemy) {
            if (enemy.cooldown <= 0) {
                const dx = player.x + player.width / 2 - (enemy.x + enemy.width / 2);
                const dy = player.y + player.height / 2 - (enemy.y + enemy.height / 2);
                const dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < 300) {
                    const speed = 200;
                    const angle = Math.atan2(dy, dx);
                    bullets.push({
                        x: enemy.x + enemy.width / 2,
                        y: enemy.y + enemy.height / 2,
                        vx: Math.cos(angle) * speed,
                        vy: Math.sin(angle) * speed,
                        isPlayer: false,
                        damage: 1
                    });
                    enemy.cooldown = 1 + Math.random() * 2;
                    // 粒子效果
                    for (let i = 0; i < 3; i++) {
                        particles.push({
                            x: enemy.x + enemy.width / 2,
                            y: enemy.y + enemy.height / 2,
                            vx: Math.cos(angle) * 80 + (Math.random() - 0.5) * 50,
                            vy: Math.sin(angle) * 80 + (Math.random() - 0.5) * 50,
                            life: 0.3,
                            color: '#FF4444'
                        });
                    }
                }
            }
        }
        // 更新游戏
        function update(deltaTime) {
            if (!gameRunning || paused) return;
            // 玩家移动
            const prevX = player.x;
            const prevY = player.y;
            let dx = 0, dy = 0;
            if (keys['w'] || keys['arrowup']) dy = -1;
            if (keys['s'] || keys['arrowdown']) dy = 1;
            if (keys['a'] || keys['arrowleft']) dx = -1;
            if (keys['d'] || keys['arrowright']) dx = 1;
            // 归一化
            const mag = Math.sqrt(dx * dx + dy * dy);
            if (mag > 0) {
                dx /= mag;
                dy /= mag;
                player.x += dx * player.speed * deltaTime;
                player.y += dy * player.speed * deltaTime;
            }
            // 更新角度
            player.angle = Math.atan2(mouseY - (player.y + player.height / 2), mouseX - (player.x + player.width / 2));
            // 边界检测
            player.x = Math.max(0, Math.min(canvas.width - player.width, player.x));
            player.y = Math.max(0, Math.min(canvas.height - player.height, player.y));
            // 障碍物碰撞
            for (const obstacle of obstacles) {
                if (checkCollision(player, obstacle)) {
                    player.x = prevX;
                    player.y = prevY;
                    break;
                }
            }
            // 冷却时间
            if (player.cooldown > 0) {
                player.cooldown -= deltaTime;
            }
            // 连续射击
            if (mouseDown) {
                shoot();
            }
            // 更新子弹
            for (let i = bullets.length - 1; i >= 0; i--) {
                const bullet = bullets[i];
                bullet.x += bullet.vx * deltaTime;
                bullet.y += bullet.vy * deltaTime;
                // 移除超出边界的子弹
                if (bullet.x < 0 || bullet.x > canvas.width || 
                    bullet.y < 0 || bullet.y > canvas.height) {
                    bullets.splice(i, 1);
                    continue;
                }
                // 子弹与障碍物碰撞
                let hitObstacle = false;
                for (const obstacle of obstacles) {
                    if (checkCollision({
                        x: bullet.x - 2,
                        y: bullet.y - 2,
                        width: 4,
                        height: 4
                    }, obstacle)) {
                        hitObstacle = true;
                        break;
                    }
                }
                if (hitObstacle) {
                    // 粒子效果
                    for (let j = 0; j < 4; j++) {
                        particles.push({
                            x: bullet.x,
                            y: bullet.y,
                            vx: (Math.random() - 0.5) * 100,
                            vy: (Math.random() - 0.5) * 100,
                            life: 0.3,
                            color: '#888'
                        });
                    }
                    bullets.splice(i, 1);
                    continue;
                }
                // 子弹与敌人碰撞
                if (bullet.isPlayer) {
                    for (let j = enemies.length - 1; j >= 0; j--) {
                        const enemy = enemies[j];
                        if (checkCollision(bullet, enemy)) {
                            enemies.splice(j, 1);
                            bullets.splice(i, 1);
                            score += 100;
                            scoreElement.textContent = `得分: ${score}`;
                            // 粒子效果
                            for (let k = 0; k < 10; k++) {
                                particles.push({
                                    x: bullet.x,
                                    y: bullet.y,
                                    vx: (Math.random() - 0.5) * 200,
                                    vy: (Math.random() - 0.5) * 200,
                                    life: 0.5,
                                    color: '#FFD700'
                                });
                            }
                            break;
                        }
                    }
                }
                // 子弹与玩家碰撞
                if (!bullet.isPlayer) {
                    if (checkCollision(bullet, player)) {
                        gameOver();
                        return;
                    }
                }
            }
            // 更新敌人
            for (let i = enemies.length - 1; i >= 0; i--) {
                const enemy = enemies[i];
                enemy.changeTimer -= deltaTime;
                // 敌人AI
                if (enemy.changeTimer <= 0) {
                    enemy.changeTimer = 1 + Math.random();
                    if (enemy.pattern === 0) {
                        // 直线移动
                        enemy.angle = Math.PI / 2 + (Math.random() - 0.5) * 0.5;
                    } else {
                        // 追踪玩家
                        const dx = player.x - enemy.x;
                        const dy = player.y - enemy.y;
                        enemy.angle = Math.atan2(dy, dx);
                    }
                }
                enemy.x += Math.cos(enemy.angle) * enemy.speed * deltaTime;
                enemy.y += Math.sin(enemy.angle) * enemy.speed * deltaTime;
                // 边界限制
                enemy.x = Math.max(0, Math.min(canvas.width - enemy.width, enemy.x));
                enemy.y = Math.max(0, Math.min(canvas.height - enemy.height, enemy.y));
                // 障碍物碰撞
                for (const obstacle of obstacles) {
                    if (checkCollision(enemy, obstacle)) {
                        enemy.x -= Math.cos(enemy.angle) * enemy.speed * deltaTime;
                        enemy.y -= Math.sin(enemy.angle) * enemy.speed * deltaTime;
                        enemy.angle += Math.PI * (Math.random() > 0.5 ? 1 : -1);
                        enemy.changeTimer = 0;
                        break;
                    }
                }
                // 更新敌人冷却时间
                if (enemy.cooldown > 0) {
                    enemy.cooldown -= deltaTime;
                }
                // 敌人射击
                enemyShoot(enemy);
                // 检查与玩家的碰撞
                if (checkCollision(enemy, player)) {
                    gameOver();
                    return;
                }
                // 移除超出屏幕的敌人
                if (enemy.y > canvas.height + 50) {
                    enemies.splice(i, 1);
                }
            }
            // 更新粒子
            for (let i = particles.length - 1; i >= 0; i--) {
                const particle = particles[i];
                particle.x += particle.vx * deltaTime;
                particle.y += particle.vy * deltaTime;
                particle.life -= deltaTime;
                if (particle.life <= 0) {
                    particles.splice(i, 1);
                }
            }
            // 生成敌人
            if (Math.random() < 0.3 * deltaTime && enemies.length < 10) {
                spawnEnemy();
            }
        }
        // 绘制坦克
        function drawTank(x, y, angle, isPlayer) {
            const size = 20;
            ctx.save();
            // 坦克身体
            const centerX = x + 20;
            const centerY = y + 20;
            ctx.translate(centerX, centerY);
            ctx.rotate(angle);
            // 身体
            ctx.fillStyle = isPlayer ? '#2ECC40' : '#FF4136';
            ctx.fillRect(-15, -12, 30, 24);
            ctx.strokeStyle = '#111';
            ctx.strokeRect(-15, -12, 30, 24);
            // 履带
            ctx.fillStyle = '#555';
            ctx.fillRect(-18, -14, 8, 28);
            ctx.fillRect(10, -14, 8, 28);
            // 炮管
            ctx.fillStyle = '#333';
            ctx.fillRect(-5, -18, 10, 36);
            ctx.strokeStyle = '#111';
            ctx.strokeRect(-5, -18, 10, 36);
            // 履带纹理
            ctx.fillStyle = '#666';
            for (let i = -12; i <= 12; i += 8) {
                ctx.fillRect(-17, i, 6, 3);
                ctx.fillRect(11, i, 6, 3);
            }
            // 舱盖
            ctx.fillStyle = isPlayer ? '#27AE60' : '#C0392B';
            ctx.beginPath();
            ctx.arc(-8, 0, 8, 0, Math.PI * 2);
            ctx.fill();
            ctx.stroke();
            ctx.restore();
        }
        // 绘制
        function draw() {
            // 清屏
            ctx.fillStyle = '#1a1a1a';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            // 迷你地图格线
            ctx.strokeStyle = 'rgba(255, 255, 255, 0.03)';
            ctx.lineWidth = 1;
            for (let i = 0; i < canvas.width; i += GRID_SIZE) {
                ctx.beginPath();
                ctx.moveTo(i, 0);
                ctx.lineTo(i, canvas.height);
                ctx.stroke();
            }
            for (let i = 0; i < canvas.height; i += GRID_SIZE) {
                ctx.beginPath();
                ctx.moveTo(0, i);
                ctx.lineTo(canvas.width, i);
                ctx.stroke();
            }
            // 绘制障碍物
            for (const obstacle of obstacles) {
                ctx.fillStyle = '#7F8C8D';
                ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
                ctx.strokeStyle = '#5D6D7E';
                ctx.strokeRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
                // 障碍物纹理
                ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)';
                ctx.beginPath();
                ctx.moveTo(obstacle.x, obstacle.y);
                ctx.lineTo(obstacle.x + obstacle.width, obstacle.y + obstacle.height);
                ctx.moveTo(obstacle.x + obstacle.width, obstacle.y);
                ctx.lineTo(obstacle.x, obstacle.y + obstacle.height);
                ctx.stroke();
            }
            // 绘制子弹
            for (const bullet of bullets) {
                ctx.save();
                ctx.beginPath();
                ctx.arc(bullet.x, bullet.y, 3, 0, Math.PI * 2);
                ctx.fillStyle = bullet.isPlayer ? '#FFD700' : '#FF4444';
                ctx.fill();
                ctx.strokeStyle = '#111';
                ctx.stroke();
                ctx.restore();
            }
            // 绘制敌人
            for (const enemy of enemies) {
                drawTank(enemy.x, enemy.y, enemy.angle, false);
            }
            // 绘制玩家
            drawTank(player.x, player.y, player.angle, true);
            // 绘制粒子
            for (const particle of particles) {
                const alpha = particle.life / 0.5;
                ctx.save();
                ctx.globalAlpha = Math.max(0, alpha);
                ctx.fillStyle = particle.color;
                ctx.fillRect(particle.x - 3, particle.y - 3, 6, 6);
                ctx.restore();
            }
            // 绘制鼠标瞄准点
            if (gameRunning) {
                ctx.save();
                ctx.strokeStyle = '#FFD700';
                ctx.lineWidth = 2;
                ctx.beginPath();
                ctx.arc(mouseX, mouseY, 15, 0, Math.PI * 2);
                ctx.stroke();
                // 十字线
                ctx.beginPath();
                ctx.moveTo(mouseX - 20, mouseY);
                ctx.lineTo(mouseX + 20, mouseY);
                ctx.moveTo(mouseX, mouseY - 20);
                ctx.lineTo(mouseX, mouseY + 20);
                ctx.stroke();
                ctx.restore();
            }
            // 暂停提示
            if (paused && gameRunning) {
                ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.fillStyle = 'white';
                ctx.font = '48px Arial';
                ctx.textAlign = 'center';
                ctx.fillText('⏸ 已暂停', canvas.width / 2, canvas.height / 2);
            }
            // 游戏结束提示
            if (!gameRunning) {
                ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.fillStyle = '#FF4444';
                ctx.font = '48px Arial';
                ctx.textAlign = 'center';
                ctx.fillText('游戏结束', canvas.width / 2, canvas.height / 2 - 20);
                ctx.fillStyle = 'white';
                ctx.font = '24px Arial';
                ctx.fillText(`得分: ${score}`, canvas.width / 2, canvas.height / 2 + 30);
            }
        }
        // 游戏结束
        function gameOver() {
            gameRunning = false;
            gameOverElement.textContent = '✖';
        }
        // 重新开始游戏
        function restartGame() {
            score = 0;
            scoreElement.textContent = '得分: 0';
            enemies.length = 0;
            bullets.length = 0;
            particles.length = 0;
            gameRunning = true;
            paused = false;
            gameOverElement.textContent = '';
            player.x = canvas.width / 2;
            player.y = canvas.height - 50;
            player.cooldown = 0;
            generateObstacles();
            // 初始敌人
            for (let i = 0; i < 3; i++) {
                spawnEnemy();
            }
        }
        // 游戏循环
        function gameLoop(timestamp) {
            const deltaTime = Math.min((timestamp - lastTime) / 1000, 0.1);
            lastTime = timestamp;
            if (!paused && gameRunning) {
                update(deltaTime);
            }
            draw();
            requestAnimationFrame(gameLoop);
        }
        // 初始化
        restartBtn.addEventListener('click', restartGame);
        generateObstacles();
        // 初始敌人
        for (let i = 0; i < 3; i++) {
            spawnEnemy();
        }
        lastTime = performance.now();
        requestAnimationFrame(gameLoop);
    </script>
</body>
</html>

游戏功能说明:

🎮 控制方式

  • WASD / 方向键:移动坦克
  • 鼠标移动:瞄准
  • 鼠标左键:射击(可长按连射)
  • P 键:暂停/继续游戏

🎯 游戏特色

  1. 敌人AI系统

    • 敌人会追踪玩家
    • 敌人会射击
    • 不同的移动模式
  2. 障碍物系统

    • 固定障碍物会阻挡坦克和子弹
    • 坦克不能穿越障碍物
  3. 视觉效果

    • 发射和爆炸粒子效果
    • 坦克转向动画
    • 瞄准准星
  4. 游戏机制

    • 实时的得分系统
    • 游戏结束检测
    • 重新开始功能

🕹️ 游戏技巧

  • 利用障碍物躲避敌人子弹
  • 不断移动避免被敌人瞄准
  • 优先消灭靠近的敌人
  • 适时使用连射模式

这是一个完整的坦克大战游戏,你可以将它保存为 HTML 文件并在浏览器中运行,游戏包含了现代坦克游戏的核心机制,并且代码结构清晰,容易理解和扩展。

上一篇贪吃蛇案例

下一篇Java游戏案例

抱歉,评论功能暂时关闭!