《腾讯云代码助手CodeBuddy初体验》通过CodeBuddy进行了代码开发的过程体验,为做到学以致用,碰巧孩子暑假了,给孩子做了个飞机大战的游戏,只能算个不成熟的初稿,还能继续优化。
游戏的使用说明,
游戏使用说明: 1. 开始游戏:按任意键开始 2. 移动控制:方向键↑↓←→移动飞机 3. 射击:空格键发射子弹 4. 游戏规则: 击落敌机获得分数 被敌机击中会损失生命值 被击中后有短暂无敌时间(飞机会闪烁) 生命值归零游戏结束 5. 重新开始:游戏结束后按R键重新开始 游戏说明
相关的code如下,
<!DOCTYPE html>
<html>
<head>
<title>星空飞机大战</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
canvas {
display: block;
background: #000;
box-shadow: 0 0 20px #0066ff;
}
#score, #weapon, #lives {
position: absolute;
left: 20px;
color: white;
font-family: Arial, sans-serif;
font-size: 24px;
text-shadow: 0 0 5px #00a2ff;
}
#score {
top: 20px;
}
#weapon {
top: 60px;
font-size: 18px;
}
#lives {
top: 90px;
}
</style>
</head>
<body>
<div id="score">分数: 0</div>
<div id="weapon">当前武器: 普通子弹 (1-普通 2-散弹 3-激光)</div>
<div id="lives">生命: ❤️❤️❤️</div>
<canvas id="gameCanvas"></canvas>
<script>
// 游戏初始化
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
// 设置画布大小为窗口大小
canvas.width = 800;
canvas.height = 600;
// 武器类型
const WEAPON_TYPES = {
NORMAL: {
name: "普通子弹",
color: "#00a2ff",
damage: 1,
delay: 100,
width: 4,
height: 20,
speed: 10
},
SPREAD: {
name: "散弹",
color: "#ff9900",
damage: 1,
delay: 300,
width: 3,
height: 15,
speed: 8,
count: 5
},
LASER: {
name: "激光",
color: "#ff00aa",
damage: 3,
delay: 500,
width: 10,
height: 30,
speed: 15
}
};
// 敌机类型
const ENEMY_TYPES = {
NORMAL: {
width: 40,
height: 40,
speed: 1 + Math.random() * 2,
health: 1,
score: 100,
color: "#ff3300"
},
LARGE: {
width: 60,
height: 60,
speed: 0.5 + Math.random() * 1.5,
health: 2,
score: 200,
color: "#ff6600"
},
BOSS: {
width: 120,
height: 120,
speed: 0.3,
health: 20,
score: 1000,
color: "#ff0000",
attackPattern: "circle",
attackDelay: 2000
}
};
// 游戏状态
const game = {
player: {
x: canvas.width / 2,
y: canvas.height - 100,
width: 50,
height: 40,
speed: 10,
isShooting: false,
lastShot: 0,
currentWeapon: WEAPON_TYPES.NORMAL,
particles: [],
lives: 3, // 玩家生命值
invincible: false, // 无敌状态
invincibleTimer: 0, // 无敌时间
visible: true
},
bullets: [],
enemies: [],
stars: [],
explosions: [],
score: 0,
lastEnemyTime: 0,
enemySpawnRate: 2000, // 敌机生成间隔从1秒增加到2秒
gameOver: false,
started: false
};
// 创建星空背景
function createStars() {
for (let i = 0; i < 200; i++) {
game.stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
size: Math.random() * 3,
speed: 0.5 + Math.random() * 2,
alpha: Math.random()
});
}
}
// 绘制星空
function drawStars() {
ctx.save();
game.stars.forEach(star => {
star.y += star.speed;
if (star.y > canvas.height) {
star.y = 0;
star.x = Math.random() * canvas.width;
}
const alpha = 0.5 + Math.sin(Date.now() / 1000 + star.x) * 0.5;
ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fill();
});
ctx.restore();
}
// 玩家飞机
function drawPlayer() {
// 无敌状态时不绘制
if (game.player.invincible && !game.player.visible) {
return;
}
ctx.save();
ctx.translate(game.player.x, game.player.y);
// 机身
ctx.fillStyle = '#0066ff';
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(0, 40);
ctx.lineTo(50, 40);
ctx.closePath();
ctx.fill();
ctx.strokeStyle = '#00a2ff';
ctx.lineWidth = 2;
ctx.stroke();
// 引擎火焰
const flameSize = 5 + Math.sin(Date.now() / 100) * 3;
ctx.fillStyle = '#ff6600';
ctx.fillRect(20, 40, 10, flameSize);
// 驾驶舱
ctx.fillStyle = '#00ccff';
ctx.beginPath();
ctx.arc(25, 15, 8, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
// 更新粒子
updateParticles();
}
// 粒子系统
function updateParticles() {
// 添加新粒子
if (Math.random() < 0.3) {
game.player.particles.push({
x: game.player.x + Math.random() * 50 - 25,
y: game.player.y + 40,
size: 3 + Math.random() * 4,
speedX: Math.random() * 2 - 1,
speedY: 1 + Math.random() * 2,
alpha: 1,
color: `hsl(${Math.random() * 30 + 20}, 100%, 50%)`
});
}
// 更新粒子
ctx.save();
game.player.particles.forEach((p, i) => {
p.x += p.speedX;
p.y += p.speedY;
p.alpha -= 0.02;
p.size *= 0.98;
if (p.alpha <= 0) {
game.player.particles.splice(i, 1);
} else {
ctx.globalAlpha = p.alpha;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
}
});
ctx.restore();
}
// 子弹
function drawBullets() {
ctx.save();
game.bullets.forEach((bullet, i) => {
// 更新子弹位置
bullet.y -= bullet.type === 'LASER' ? 15 : 10;
// 移除屏幕外的子弹
if (bullet.y < 0) {
game.bullets.splice(i, 1);
} else {
// 根据子弹类型绘制不同效果
if (bullet.type === 'NORMAL') {
const gradient = ctx.createLinearGradient(bullet.x, bullet.y, bullet.x, bullet.y + 20);
gradient.addColorStop(0, '#ffffff');
gradient.addColorStop(1, '#0066ff');
ctx.fillStyle = gradient;
ctx.fillRect(bullet.x - 2, bullet.y, 4, 20);
// 子弹尾迹
ctx.fillStyle = 'rgba(0, 200, 255, 0.3)';
ctx.fillRect(bullet.x - 3, bullet.y + 10, 6, 30);
}
else if (bullet.type === 'SPREAD') {
ctx.fillStyle = '#ff9900';
ctx.beginPath();
ctx.arc(bullet.x, bullet.y, 3, 0, Math.PI * 2);
ctx.fill();
// 散弹尾迹
ctx.fillStyle = 'rgba(255, 150, 0, 0.3)';
ctx.beginPath();
ctx.arc(bullet.x, bullet.y + 10, 5, 0, Math.PI * 2);
ctx.fill();
}
else if (bullet.type === 'LASER') {
// 激光光束
const gradient = ctx.createLinearGradient(bullet.x, bullet.y, bullet.x, bullet.y + 30);
gradient.addColorStop(0, '#ff00aa');
gradient.addColorStop(1, '#ffffff');
ctx.fillStyle = gradient;
ctx.fillRect(bullet.x - 5, bullet.y, 10, 30);
// 激光光晕
ctx.fillStyle = 'rgba(255, 0, 170, 0.2)';
ctx.fillRect(bullet.x - 10, bullet.y, 20, 40);
}
}
});
ctx.restore();
}
// 敌机
function drawEnemies() {
const now = Date.now();
if (now - game.lastEnemyTime > game.enemySpawnRate) {
game.lastEnemyTime = now;
// 每5000分出现Boss
if (game.score > 0 && game.score % 5000 === 0) {
game.enemies.push({
...ENEMY_TYPES.BOSS,
x: canvas.width / 2 - ENEMY_TYPES.BOSS.width / 2,
y: -ENEMY_TYPES.BOSS.height,
lastAttack: now
});
} else {
// 普通敌机
const type = Math.random() > 0.3 ? ENEMY_TYPES.NORMAL : ENEMY_TYPES.LARGE;
game.enemies.push({
...type,
x: Math.random() * (canvas.width - type.width),
y: -type.height
});
}
}
ctx.save();
game.enemies.forEach((enemy, i) => {
enemy.y += enemy.speed;
// 移除屏幕外的敌机
if (enemy.y > canvas.height) {
game.enemies.splice(i, 1);
} else {
// 绘制敌机
ctx.fillStyle = enemy.color || '#ff3300';
if (enemy.width === ENEMY_TYPES.BOSS.width) {
// Boss特殊绘制
ctx.beginPath();
ctx.arc(enemy.x + enemy.width/2, enemy.y + enemy.height/2,
enemy.width/2, 0, Math.PI * 2);
ctx.fill();
// Boss光环效果
ctx.strokeStyle = 'rgba(255, 255, 0, 0.7)';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(enemy.x + enemy.width/2, enemy.y + enemy.height/2,
enemy.width/2 + 5 + Math.sin(now/200)*5, 0, Math.PI * 2);
ctx.stroke();
} else {
// 普通敌机绘制
ctx.beginPath();
ctx.moveTo(enemy.x + enemy.width/2, enemy.y);
ctx.lineTo(enemy.x, enemy.y + enemy.height);
ctx.lineTo(enemy.x + enemy.width, enemy.y + enemy.height);
ctx.closePath();
ctx.fill();
}
// 敌机引擎效果
ctx.fillStyle = '#ff9900';
ctx.fillRect(enemy.x + enemy.width/2 - 5, enemy.y + enemy.height,
10, 5 + Math.sin(now / 100) * 3);
}
});
ctx.restore();
}
// 爆炸效果
function drawExplosions() {
ctx.save();
game.explosions.forEach((exp, i) => {
exp.particles.forEach(p => {
p.x += p.speedX;
p.y += p.speedY;
p.size *= 0.95;
p.alpha -= 0.02;
if (p.alpha > 0) {
ctx.globalAlpha = p.alpha;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
}
});
// 移除消失的爆炸
if (exp.particles.every(p => p.alpha <= 0)) {
game.explosions.splice(i, 1);
}
});
ctx.restore();
}
// 创建爆炸
function createExplosion(x, y) {
const particles = [];
for (let i = 0; i < 30; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 1 + Math.random() * 3;
particles.push({
x: x,
y: y,
speedX: Math.cos(angle) * speed,
speedY: Math.sin(angle) * speed,
size: 3 + Math.random() * 5,
alpha: 1,
color: `hsl(${Math.random() * 30 + 20}, 100%, 50%)`
});
}
game.explosions.push({ particles });
}
// 碰撞检测
function checkCollisions() {
const now = Date.now();
// 子弹与敌机
game.bullets.forEach((bullet, bIndex) => {
game.enemies.forEach((enemy, eIndex) => {
if (bullet.x > enemy.x &&
bullet.x < enemy.x + enemy.width &&
bullet.y > enemy.y &&
bullet.y < enemy.y + enemy.height) {
enemy.health--;
game.bullets.splice(bIndex, 1);
if (enemy.health <= 0) {
createExplosion(enemy.x + enemy.width/2, enemy.y + enemy.height/2);
game.enemies.splice(eIndex, 1);
game.score += enemy.score || 100;
scoreElement.textContent = `分数: ${game.score}`;
}
return;
}
});
});
// 玩家与敌机碰撞
if (!game.player.invincible) {
game.enemies.forEach((enemy, eIndex) => {
if (game.player.x < enemy.x + enemy.width &&
game.player.x + game.player.width > enemy.x &&
game.player.y < enemy.y + enemy.height &&
game.player.y + game.player.height > enemy.y) {
createExplosion(enemy.x + enemy.width/2, enemy.y + enemy.height/2);
game.enemies.splice(eIndex, 1);
hitPlayer();
}
});
}
}
// 玩家被击中
function hitPlayer() {
const now = Date.now();
// 只在非无敌状态下减少生命值
if (!game.player.invincible) {
game.player.lives--;
updateLivesDisplay();
if (game.player.lives <= 0) {
createExplosion(game.player.x + game.player.width/2, game.player.y + game.player.height/2);
game.gameOver = true;
game.started = false;
return;
}
// 设置无敌状态
game.player.invincible = true;
game.player.invincibleTimer = now + 2000; // 2秒无敌时间
// 闪烁效果
const blinkInterval = setInterval(() => {
game.player.visible = !game.player.visible;
if (Date.now() > game.player.invincibleTimer) {
clearInterval(blinkInterval);
game.player.invincible = false;
game.player.visible = true;
}
}, 100);
}
}
// 更新生命值显示
function updateLivesDisplay() {
const livesElement = document.getElementById('lives');
livesElement.textContent = '生命: ' + '❤️'.repeat(game.player.lives);
}
// 游戏结束画面
function drawGameOver() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ff3300';
ctx.font = '48px Arial';
ctx.textAlign = 'center';
ctx.fillText('游戏结束', canvas.width/2, canvas.height/2 - 40);
ctx.fillStyle = '#ffffff';
ctx.font = '36px Arial';
ctx.fillText(`最终分数: ${game.score}`, canvas.width/2, canvas.height/2 + 20);
ctx.fillStyle = '#00a2ff';
ctx.font = '24px Arial';
ctx.fillText('按R键重新开始', canvas.width/2, canvas.height/2 + 80);
}
// 重置游戏
function resetGame() {
game.player.x = canvas.width / 2;
game.player.y = canvas.height - 100;
game.player.lives = 3;
game.player.invincible = false;
game.player.invincibleTimer = 0;
game.bullets = [];
game.enemies = [];
game.explosions = [];
game.score = 0;
game.lastEnemyTime = 0;
game.gameOver = false;
game.started = true;
scoreElement.textContent = `分数: ${game.score}`;
updateLivesDisplay();
console.log('Game reset, starting loop...');
if (!animationId) {
animationId = requestAnimationFrame(gameLoop);
}
}
// 键盘控制
const keys = {};
window.addEventListener('keydown', e => {
console.log('Key pressed:', e.key); // 调试输出
// 开始游戏逻辑
if (!game.started && !game.gameOver) {
console.log('Starting game...');
game.started = true;
resetGame();
return;
}
keys[e.key] = true;
// 武器切换
if (e.key === '1') game.player.currentWeapon = WEAPON_TYPES.NORMAL;
if (e.key === '2') game.player.currentWeapon = WEAPON_TYPES.SPREAD;
if (e.key === '3') game.player.currentWeapon = WEAPON_TYPES.LASER;
// 射击
if (e.key === ' ' && !game.player.isShooting && !game.gameOver) {
const now = Date.now();
if (now - game.player.lastShot > game.player.currentWeapon.delay) {
game.player.lastShot = now;
const weapon = game.player.currentWeapon;
if (weapon === WEAPON_TYPES.NORMAL) {
game.bullets.push({
x: game.player.x + game.player.width/2 - weapon.width/2,
y: game.player.y,
type: 'NORMAL',
damage: weapon.damage
});
}
else if (weapon === WEAPON_TYPES.SPREAD) {
// 散弹发射5颗子弹
for (let i = 0; i < weapon.count; i++) {
game.bullets.push({
x: game.player.x + game.player.width/2 - weapon.width/2 + (i-2)*10,
y: game.player.y,
type: 'SPREAD',
damage: weapon.damage
});
}
}
else if (weapon === WEAPON_TYPES.LASER) {
game.bullets.push({
x: game.player.x + game.player.width/2 - weapon.width/2,
y: game.player.y,
type: 'LASER',
damage: weapon.damage
});
}
}
}
// 重新开始
if (e.key === 'r' && game.gameOver) {
resetGame();
}
});
window.addEventListener('keyup', e => {
keys[e.key] = false;
});
// 创建初始星空
createStars();
// 游戏开始画面
function drawStartScreen() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#00a2ff';
ctx.font = '48px Arial';
ctx.textAlign = 'center';
ctx.fillText('星空飞机大战', canvas.width/2, canvas.height/2 - 60);
ctx.fillStyle = '#ffffff';
ctx.font = '24px Arial';
ctx.fillText('使用方向键移动,空格键射击', canvas.width/2, canvas.height/2);
ctx.fillStyle = '#ff9900';
ctx.font = '24px Arial';
ctx.fillText('1-普通子弹 2-散弹 3-激光', canvas.width/2, canvas.height/2 + 40);
ctx.fillStyle = '#00ffaa';
ctx.font = '24px Arial';
ctx.fillText('按任意键开始游戏', canvas.width/2, canvas.height/2 + 100);
}
// 游戏主循环
let animationId;
function gameLoop() {
if (!game.started) {
drawStartScreen();
animationId = requestAnimationFrame(gameLoop);
return;
}
if (!game.gameOver) {
// 清屏
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制星空
drawStars();
// 更新游戏状态
if (keys['ArrowLeft'] && game.player.x > 0) {
game.player.x -= game.player.speed;
}
if (keys['ArrowRight'] && game.player.x < canvas.width - game.player.width) {
game.player.x += game.player.speed;
}
if (keys['ArrowUp'] && game.player.y > 0) {
game.player.y -= game.player.speed;
}
if (keys['ArrowDown'] && game.player.y < canvas.height - game.player.height) {
game.player.y += game.player.speed;
}
// 绘制游戏元素
drawPlayer();
drawBullets();
drawEnemies();
drawExplosions();
// 碰撞检测
checkCollisions();
// 更新武器状态显示
document.getElementById('weapon').textContent =
`当前武器: ${game.player.currentWeapon.name} (1-普通 2-散弹 3-激光)`;
} else {
drawGameOver();
}
requestAnimationFrame(gameLoop);
}
// 启动游戏
gameLoop();
</script>
</body>
</html>