经典坦克大战游戏,作为街机游戏的代表之一,玩家控制一辆坦克,射击敌人并避免被敌人击中。这个游戏充满了动作和策略,每一局的战斗都紧张刺激。而制作一个经典的坦克大战游戏,看似简单,但其实需要处理坦克的移动、射击、敌人的生成与AI、碰撞检测等多个复杂的游戏逻辑。
过去,开发一个坦克大战游戏通常需要自己编写大量的代码,处理坦克的控制、敌人生成、子弹发射与碰撞检测等各个方面。而且,设计战斗和AI智能也是一项繁琐的任务。然而,自从我开始使用 Trae IDE,游戏开发变得轻松而有趣。接下来,我将分享如何通过 Trae 快速实现经典坦克大战游戏,让你轻松体验这款经典街机游戏。
💡 我的需求其实很简单
我的需求非常明确:制作一个经典的坦克大战游戏,功能要求如下:
- 坦克控制:玩家能够通过键盘控制坦克的移动,并发射子弹。
- 敌人生成:敌人坦克会自动生成并向玩家发起攻击。
- 战斗逻辑:玩家需要避免被敌人击中,并击毁敌人坦克。
- 街机风格:游戏需要拥有经典街机游戏的风格,简洁的UI,丰富的战斗体验。
虽然游戏的核心玩法并不复杂,但涉及到坦克控制、敌人AI和战斗逻辑的处理,手动编写这些功能代码可能会花费不少时间。
✨ Trae 如何理解需求并生成代码?
我只需要在 Trae 中输入一句话:
"生成一个经典坦克大战游戏,玩家控制坦克射击敌人,避免被敌人击中。"
Trae 立即解析并生成了一个完整的游戏代码,包括:
- 坦克控制:玩家可以通过键盘的上下左右键来控制坦克的移动,空格键发射子弹。
- 敌人生成与AI:敌人坦克会自动生成,并不断向玩家发起攻击。敌人会智能地向玩家移动并进行射击。
- 碰撞检测与战斗逻辑:玩家的子弹会击中敌人坦克并销毁它,而敌人的子弹会击中玩家坦克并导致失败。
- 简洁的UI:游戏界面采用经典的街机风格,界面简洁,操作直观。

