代码
<!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;
overflow: hidden;
font-family: Arial, sans-serif;
}
#gameCanvas {
display: block;
background: linear-gradient(to bottom, #87CEEB, #E0F7FA);
}
#controlPanel {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(255, 255, 255, 0.7);
padding: 10px;
border-radius: 5px;
}
#score {
position: absolute;
top: 10px;
right: 10px;
background-color: rgba(255, 255, 255, 0.7);
padding: 10px;
border-radius: 5px;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="controlPanel">
<button id="startBtn">开始飞行</button>
<button id="restartBtn">重新开始</button>
<div>
<label for="angle">飞行角度: </label>
<input type="range" id="angle" min="-45" max="45" value="0">
<span id="angleValue">0°</span>
</div>
</div>
<div id="score">
分数: <span id="scoreValue">0</span><br>
高度: <span id="altitude">1000</span>m
</div>
<script>
// 游戏变量
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const angleSlider = document.getElementById('angle');
const angleValue = document.getElementById('angleValue');
const scoreElement = document.getElementById('scoreValue');
const altitudeElement = document.getElementById('altitude');
let gameRunning = false;
let score = 0;
let terrain = [];
let player = {
x: 0,
y: 0,
angle: 0,
speed: 3,
size: 10
};
let targetPoints = [];
let cameraOffset = { x: 0, y: 0 };
// 初始化游戏
function initGame() {
// 设置画布尺寸
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 重置玩家
player.x = canvas.width / 4;
player.y = canvas.height / 4;
player.angle = 0;
// 生成地形
generateTerrain();
// 生成目标点
generateTargetPoints(15);
// 重置分数
score = 0;
scoreElement.textContent = score;
altitudeElement.textContent = '1000';
// 重置相机
cameraOffset = { x: 0, y: 0 };
// 更新角度显示
angleSlider.value = 0;
angleValue.textContent = '0°';
}
// 生成地形(等高线地图)
function generateTerrain() {
terrain = [];
// 使用简化的柏林噪声算法生成山体
const segments = 100;
const amplitude = canvas.height / 2;
const offset = canvas.height / 2 + canvas.height / 4;
for (let i = 0; i <= segments; i++) {
const x = i * (canvas.width * 3) / segments;
// 使用多个正弦波叠加模拟地形
let y = Math.sin(i * 0.05) * amplitude * 0.5;
y += Math.sin(i * 0.02) * amplitude * 0.3;
y += Math.sin(i * 0.01) * amplitude * 0.2;
// 增加一些随机性
y += (Math.random() - 0.5) * amplitude * 0.1;
terrain.push({ x, y: y + offset });
}
}
// 生成目标点
function generateTargetPoints(count) {
targetPoints = [];
for (let i = 0; i < count; i++) {
const x = Math.random() * canvas.width * 2.5 + canvas.width * 0.2;
const y = Math.random() * (canvas.height * 0.6) + canvas.height * 0.2;
// 确保目标点不在地形内部
if (!isPointInTerrain(x, y)) {
targetPoints.push({
x,
y,
collected: false,
radius: 15
});
}
}
}
// 判断点是否在地形内部
function isPointInTerrain(x, y) {
// 找到地形上最接近的点
let terrainY = canvas.height;
for (let i = 1; i < terrain.length; i++) {
if (terrain[i-1].x <= x && terrain[i].x >= x) {
// 线性插值找到该x位置的地形高度
const ratio = (x - terrain[i-1].x) / (terrain[i].x - terrain[i-1].x);
terrainY = terrain[i-1].y + ratio * (terrain[i].y - terrain[i-1].y);
break;
}
}
return y > terrainY;
}
// 游戏主循环
function gameLoop() {
if (!gameRunning) return;
// 清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新玩家位置
updatePlayer();
// 检查碰撞
checkCollisions();
// 渲染场景
drawScene();
// 继续循环
requestAnimationFrame(gameLoop);
}
// 更新玩家位置
function updatePlayer() {
// 应用空气动力学简化模型
// 角度影响水平和垂直速度
const radians = player.angle * Math.PI / 180;
const horizontalSpeed = player.speed * Math.cos(radians) * 2;
const verticalSpeed = player.speed * Math.sin(radians) + 1; // 始终有一点下降
// 更新玩家位置
player.x += horizontalSpeed;
player.y += verticalSpeed;
// 更新相机位置(跟随玩家)
cameraOffset.x = player.x - canvas.width / 3;
// 更新高度显示(模拟从1000米开始的下降)
const altitude = Math.max(0, Math.floor(1000 - (player.y / canvas.height) * 1000));
altitudeElement.textContent = altitude;
// 如果玩家飞出了视野,游戏结束
if (player.y > canvas.height + 50) {
endGame();
}
}
// 检查碰撞
function checkCollisions() {
// 检查与目标点的碰撞
targetPoints.forEach(point => {
if (!point.collected) {
const dx = point.x - player.x;
const dy = point.y - player.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < point.radius + player.size / 2) {
// 收集目标点
point.collected = true;
score += 100;
scoreElement.textContent = score;
}
}
});
// 检查与地形的碰撞
if (isPointInTerrain(player.x, player.y)) {
endGame();
}
}
// 游戏结束
function endGame() {
gameRunning = false;
alert(`游戏结束!您的得分: ${score}`);
}
// 绘制场景
function drawScene() {
// 应用相机偏移
ctx.save();
ctx.translate(-cameraOffset.x, 0);
// 绘制天空(已在CSS中设置)
// 绘制地形
drawTerrain();
// 绘制等高线
drawContours();
// 绘制目标点
drawTargetPoints();
// 绘制玩家
drawPlayer();
ctx.restore();
}
// 绘制地形
function drawTerrain() {
ctx.fillStyle = '#4CAF50';
ctx.beginPath();
ctx.moveTo(terrain[0].x, terrain[0].y);
terrain.forEach(point => {
ctx.lineTo(point.x, point.y);
});
ctx.lineTo(terrain[terrain.length - 1].x, canvas.height);
ctx.lineTo(terrain[0].x, canvas.height);
ctx.closePath();
ctx.fill();
}
// 绘制等高线
function drawContours() {
// 绘制一些等高线来增强地形视觉效果
const contourLevels = 5;
const contourStep = canvas.height / contourLevels;
ctx.strokeStyle = 'rgba(0, 100, 0, 0.3)';
ctx.lineWidth = 1;
for (let level = 1; level <= contourLevels; level++) {
const contourHeight = canvas.height - level * contourStep;
ctx.beginPath();
for (let i = 0; i < terrain.length - 1; i++) {
if (terrain[i].y <= contourHeight && terrain[i+1].y >= contourHeight ||
terrain[i].y >= contourHeight && terrain[i+1].y <= contourHeight) {
// 计算等高线与地形线段的交点
const ratio = (contourHeight - terrain[i].y) / (terrain[i+1].y - terrain[i].y);
const x = terrain[i].x + ratio * (terrain[i+1].x - terrain[i].x);
ctx.lineTo(x, contourHeight);
}
}
ctx.stroke();
}
}
// 绘制目标点
function drawTargetPoints() {
targetPoints.forEach(point => {
if (!point.collected) {
ctx.fillStyle = 'gold';
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = 'orange';
ctx.lineWidth = 2;
ctx.stroke();
}
});
}
// 绘制玩家
function drawPlayer() {
ctx.save();
ctx.translate(player.x, player.y);
ctx.rotate(player.angle * Math.PI / 180);
// 绘制翼装飞行员
ctx.fillStyle = 'red';
// 身体
ctx.beginPath();
ctx.arc(0, 0, player.size / 2, 0, Math.PI * 2);
ctx.fill();
// 翼装
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.moveTo(0, -player.size / 2);
ctx.lineTo(-player.size * 1.5, player.size / 2);
ctx.lineTo(player.size * 1.5, player.size / 2);
ctx.closePath();
ctx.fill();
ctx.restore();
}
// 事件监听器
startBtn.addEventListener('click', () => {
if (!gameRunning) {
gameRunning = true;
gameLoop();
}
});
restartBtn.addEventListener('click', () => {
gameRunning = false;
initGame();
});
angleSlider.addEventListener('input', () => {
player.angle = parseInt(angleSlider.value);
angleValue.textContent = `${player.angle}°`;
});
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
if (!gameRunning) {
initGame();
}
});
// 初始化游戏
initGame();
</script>
</body>
</html></div>