一个基于HTML5 Canvas的飞行射击游戏,玩家可以控制战机躲避陨石并射击敌人。
设计思路
- 使用Canvas实现流畅的游戏动画
- 添加太空背景和粒子效果增强沉浸感
- 实现玩家战机控制、射击系统和敌人AI
- 包含分数系统、生命值和游戏状态管理
下面是完整的实现代码:
<!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;
}
body {
background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow: hidden;
color: #fff;
}
.game-container {
position: relative;
width: 800px;
height: 600px;
box-shadow: 0 0 30px rgba(0, 150, 255, 0.5);
border-radius: 10px;
overflow: hidden;
}
#gameCanvas {
background: radial-gradient(ellipse at center, #1a2980 0%, #26d0ce 100%);
display: block;
}
.ui-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
padding: 20px;
display: flex;
justify-content: space-between;
}
.stats {
background: rgba(0, 0, 0, 0.6);
padding: 10px 20px;
border-radius: 10px;
border: 1px solid #00aaff;
}
.stats div {
margin: 5px 0;
}
.screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 10, 30, 0.85);
z-index: 10;
}
.title {
font-size: 48px;
font-weight: bold;
margin-bottom: 30px;
text-shadow: 0 0 10px #00aaff, 0 0 20px #00aaff;
color: #fff;
letter-spacing: 3px;
}
.btn {
background: linear-gradient(to right, #00aaff, #0088ff);
color: white;
border: none;
padding: 15px 40px;
font-size: 18px;
border-radius: 50px;
cursor: pointer;
margin: 15px 0;
transition: all 0.3s;
box-shadow: 0 5px 15px rgba(0, 170, 255, 0.4);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0, 170, 255, 0.6);
}
.instructions {
background: rgba(0, 0, 0, 0.6);
padding: 20px;
border-radius: 10px;
max-width: 80%;
margin-top: 30px;
border: 1px solid #00aaff;
}
.instructions h3 {
margin-bottom: 10px;
color: #00aaff;
}
.instructions p {
margin: 5px 0;
}
.hidden {
display: none;
}
.game-over {
font-size: 72px;
color: #ff0055;
text-shadow: 0 0 10px #ff0055, 0 0 20px #ff0055;
margin-bottom: 30px;
}
</style>
</head>
<body>
<div class="game-container">
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div class="ui-overlay">
<div class="stats">
<div>分数: <span id="score">0</span></div>
<div>生命值: <span id="lives">3</span></div>
<div>等级: <span id="level">1</span></div>
</div>
</div>
<div id="startScreen" class="screen">
<h1 class="title">星际战机</h1>
<button id="startBtn" class="btn">开始游戏</button>
<div class="instructions">
<h3>游戏说明</h3>
<p>← → 方向键控制战机左右移动</p>
<p>空格键或鼠标左键发射子弹</p>
<p>躲避陨石和敌机,射击敌机获得分数</p>
<p>每1000分提升一个等级,敌机速度增加</p>
</div>
</div>
<div id="gameOverScreen" class="screen hidden">
<h1 class="game-over">游戏结束</h1>
<h2>最终得分: <span id="finalScore">0</span></h2>
<button id="restartBtn" class="btn">重新开始</button>
</div>
</div>
<script>
// 获取Canvas和上下文
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// 游戏状态
const gameState = {
score: 0,
lives: 3,
level: 1,
gameOver: false,
isRunning: false,
enemies: [],
bullets: [],
particles: [],
stars: [],
lastTime: 0,
enemySpawnTimer: 0,
enemySpawnInterval: 1000, // 敌机生成间隔(毫秒)
player: {
x: canvas.width / 2 - 25,
y: canvas.height - 80,
width: 50,
height: 60,
speed: 6,
isMovingLeft: false,
isMovingRight: false,
shootCooldown: 0
}
};
// 初始化星星背景
function initStars() {
gameState.stars = [];
for (let i = 0; i < 150; i++) {
gameState.stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
size: Math.random() * 2 + 1,
speed: Math.random() * 2 + 0.5
});
}
}
// 初始化游戏
function initGame() {
gameState.score = 0;
gameState.lives = 3;
gameState.level = 1;
gameState.gameOver = false;
gameState.enemies = [];
gameState.bullets = [];
gameState.particles = [];
gameState.enemySpawnTimer = 0;
gameState.enemySpawnInterval = 1000;
gameState.player = {
x: canvas.width / 2 - 25,
y: canvas.height - 80,
width: 50,
height: 60,
speed: 6,
isMovingLeft: false,
isMovingRight: false,
shootCooldown: 0
};
initStars();
updateUI();
}
// 更新UI显示
function updateUI() {
document.getElementById('score').textContent = gameState.score;
document.getElementById('lives').textContent = gameState.lives;
document.getElementById('level').textContent = gameState.level;
}
// 绘制玩家战机
function drawPlayer() {
ctx.save();
// 绘制战机主体
ctx.fillStyle = '#00aaff';
ctx.beginPath();
ctx.moveTo(gameState.player.x + gameState.player.width / 2, gameState.player.y);
ctx.lineTo(gameState.player.x + gameState.player.width, gameState.player.y + gameState.player.height / 2);
ctx.lineTo(gameState.player.x + gameState.player.width * 0.7, gameState.player.y + gameState.player.height);
ctx.lineTo(gameState.player.x + gameState.player.width * 0.3, gameState.player.y + gameState.player.height);
ctx.lineTo(gameState.player.x, gameState.player.y + gameState.player.height / 2);
ctx.closePath();
ctx.fill();
// 绘制驾驶舱
ctx.fillStyle = '#aaffff';
ctx.beginPath();
ctx.arc(
gameState.player.x + gameState.player.width / 2,
gameState.player.y + gameState.player.height / 3,
8, 0, Math.PI * 2
);
ctx.fill();
// 绘制引擎火焰
const flameHeight = 15 + Math.sin(Date.now() / 100) * 5;
ctx.fillStyle = '#ff5500';
ctx.beginPath();
ctx.moveTo(gameState.player.x + gameState.player.width * 0.3, gameState.player.y + gameState.player.height);
ctx.lineTo(gameState.player.x + gameState.player.width * 0.5, gameState.player.y + gameState.player.height + flameHeight);
ctx.lineTo(gameState.player.x + gameState.player.width * 0.7, gameState.player.y + gameState.player.height);
ctx.closePath();
ctx.fill();
ctx.restore();
}
// 绘制敌机
function drawEnemy(enemy) {
ctx.save();
// 敌机颜色根据类型变化
if (enemy.type === 1) {
ctx.fillStyle = '#ff5555';
} else {
ctx.fillStyle = '#ffaa00';
}
ctx.beginPath();
ctx.moveTo(enemy.x, enemy.y);
ctx.lineTo(enemy.x + enemy.width, enemy.y);
ctx.lineTo(enemy.x + enemy.width * 0.8, enemy.y + enemy.height * 0.7);
ctx.lineTo(enemy.x + enemy.width, enemy.y + enemy.height);
ctx.lineTo(enemy.x, enemy.y + enemy.height);
ctx.lineTo(enemy.x + enemy.width * 0.2, enemy.y + enemy.height * 0.7);
ctx.closePath();
ctx.fill();
// 敌机引擎
ctx.fillStyle = '#ff0000';
ctx.fillRect(enemy.x + enemy.width * 0.3, enemy.y + enemy.height, enemy.width * 0.4, 5);
ctx.restore();
}
// 绘制子弹
function drawBullet(bullet) {
ctx.save();
ctx.fillStyle = '#ffff00';
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, bullet.radius, 0, Math.PI * 2);
ctx.fill();
// 添加发光效果
ctx.shadowBlur = 10;
ctx.shadowColor = '#ffff00';
ctx.restore();
}
// 绘制粒子
function drawParticle(particle) {
ctx.save();
ctx.globalAlpha = particle.alpha;
ctx.fillStyle = particle.color;
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
// 绘制星星背景
function drawStars() {
ctx.fillStyle = '#ffffff';
gameState.stars.forEach(star => {
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fill();
});
}
// 更新星星位置
function updateStars() {
gameState.stars.forEach(star => {
star.y += star.speed;
if (star.y > canvas.height) {
star.y = 0;
star.x = Math.random() * canvas.width;
}
});
}
// 生成敌机
function spawnEnemy() {
const type = Math.random() > 0.7 ? 2 : 1; // 30%概率生成特殊敌机
const width = type === 1 ? 40 : 60;
const height = type === 1 ? 30 : 45;
const speed = type === 1 ? 2 + gameState.level * 0.2 : 1.5 + gameState.level * 0.15;
const health = type === 1 ? 1 : 2;
gameState.enemies.push({
x: Math.random() * (canvas.width - width),
y: -height,
width: width,
height: height,
speed: speed,
type: type,
health: health
});
}
// 玩家射击
function playerShoot() {
if (gameState.player.shootCooldown <= 0) {
gameState.bullets.push({
x: gameState.player.x + gameState.player.width / 2,
y: gameState.player.y,
radius: 4,
speed: 10
});
gameState.player.shootCooldown = 15; // 射击冷却时间
// 添加射击粒子效果
for (let i = 0; i < 5; i++) {
gameState.particles.push({
x: gameState.player.x + gameState.player.width / 2,
y: gameState.player.y,
size: Math.random() * 3 + 1,
speedX: (Math.random() - 0.5) * 3,
speedY: Math.random() * -2 - 1,
color: '#ffff00',
alpha: 1,
life: 30
});
}
}
}
// 创建爆炸粒子
function createExplosion(x, y, color, count) {
for (let i = 0; i < count; i++) {
gameState.particles.push({
x: x,
y: y,
size: Math.random() * 4 + 2,
speedX: (Math.random() - 0.5) * 6,
speedY: (Math.random() - 0.5) * 6,
color: color,
alpha: 1,
life: Math.random() * 30 + 20
});
}
}
// 检测碰撞
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;
}
// 更新游戏状态
function updateGame(timestamp) {
if (!gameState.isRunning) return;
const deltaTime = timestamp - gameState.lastTime;
gameState.lastTime = timestamp;
// 更新玩家射击冷却
if (gameState.player.shootCooldown > 0) {
gameState.player.shootCooldown--;
}
// 移动玩家
if (gameState.player.isMovingLeft) {
gameState.player.x = Math.max(0, gameState.player.x - gameState.player.speed);
}
if (gameState.player.isMovingRight) {
gameState.player.x = Math.min(canvas.width - gameState.player.width, gameState.player.x + gameState.player.speed);
}
// 生成敌机
gameState.enemySpawnTimer += deltaTime;
if (gameState.enemySpawnTimer > gameState.enemySpawnInterval) {
spawnEnemy();
gameState.enemySpawnTimer = 0;
// 随着等级提高,敌机生成速度加快
gameState.enemySpawnInterval = Math.max(200, 1000 - gameState.level * 50);
}
// 更新敌机位置
gameState.enemies.forEach((enemy, index) => {
enemy.y += enemy.speed;
// 检测敌机与玩家碰撞
if (checkCollision(gameState.player, enemy)) {
gameState.lives--;
createExplosion(
enemy.x + enemy.width / 2,
enemy.y + enemy.height / 2,
'#ff5555',
30
);
gameState.enemies.splice(index, 1);
updateUI();
if (gameState.lives <= 0) {
gameOver();
return;
}
}
// 移除超出屏幕的敌机
if (enemy.y > canvas.height) {
gameState.enemies.splice(index, 1);
}
});
// 更新子弹位置
gameState.bullets.forEach((bullet, index) => {
bullet.y -= bullet.speed;
// 检测子弹与敌机碰撞
let hit = false;
gameState.enemies.forEach((enemy, enemyIndex) => {
if (
bullet.x > enemy.x &&
bullet.x < enemy.x + enemy.width &&
bullet.y > enemy.y &&
bullet.y < enemy.y + enemy.height
) {
enemy.health--;
if (enemy.health <= 0) {
// 敌机被摧毁
gameState.score += enemy.type === 1 ? 100 : 200;
createExplosion(
enemy.x + enemy.width / 2,
enemy.y + enemy.height / 2,
enemy.type === 1 ? '#ff5555' : '#ffaa00',
40
);
gameState.enemies.splice(enemyIndex, 1);
} else {
// 敌机受伤但没有被摧毁
createExplosion(
bullet.x,
bullet.y,
'#ffff00',
10
);
}
hit = true;
gameState.bullets.splice(index, 1);
// 更新等级
const newLevel = Math.floor(gameState.score / 1000) + 1;
if (newLevel > gameState.level) {
gameState.level = newLevel;
}
updateUI();
}
});
// 移除超出屏幕的子弹
if (!hit && bullet.y < 0) {
gameState.bullets.splice(index, 1);
}
});
// 更新粒子
gameState.particles.forEach((particle, index) => {
particle.x += particle.speedX;
particle.y += particle.speedY;
particle.life--;
particle.alpha = particle.life / 30;
if (particle.life <= 0) {
gameState.particles.splice(index, 1);
}
});
// 更新星星
updateStars();
// 继续游戏循环
if (!gameState.gameOver) {
requestAnimationFrame(updateGame);
}
}
// 绘制游戏
function drawGame() {
if (!gameState.isRunning) return;
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制背景
drawStars();
// 绘制粒子
gameState.particles.forEach(particle => {
drawParticle(particle);
});
// 绘制子弹
gameState.bullets.forEach(bullet => {
drawBullet(bullet);
});
// 绘制敌机
gameState.enemies.forEach(enemy => {
drawEnemy(enemy);
});
// 绘制玩家
drawPlayer();
// 继续绘制循环
requestAnimationFrame(drawGame);
}
// 游戏结束
function gameOver() {
gameState.gameOver = true;
gameState.isRunning = false;
document.getElementById('finalScore').textContent = gameState.score;
document.getElementById('gameOverScreen').classList.remove('hidden');
}
// 开始游戏
function startGame() {
initGame();
gameState.isRunning = true;
gameState.gameOver = false;
gameState.lastTime = performance.now();
document.getElementById('startScreen').classList.add('hidden');
document.getElementById('gameOverScreen').classList.add('hidden');
updateGame(gameState.lastTime);
drawGame();
}
// 事件监听
document.getElementById('startBtn').addEventListener('click', startGame);
document.getElementById('restartBtn').addEventListener('click', startGame);
// 键盘控制
window.addEventListener('keydown', (e) => {
if (!gameState.isRunning) return;
switch(e.key) {
case 'ArrowLeft':
gameState.player.isMovingLeft = true;
break;
case 'ArrowRight':
gameState.player.isMovingRight = true;
break;
case ' ':
playerShoot();
e.preventDefault();
break;
}
});
window.addEventListener('keyup', (e) => {
if (!gameState.isRunning) return;
switch(e.key) {
case 'ArrowLeft':
gameState.player.isMovingLeft = false;
break;
case 'ArrowRight':
gameState.player.isMovingRight = false;
break;
}
});
// 鼠标控制射击
canvas.addEventListener('click', () => {
if (gameState.isRunning) {
playerShoot();
}
});
// 初始化星星背景
initStars();
// 初始绘制
drawGame();
</script>
</body>
</html>
游戏特点
-
视觉效果:
- 太空背景与动态星星
- 粒子爆炸效果
- 战机引擎火焰动画
- 发光子弹效果
-
游戏机制:
- 玩家控制战机左右移动
- 空格键或鼠标点击发射子弹
- 两种类型的敌机(普通和特殊)
- 分数系统和等级提升
- 生命值系统
-
游戏状态:
- 开始界面
- 游戏进行界面
- 游戏结束界面
-
控制方式:
- 键盘左右方向键控制移动
- 空格键或鼠标点击射击
如何玩
- 点击"开始游戏"按钮进入游戏
- 使用左右方向键移动战机
- 按空格键或鼠标点击发射子弹
- 射击敌机获得分数,每1000分提升一个等级
- 躲避敌机和陨石,被撞击会减少生命值
- 生命值归零时游戏结束
这个游戏包含了完整的游戏循环、碰撞检测、粒子效果和UI界面,可以直接复制代码到HTML文件中运行!