只需要输入简单的指令,Trae 就能够自动生成完整的坦克大战游戏,并且为我提供了简洁的UI和完善的战斗逻辑。
🧩 游戏操作直观,战斗充满挑战
Trae 生成的坦克大战游戏操作非常简单,玩家可以使用键盘的方向键来控制坦克移动,通过空格键发射子弹。每当玩家射中敌人时,敌人坦克会被销毁,游戏画面也会即时更新。而敌人坦克则会持续向玩家发起攻击,玩家需要时刻保持警惕,避免被敌人击中。
游戏的AI智能也非常强大,敌人坦克能够根据玩家的移动做出反应,并适时发射子弹,让每一局游戏都充满了挑战。随着敌人数量的增加,游戏的难度也在逐渐上升,让玩家感受到真正的战斗压力。
🛠 游戏拓展,功能轻松加
虽然 Trae 生成的坦克大战游戏已经非常完善,但它也支持轻松添加更多功能。例如:
- 多种敌人类型:可以增加不同类型的敌人,例如具有不同攻击模式和更高AI的坦克。
- 关卡设计:可以设计不同的关卡,每个关卡有不同的敌人和难度。
- 得分系统:记录玩家击毁敌人的数量,并显示总分。
- 重生机制:增加一个机制,让玩家在被击中后重新出现在游戏中,继续进行战斗。
这些拓展功能都可以通过简单的指令描述,Trae 就能自动生成并集成到现有的游戏中。
这就是游戏开发的未来
通过这次坦克大战游戏的开发,我深刻感受到了 Trae 带来的便利。从坦克控制到敌人生成与AI,再到碰撞检测和战斗逻辑,Trae 都能快速生成完整的代码,并提供经典的街机风格UI。以前需要手动编写的复杂游戏逻辑,现在只需要输入简单的指令,就能轻松实现。
对于独立开发者或小团队来说,Trae 无疑是一个非常高效的工具,它帮助我节省了大量的开发时间,让我可以更加专注于游戏的创意和功能拓展。
结语
如果你也想制作一个经典的坦克大战游戏,试试 Trae IDE,输入类似的需求:
"生成一个经典坦克大战游戏,玩家控制坦克射击敌人,避免被敌人击中。"
几秒钟内,Trae 就会生成完整的游戏代码,带有智能敌人AI、坦克控制、战斗逻辑和街机风格的UI设计。你可以直接将它嵌入到你的项目中,甚至根据需求继续扩展和优化。
快来体验一下 Trae,让你的游戏开发变得更加轻松、有趣、充满挑战!
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>
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #222;
font-family: Arial, sans-serif;
color: #fff;
}
.game-container {
position: relative;
width: 800px;
height: 600px;
background-color: #000;
overflow: hidden;
border: 2px solid #444;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
}
#game-canvas {
display: block;
background-color: #000;
}
.controls {
margin-top: 20px;
display: flex;
gap: 20px;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #45a049;
}
.game-info {
margin-top: 10px;
display: flex;
justify-content: space-between;
width: 800px;
}
.score, .lives, .level {
font-size: 18px;
font-weight: bold;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.8);
padding: 20px 40px;
border-radius: 10px;
text-align: center;
display: none;
}
.game-over h2 {
color: #ff0000;
font-size: 36px;
margin-bottom: 20px;
}
.instructions {
margin-top: 20px;
background-color: #333;
padding: 15px;
border-radius: 5px;
width: 800px;
}
.instructions h3 {
margin-top: 0;
color: #4CAF50;
}
.instructions ul {
padding-left: 20px;
}
</style>
</head>
<body>
<h1>坦克大战</h1>
<div class="game-info">
<div class="score">分数: <span id="score">0</span></div>
<div class="level">关卡: <span id="level">1</span></div>
<div class="lives">生命: <span id="lives">3</span></div>
</div>
<div class="game-container">
<canvas id="game-canvas" width="800" height="600"></canvas>
<div class="game-over" id="game-over">
<h2>游戏结束</h2>
<p>你的最终分数: <span id="final-score">0</span></p>
<button id="restart-btn">重新开始</button>
</div>
</div>
<div class="controls">
<button id="start-btn">开始游戏</button>
<button id="pause-btn">暂停</button>
</div>
<div class="instructions">
<h3>游戏说明:</h3>
<ul>
<li>使用方向键(↑ ↓ ← →)控制坦克移动</li>
<li>按空格键发射子弹</li>
<li>摧毁敌方坦克获得分数</li>
<li>避免被敌方坦克击中</li>
<li>保护你的基地不被摧毁</li>
</ul>
</div>
<script>
// 游戏常量
const TANK_SIZE = 40;
const BULLET_SIZE = 8;
const BULLET_SPEED = 5;
const PLAYER_SPEED = 3;
const ENEMY_SPEED = 1.5;
const BRICK_SIZE = 40;
const EXPLOSION_DURATION = 500; // 爆炸动画持续时间(毫秒)
// 游戏状态
let gameRunning = false;
let gamePaused = false;
let score = 0;
let lives = 3;
let level = 1;
let enemySpawnRate = 3000; // 敌人生成间隔(毫秒)
let lastEnemySpawn = 0;
let maxEnemies = 5; // 同时存在的最大敌人数量
// 游戏对象
let player;
let bullets = [];
let enemies = [];
let enemyBullets = [];
let walls = [];
let explosions = [];
let base;
// 图像资源
const images = {};
const imageUrls = {
playerTank: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHJlY3QgeD0iNSIgeT0iNSIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIiBmaWxsPSIjNWNiODUwIiByeD0iMyIgcnk9IjMiLz48cmVjdCB4PSIxNSIgeT0iMCIgd2lkdGg9IjEwIiBoZWlnaHQ9IjIwIiBmaWxsPSIjNWNiODUwIi8+PGNpcmNsZSBjeD0iMjAiIGN5PSIyMCIgcj0iOCIgZmlsbD0iIzM4NzAzMCIvPjxyZWN0IHg9IjAiIHk9IjEyIiB3aWR0aD0iNDAiIGhlaWdodD0iMTYiIGZpbGw9IiM1Y2I4NTAiIHJ4PSIzIiByeT0iMyIvPjwvc3ZnPg==',
enemyTank: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHJlY3QgeD0iNSIgeT0iNSIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIiBmaWxsPSIjZDk1MzRmIiByeD0iMyIgcnk9IjMiLz48cmVjdCB4PSIxNSIgeT0iMCIgd2lkdGg9IjEwIiBoZWlnaHQ9IjIwIiBmaWxsPSIjZDk1MzRmIi8+PGNpcmNsZSBjeD0iMjAiIGN5PSIyMCIgcj0iOCIgZmlsbD0iIzk5MzMzMCIvPjxyZWN0IHg9IjAiIHk9IjEyIiB3aWR0aD0iNDAiIGhlaWdodD0iMTYiIGZpbGw9IiNkOTUzNGYiIHJ4PSIzIiByeT0iMyIvPjwvc3ZnPg==',
brick: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIiBmaWxsPSIjYTU2NzNmIi8+PHJlY3QgeD0iMjAiIHk9IjAiIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0iIzhkNTUzNSIvPjxyZWN0IHg9IjAiIHk9IjIwIiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIGZpbGw9IiM4ZDU1MzUiLz48cmVjdCB4PSIyMCIgeT0iMjAiIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2E1NjczZiIvPjwvc3ZnPg==',
steel: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIiBmaWxsPSIjNzA3MDcwIi8+PHJlY3QgeD0iMiIgeT0iMiIgd2lkdGg9IjM2IiBoZWlnaHQ9IjM2IiBmaWxsPSIjYTBhMGEwIi8+PHJlY3QgeD0iNSIgeT0iNSIgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIiBmaWxsPSIjODA4MDgwIi8+PC9zdmc+',
base: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIiBmaWxsPSIjMzMzIi8+PHBvbHlnb24gcG9pbnRzPSIyMCwwIDQwLDIwIDIwLDQwIDAsMjAiIGZpbGw9IiNmZmNjMDAiLz48Y2lyY2xlIGN4PSIyMCIgY3k9IjIwIiByPSIxMCIgZmlsbD0iI2ZmMDAwMCIvPjxjaXJjbGUgY3g9IjIwIiBjeT0iMjAiIHI9IjUiIGZpbGw9IiNmZmZmMDAiLz48L3N2Zz4=',
explosion: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MCA0MCI+PGNpcmNsZSBjeD0iMjAiIGN5PSIyMCIgcj0iMTgiIGZpbGw9IiNmZjk5MDAiLz48Y2lyY2xlIGN4PSIyMCIgY3k9IjIwIiByPSIxMiIgZmlsbD0iI2ZmY2MwMCIvPjxjaXJjbGUgY3g9IjIwIiBjeT0iMjAiIHI9IjYiIGZpbGw9IiNmZmZmMDAiLz48cGF0aCBkPSJNMTAsMCBMMzAsMCBMMjAsMTAgWiIgZmlsbD0iI2ZmOTkwMCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAsIDApIHJvdGF0ZSgwKSIvPjxwYXRoIGQ9Ik0xMCwwIEwzMCwwIEwyMCwxMCBaIiBmaWxsPSIjZmY5OTAwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0MCwgMjApIHJvdGF0ZSg5MCkiLz48cGF0aCBkPSJNMTAsMCBMMzAsMCBMMjAsMTAgWiIgZmlsbD0iI2ZmOTkwMCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAsIDQwKSByb3RhdGUoMTgwKSIvPjxwYXRoIGQ9Ik0xMCwwIEwzMCwwIEwyMCwxMCBaIiBmaWxsPSIjZmY5OTAwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLCAyMCkgcm90YXRlKDI3MCkiLz48L3N2Zz4='
};
// DOM 元素
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
const startBtn = document.getElementById('start-btn');
const pauseBtn = document.getElementById('pause-btn');
const restartBtn = document.getElementById('restart-btn');
const gameOverEl = document.getElementById('game-over');
const scoreEl = document.getElementById('score');
const livesEl = document.getElementById('lives');
const levelEl = document.getElementById('level');
const finalScoreEl = document.getElementById('final-score');
// 加载图像资源
function loadImages() {
const promises = [];
for (const key in imageUrls) {
const img = new Image();
img.src = imageUrls[key];
images[key] = img;
const promise = new Promise(resolve => {
img.onload = resolve;
});
promises.push(promise);
}
return Promise.all(promises);
}
// 初始化游戏
function initGame() {
// 创建玩家坦克
player = {
x: canvas.width / 2 - TANK_SIZE / 2,
y: canvas.height - TANK_SIZE - 20,
width: TANK_SIZE,
height: TANK_SIZE,
direction: 'up',
lastShot: 0,
shootDelay: 300 // 射击延迟(毫秒)
};
// 创建基地
base = {
x: canvas.width / 2 - TANK_SIZE / 2,
y: canvas.height - TANK_SIZE,
width: TANK_SIZE,
height: TANK_SIZE
};
// 创建墙壁
createWalls();
// 重置游戏状态
bullets = [];
enemies = [];
enemyBullets = [];
explosions = [];
score = 0;
lives = 3;
level = 1;
enemySpawnRate = 3000;
maxEnemies = 5;
// 更新UI
updateUI();
}
// 创建墙壁
function createWalls() {
walls = [];
// 基地周围的墙
const baseX = base.x;
const baseY = base.y;
// 左侧墙
walls.push({ x: baseX - BRICK_SIZE, y: baseY, width: BRICK_SIZE, height: BRICK_SIZE, type: 'brick' });
walls.push({ x: baseX - BRICK_SIZE, y: baseY - BRICK_SIZE, width: BRICK_SIZE, height: BRICK_SIZE, type: 'brick' });
// 右侧墙
walls.push({ x: baseX + TANK_SIZE, y: baseY, width: BRICK_SIZE, height: BRICK_SIZE, type: 'brick' });
walls.push({ x: baseX + TANK_SIZE, y: baseY - BRICK_SIZE, width: BRICK_SIZE, height: BRICK_SIZE, type: 'brick' });
// 上方墙
walls.push({ x: baseX, y: baseY - BRICK_SIZE, width: BRICK_SIZE, height: BRICK_SIZE, type: 'brick' });
// 添加随机墙壁
const gridSize = BRICK_SIZE;
const gridWidth = canvas.width / gridSize;
const gridHeight = canvas.height / gridSize;
// 创建一些随机的砖墙
for (let i = 0; i < 30; i++) {
const x = Math.floor(Math.random() * (gridWidth - 2) + 1) * gridSize;
const y = Math.floor(Math.random() * (gridHeight - 6) + 1) * gridSize;
// 确保不会在玩家初始位置创建墙
if (Math.abs(x - player.x) > TANK_SIZE * 2 || Math.abs(y - player.y) > TANK_SIZE * 2) {
walls.push({ x, y, width: BRICK_SIZE, height: BRICK_SIZE, type: 'brick' });
}
}
// 创建一些钢墙(不可摧毁)
for (let i = 0; i < 10; i++) {
const x = Math.floor(Math.random() * (gridWidth - 2) + 1) * gridSize;
const y = Math.floor(Math.random() * (gridHeight - 6) + 1) * gridSize;
// 确保不会在玩家初始位置创建墙
if (Math.abs(x - player.x) > TANK_SIZE * 2 || Math.abs(y - player.y) > TANK_SIZE * 2) {
walls.push({ x, y, width: BRICK_SIZE, height: BRICK_SIZE, type: 'steel' });
}
}
}
// 生成敌人
function spawnEnemy() {
if (enemies.length >= maxEnemies) return;
const spawnPoints = [
{ x: 0, y: 0 },
{ x: canvas.width / 2 - TANK_SIZE / 2, y: 0 },
{ x: canvas.width - TANK_SIZE, y: 0 }
];
const spawnPoint = spawnPoints[Math.floor(Math.random() * spawnPoints.length)];
// 检查是否与现有敌人重叠
for (const enemy of enemies) {
if (Math.abs(enemy.x - spawnPoint.x) < TANK_SIZE && Math.abs(enemy.y - spawnPoint.y) < TANK_SIZE) {
return; // 如果重叠,不生成新敌人
}
}
const directions = ['down', 'left', 'right'];
const enemy = {
x: spawnPoint.x,
y: spawnPoint.y,
width: TANK_SIZE,
height: TANK_SIZE,
direction: directions[Math.floor(Math.random() * directions.length)],
lastShot: 0,
shootDelay: 1500 + Math.random() * 1500, // 随机射击延迟
moveTimer: 0,
moveDelay: 1000 + Math.random() * 1000, // 随机移动延迟
speed: ENEMY_SPEED * (1 + level * 0.1) // 随着关卡增加速度
};
enemies.push(enemy);
}
// 更新游戏状态
function update(timestamp) {
if (!gameRunning || gamePaused) return;
// 生成敌人
if (timestamp - lastEnemySpawn > enemySpawnRate) {
spawnEnemy();
lastEnemySpawn = timestamp;
}
// 更新玩家子弹
updateBullets(bullets);
// 更新敌人子弹
updateBullets(enemyBullets);
// 更新敌人
updateEnemies(timestamp);
// 更新爆炸效果
updateExplosions(timestamp);
// 检查关卡进度
checkLevelProgress();
}
// 更新子弹位置和碰撞
function updateBullets(bulletArray) {
for (let i = bulletArray.length - 1; i >= 0; i--) {
const bullet = bulletArray[i];
// 根据方向移动子弹
switch (bullet.direction) {
case 'up':
bullet.y -= BULLET_SPEED;
break;
case 'down':
bullet.y += BULLET_SPEED;
break;
case 'left':
bullet.x -= BULLET_SPEED;
break;
case 'right':
bullet.x += BULLET_SPEED;
break;
}
// 检查子弹是否超出边界
if (bullet.x < 0 || bullet.x > canvas.width || bullet.y < 0 || bullet.y > canvas.height) {
bulletArray.splice(i, 1);
continue;
}
// 检查子弹与墙壁碰撞
let hitWall = false;
for (let j = walls.length - 1; j >= 0; j--) {
const wall = walls[j];
if (checkCollision(bullet, wall)) {
bulletArray.splice(i, 1);
// 只有砖墙可以被摧毁
if (wall.type === 'brick') {
walls.splice(j, 1);
createExplosion(bullet.x, bullet.y, 0.5);
}
hitWall = true;
break;
}
}
if (hitWall) continue;
// 检查玩家子弹与敌人碰撞
if (bulletArray === bullets) {
for (let j = enemies.length - 1; j >= 0; j--) {
const enemy = enemies[j];
if (checkCollision(bullet, enemy)) {
bulletArray.splice(i, 1);
enemies.splice(j, 1);
createExplosion(enemy.x + enemy.width / 2, enemy.y + enemy.height / 2, 1);
score += 100;
updateUI();
break;
}
}
}
// 检查敌人子弹与玩家碰撞
if (bulletArray === enemyBullets && player.alive !== false) {
if (checkCollision(bullet, player)) {
bulletArray.splice(i, 1);
playerHit();
break;
}
}
// 检查子弹与基地碰撞
if (checkCollision(bullet, base)) {
bulletArray.splice(i, 1);
createExplosion(base.x + base.width / 2, base.y + base.height / 2, 1.5);
gameOver();
break;
}
}
}
// 更新敌人行为
function updateEnemies(timestamp) {
for (let i = 0; i < enemies.length; i++) {
const enemy = enemies[i];
// 敌人射击
if (timestamp - enemy.lastShot > enemy.shootDelay) {
enemyShoot(enemy);
enemy.lastShot = timestamp;
}
// 敌人移动
if (timestamp - enemy.moveTimer > enemy.moveDelay) {
// 随机改变方向
const directions = ['up', 'down', 'left', 'right'];
enemy.direction = directions[Math.floor(Math.random() * directions.length)];
enemy.moveTimer = timestamp;
enemy.moveDelay = 1000 + Math.random() * 1000;
}
// 根据方向移动敌人
let newX = enemy.x;
let newY = enemy.y;
switch (enemy.direction) {
case 'up':
newY -= enemy.speed;
break;
case 'down':
newY += enemy.speed;
break;
case 'left':
newX -= enemy.speed;
break;
case 'right':
newX += enemy.speed;
break;
}
// 检查边界碰撞
if (newX < 0) {
newX = 0;
enemy.direction = 'right';
} else if (newX + enemy.width > canvas.width) {
newX = canvas.width - enemy.width;
enemy.direction = 'left';
}
if (newY < 0) {
newY = 0;
enemy.direction = 'down';
} else if (newY + enemy.height > canvas.height) {
newY = canvas.height - enemy.height;
enemy.direction = 'up';
}
// 检查与墙壁碰撞
const tempEnemy = { ...enemy, x: newX, y: newY };
let wallCollision = false;
for (const wall of walls) {
if (checkCollision(tempEnemy, wall)) {
wallCollision = true;
break;
}
}
// 检查与其他敌人碰撞
let enemyCollision = false;
for (const otherEnemy of enemies) {
if (otherEnemy === enemy) continue;
if (checkCollision(tempEnemy, otherEnemy)) {
enemyCollision = true;
break;
}
}
// 检查与玩家碰撞
let playerCollision = false;
if (player.alive !== false && checkCollision(tempEnemy, player)) {
playerCollision = true;
}
// 检查与基地碰撞
let baseCollision = false;
if (checkCollision(tempEnemy, base)) {
baseCollision = true;
}
// 如果没有碰撞,更新位置
if (!wallCollision && !enemyCollision && !playerCollision && !baseCollision) {
enemy.x = newX;
enemy.y = newY;
} else {
// 如果有碰撞,改变方向
const directions = ['up', 'down', 'left', 'right'];
enemy.direction = directions[Math.floor(Math.random() * directions.length)];
}
}
}
// 更新爆炸效果
function updateExplosions(timestamp) {
for (let i = explosions.length - 1; i >= 0; i--) {
const explosion = explosions[i];
if (timestamp - explosion.startTime > EXPLOSION_DURATION) {
explosions.splice(i, 1);
}
}
}
// 检查关卡进度
function checkLevelProgress() {
// 如果消灭了足够多的敌人,进入下一关
if (score >= level * 1000) {
level++;
enemySpawnRate = Math.max(1000, 3000 - level * 200); // 随着关卡增加,敌人生成速度加快
maxEnemies = Math.min(10, 5 + Math.floor(level / 2)); // 随着关卡增加,最大敌人数量增加
updateUI();
// 创建新的墙壁布局
createWalls();
}
}
// 玩家被击中
function playerHit() {
lives--;
updateUI();
createExplosion(player.x + player.width / 2, player.y + player.height / 2, 1);
// 暂时使玩家无敌
player.alive = false;
// 如果还有生命,重生玩家
if (lives > 0) {
setTimeout(() => {
player.x = canvas.width / 2 - TANK_SIZE / 2;
player.y = canvas.height - TANK_SIZE - 20;
player.direction = 'up';
player.alive = true;
}, 1000);
} else {
gameOver();
}
}
// 游戏结束
function gameOver() {
gameRunning = false;
finalScoreEl.textContent = score;
gameOverEl.style.display = 'block';
}
// 敌人射击
function enemyShoot(enemy) {
const bulletX = enemy.x + enemy.width / 2 - BULLET_SIZE / 2;
const bulletY = enemy.y + enemy.height / 2 - BULLET_SIZE / 2;
// 根据敌人方向调整子弹位置
switch (enemy.direction) {
case 'up':
enemyBullets.push({ x: bulletX, y: enemy.y - BULLET_SIZE, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'up' });
break;
case 'down':
enemyBullets.push({ x: bulletX, y: enemy.y + enemy.height, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'down' });
break;
case 'left':
enemyBullets.push({ x: enemy.x - BULLET_SIZE, y: bulletY, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'left' });
break;
case 'right':
enemyBullets.push({ x: enemy.x + enemy.width, y: bulletY, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'right' });
break;
}
}
// 玩家射击
function playerShoot() {
if (!gameRunning || gamePaused || player.alive === false) return;
const now = Date.now();
if (now - player.lastShot < player.shootDelay) return;
player.lastShot = now;
const bulletX = player.x + player.width / 2 - BULLET_SIZE / 2;
const bulletY = player.y + player.height / 2 - BULLET_SIZE / 2;
// 根据玩家方向调整子弹位置
switch (player.direction) {
case 'up':
bullets.push({ x: bulletX, y: player.y - BULLET_SIZE, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'up' });
break;
case 'down':
bullets.push({ x: bulletX, y: player.y + player.height, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'down' });
break;
case 'left':
bullets.push({ x: player.x - BULLET_SIZE, y: bulletY, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'left' });
break;
case 'right':
bullets.push({ x: player.x + player.width, y: bulletY, width: BULLET_SIZE, height: BULLET_SIZE, direction: 'right' });
break;
}
}
// 创建爆炸效果
function createExplosion(x, y, scale = 1) {
explosions.push({
x: x - (TANK_SIZE * scale) / 2,
y: y - (TANK_SIZE * scale) / 2,
width: TANK_SIZE * scale,
height: TANK_SIZE * scale,
startTime: Date.now()
});
}
// 检查碰撞
function checkCollision(obj1, obj2) {
return obj1.x < obj2.x + obj2.width &&
obj1.x + obj1.width > obj2.x &&
obj1.y < obj2.y + obj2.height &&
obj1.y + obj1.height > obj2.y;
}
// 渲染游戏
function render() {
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制墙壁
for (const wall of walls) {
const img = wall.type === 'brick' ? images.brick : images.steel;
ctx.drawImage(img, wall.x, wall.y, wall.width, wall.height);
}
// 绘制基地
ctx.drawImage(images.base, base.x, base.y, base.width, base.height);
// 绘制玩家
if (player.alive !== false) {
// 保存当前状态
ctx.save();
// 移动到坦克中心
ctx.translate(player.x + player.width / 2, player.y + player.height / 2);
// 根据方向旋转
switch (player.direction) {
case 'up':
ctx.rotate(0);
break;
case 'right':
ctx.rotate(Math.PI / 2);
break;
case 'down':
ctx.rotate(Math.PI);
break;
case 'left':
ctx.rotate(-Math.PI / 2);
break;
}
// 绘制坦克(中心点在原点)
ctx.drawImage(images.playerTank, -player.width / 2, -player.height / 2, player.width, player.height);
// 恢复状态
ctx.restore();
}
// 绘制敌人
for (const enemy of enemies) {
// 保存当前状态
ctx.save();
// 移动到坦克中心
ctx.translate(enemy.x + enemy.width / 2, enemy.y + enemy.height / 2);
// 根据方向旋转
switch (enemy.direction) {
case 'up':
ctx.rotate(0);
break;
case 'right':
ctx.rotate(Math.PI / 2);
break;
case 'down':
ctx.rotate(Math.PI);
break;
case 'left':
ctx.rotate(-Math.PI / 2);
break;
}
// 绘制坦克(中心点在原点)
ctx.drawImage(images.enemyTank, -enemy.width / 2, -enemy.height / 2, enemy.width, enemy.height);
// 恢复状态
ctx.restore();
}
// 绘制玩家子弹
ctx.fillStyle = '#5cb850';
for (const bullet of bullets) {
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
}
// 绘制敌人子弹
ctx.fillStyle = '#d9534f';
for (const bullet of enemyBullets) {
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
}
// 绘制爆炸效果
for (const explosion of explosions) {
ctx.drawImage(images.explosion, explosion.x, explosion.y, explosion.width, explosion.height);
}
}
// 更新UI
function updateUI() {
scoreEl.textContent = score;
livesEl.textContent = lives;
levelEl.textContent = level;
}
// 游戏循环
let lastTime = 0;
function gameLoop(timestamp) {
if (!lastTime) lastTime = timestamp;
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
update(timestamp);
render();
requestAnimationFrame(gameLoop);
}
// 键盘控制
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.key] = true;
// 空格键射击
if (e.key === ' ') {
playerShoot();
}
// 防止方向键滚动页面
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(e.key)) {
e.preventDefault();
}
});
window.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
// 处理玩家移动
function handlePlayerMovement() {
if (!gameRunning || gamePaused || player.alive === false) return;
let newX = player.x;
let newY = player.y;
let directionChanged = false;
if (keys['ArrowUp']) {
newY -= PLAYER_SPEED;
if (player.direction !== 'up') {
player.direction = 'up';
directionChanged = true;
}
} else if (keys['ArrowDown']) {
newY += PLAYER_SPEED;
if (player.direction !== 'down') {
player.direction = 'down';
directionChanged = true;
}
} else if (keys['ArrowLeft']) {
newX -= PLAYER_SPEED;
if (player.direction !== 'left') {
player.direction = 'left';
directionChanged = true;
}
} else if (keys['ArrowRight']) {
newX += PLAYER_SPEED;
if (player.direction !== 'right') {
player.direction = 'right';
directionChanged = true;
}
}
// 如果只是改变方向,不需要检查碰撞
if (directionChanged && newX === player.x && newY === player.y) {
return;
}
// 检查边界碰撞
if (newX < 0) {
newX = 0;
} else if (newX + player.width > canvas.width) {
newX = canvas.width - player.width;
}
if (newY < 0) {
newY = 0;
} else if (newY + player.height > canvas.height) {
newY = canvas.height - player.height;
}
// 检查与墙壁碰撞
const tempPlayer = { ...player, x: newX, y: newY };
let wallCollision = false;
for (const wall of walls) {
if (checkCollision(tempPlayer, wall)) {
wallCollision = true;
break;
}
}
// 检查与敌人碰撞
let enemyCollision = false;
for (const enemy of enemies) {
if (checkCollision(tempPlayer, enemy)) {
enemyCollision = true;
break;
}
}
// 检查与基地碰撞
let baseCollision = false;
if (checkCollision(tempPlayer, base)) {
baseCollision = true;
}
// 如果没有碰撞,更新位置
if (!wallCollision && !enemyCollision && !baseCollision) {
player.x = newX;
player.y = newY;
}
}
// 设置移动处理间隔
setInterval(handlePlayerMovement, 16); // 约60fps
// 事件监听器
startBtn.addEventListener('click', () => {
if (!gameRunning) {
initGame();
gameRunning = true;
gamePaused = false;
gameOverEl.style.display = 'none';
requestAnimationFrame(gameLoop);
}
});
pauseBtn.addEventListener('click', () => {
if (gameRunning) {
gamePaused = !gamePaused;
pauseBtn.textContent = gamePaused ? '继续' : '暂停';
}
});
restartBtn.addEventListener('click', () => {
gameOverEl.style.display = 'none';
initGame();
gameRunning = true;
gamePaused = false;
requestAnimationFrame(gameLoop);
});
// 加载图像并初始化游戏
loadImages().then(() => {
initGame();
});
</script>
</body>
</html>