<!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(to bottom, #87CEEB 0%, #98FB98 100%);
font-family: Arial, sans-serif;
overflow: hidden;
user-select: none;
}
#gameContainer {
position: relative;
width: 100vw;
height: 100vh;
}
#gameCanvas {
display: block;
cursor: pointer;
}
#ui {
position: absolute;
top: 20px;
left: 20px;
color: #333;
font-size: 20px;
font-weight: bold;
z-index: 10;
}
#startScreen, #gameOverScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.9);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
z-index: 20;
}
#gameOverScreen {
display: none;
}
.title {
font-size: 36px;
margin-bottom: 20px;
color: #333;
}
.btn {
padding: 12px 24px;
font-size: 18px;
background: #4CAF50;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
margin: 10px;
}
.btn:hover {
background: #45a049;
}
.stats {
font-size: 18px;
margin: 8px 0;
color: #333;
}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="gameCanvas"></canvas>
<div id="ui">
<div>分數: <span id="score">0</span></div>
<div>最佳: <span id="bestScore">0</span></div>
<div>距離: <span id="distance">0</span>m</div>
</div>
<div class="difficulty-indicator">
難度: <span id="difficulty">簡單</span>
</div>
<div style="position: absolute; bottom: 20px; left: 20px; color: white; font-size: 14px; opacity: 0.8;">
✨ 遊戲已加載 | 飛行穿越模式
</div>
<div id="startScreen">
<h1 class="title">幾何衝刺 - 飛行模式</h1>
<div class="instructions">
<p>🚀 點擊屏幕或按空格鍵向上飛行</p>
<p>✨ 不點擊時會受重力影響下落</p>
<p>🔄 可以連續點擊控制飛行高度</p>
<p>⚡ 穿過上下障礙物之間的縫隙</p>
<p>⚠️ 撞到上下邊界或障礙物就會死亡</p>
<p>🏆 挑戰你的最高分數!</p>
</div>
<button class="btn" onclick="startGame()">開始飛行挑戰</button>
</div>
<div id="gameOverScreen">
<h2 class="title">遊戲結束</h2>
<div class="stats">本次分數: <span id="finalScore">0</span></div>
<div class="stats">最佳分數: <span id="finalBestScore">0</span></div>
<div class="stats">生存距離: <span id="finalDistance">0</span>m</div>
<button class="btn" onclick="restartGame()">重新飛行挑戰</button>
<button class="btn" onclick="backToMenu()">返回菜單</button>
</div>
</div>
<script>
// 遊戲主腳本
(function() {
'use strict';
// 確保遊戲環境純淨 - 防止第三方擴展干擾
const originalConsole = {...console};
const suppressExtensionErrors = () => {
const originalError = console.error;
console.error = function(...args) {
const errorMsg = args.join(' ');
// 過濾掉擴展相關的錯誤
if (!errorMsg.includes('extension') && !errorMsg.includes('chrome-extension')) {
originalError.apply(console, args);
}
};
// 5秒後恢復原始console
setTimeout(() => {
console.error = originalError;
}, 5000);
};
suppressExtensionErrors();
document.documentElement.classList.add('geometry-dash-game', 'notranslate');
document.documentElement.setAttribute('translate', 'no');
window._gameInitialized = true;
// 遊戲狀態
let gameState = 'menu';
let score = 0;
let distance = 0;
let bestScore = localStorage.getItem('bestScore') || 0;
let animationId;
// Canvas 設置
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
try {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
game.gameHeight = canvas.height;
// 確保玩家不會因為窗口尺寸問題而超出邊界
if (player.y + player.height > game.gameHeight - 10) {
player.y = game.gameHeight / 2; // 重新居中
}
console.log('畫布初始化成功:', canvas.width, 'x', canvas.height);
} catch (error) {
console.error('畫布初始化失敗:', error);
}
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 遊戲對象
const player = {
x: 100,
y: 300,
width: 30,
height: 30,
velocityY: 0,
rotation: 0,
color: '#FF6B6B',
trail: []
};
const game = {
gravity: 0.5, // 減小重力,下落更慢
jumpStrength: -10, // 減小跳躍力,更容易控制
speed: 3, // 減慢遊戲速度
obstacles: [],
particles: [],
lastObstacleX: 0,
difficultyLevel: 1,
backgroundOffset: 0,
stars: [],
gameHeight: 0,
safeZoneHeight: 200 // 增大安全通道高度
};
// 隨機關卡生成器 - 上下障礙物模式
class RandomLevelGenerator {
constructor() {
this.patterns = [
'simple_gap',
'narrow_gap',
'offset_gaps',
'multi_level',
'wave_pattern',
'tight_squeeze',
'staggered'
];
this.lastPattern = '';
this.patternCooldown = 0;
}
generateNextObstacles() {
if (this.patternCooldown > 0) {
this.patternCooldown--;
return;
}
const baseDistance = 350 + Math.random() * 150; // 增大障礙物間距
const patternDistance = game.lastObstacleX + baseDistance;
// 降低難度增長速度
const difficultyMultiplier = Math.min(1 + distance / 2000, 1.8); // 降低最大難度
game.difficultyLevel = Math.floor(difficultyMultiplier);
// 隨機選擇模式
let availablePatterns = this.patterns.filter(p => p !== this.lastPattern);
const pattern = availablePatterns[Math.floor(Math.random() * availablePatterns.length)];
this.lastPattern = pattern;
this.createPattern(pattern, patternDistance, difficultyMultiplier);
this.patternCooldown = Math.floor(Math.random() * 3) + 2; // 增加冷卻時間
}
createPattern(pattern, startX, difficulty) {
const screenHeight = game.gameHeight;
const baseGapSize = Math.max(game.safeZoneHeight + 50 - difficulty * 15, 140); // 增大縫隙,最小140px
switch(pattern) {
case 'simple_gap':
const gapY = 80 + Math.random() * (screenHeight - baseGapSize - 160); // 留更多空間
// 上方障礙物
game.obstacles.push(new Obstacle(startX, 'top_wall', 0, gapY, 60)); // 減小寬度
// 下方障礙物
game.obstacles.push(new Obstacle(startX, 'bottom_wall', gapY + baseGapSize, screenHeight - (gapY + baseGapSize), 60));
game.lastObstacleX = startX + 60;
console.log(`生成simple_gap: 上方(0,${gapY}) 下方(${gapY + baseGapSize},${screenHeight - (gapY + baseGapSize)})`);
break;
case 'narrow_gap':
const narrowGapY = 100 + Math.random() * (screenHeight - baseGapSize * 0.9 - 200);
const narrowGap = baseGapSize * 0.9; // 不要太窄
game.obstacles.push(new Obstacle(startX, 'top_wall', 0, narrowGapY, 50));
game.obstacles.push(new Obstacle(startX, 'bottom_wall', narrowGapY + narrowGap, screenHeight - (narrowGapY + narrowGap), 50));
game.lastObstacleX = startX + 50;
break;
case 'offset_gaps':
const gap1Y = 80 + Math.random() * (screenHeight - baseGapSize - 160);
const gap2Y = 80 + Math.random() * (screenHeight - baseGapSize - 160);
// 第一組
game.obstacles.push(new Obstacle(startX, 'top_wall', 0, gap1Y, 60));
game.obstacles.push(new Obstacle(startX, 'bottom_wall', gap1Y + baseGapSize, screenHeight - (gap1Y + baseGapSize), 60));
// 第二組(錯開)
game.obstacles.push(new Obstacle(startX + 120, 'top_wall', 0, gap2Y, 60));
game.obstacles.push(new Obstacle(startX + 120, 'bottom_wall', gap2Y + baseGapSize, screenHeight - (gap2Y + baseGapSize), 60));
game.lastObstacleX = startX + 180;
break;
case 'multi_level':
const levels = 3;
for(let i = 0; i < levels; i++) {
const levelGapY = 60 + Math.random() * (screenHeight - baseGapSize - 120);
game.obstacles.push(new Obstacle(startX + i * 80, 'top_wall', 0, levelGapY, 50));
game.obstacles.push(new Obstacle(startX + i * 80, 'bottom_wall', levelGapY + baseGapSize, screenHeight - (levelGapY + baseGapSize), 50));
}
game.lastObstacleX = startX + levels * 80;
break;
case 'wave_pattern':
for(let i = 0; i < 4; i++) {
const waveOffset = Math.sin(i * 0.8) * 60;
const waveGapY = 140 + waveOffset + Math.random() * 40;
game.obstacles.push(new Obstacle(startX + i * 70, 'top_wall', 0, waveGapY, 50));
game.obstacles.push(new Obstacle(startX + i * 70, 'bottom_wall', waveGapY + baseGapSize, screenHeight - (waveGapY + baseGapSize), 50));
}
game.lastObstacleX = startX + 280;
break;
case 'tight_squeeze':
const squeezeGap = Math.max(baseGapSize * 0.7, 80);
const squeezeY = (screenHeight - squeezeGap) / 2;
game.obstacles.push(new Obstacle(startX, 'top_wall', 0, squeezeY, 100));
game.obstacles.push(new Obstacle(startX, 'bottom_wall', squeezeY + squeezeGap, screenHeight - (squeezeY + squeezeGap), 100));
game.lastObstacleX = startX + 100;
break;
case 'staggered':
const staggerCount = 3;
for(let i = 0; i < staggerCount; i++) {
const staggerY = 90 + (i % 2) * 80 + Math.random() * 60;
const staggerGap = baseGapSize + (i % 2) * 30;
game.obstacles.push(new Obstacle(startX + i * 90, 'top_wall', 0, staggerY, 60));
game.obstacles.push(new Obstacle(startX + i * 90, 'bottom_wall', staggerY + staggerGap, screenHeight - (staggerY + staggerGap), 60));
}
game.lastObstacleX = startX + staggerCount * 90;
break;
}
}
}
const levelGenerator = new RandomLevelGenerator();
// 障礙物類 - 上下障礙物
class Obstacle {
constructor(x, type = 'top_wall', y = 0, height = 100, width = 80) {
this.x = x;
this.type = type;
this.width = width;
this.height = height;
this.y = y;
this.color = type.includes('top') ? '#FF0000' : '#8B0000';
this.glowIntensity = Math.random() * 0.5 + 0.5;
}
update() {
this.x -= game.speed;
this.glowIntensity = Math.sin(Date.now() * 0.01) * 0.3 + 0.7;
}
draw() {
// 強烈發光效果
ctx.shadowColor = this.color;
ctx.shadowBlur = 15 * this.glowIntensity;
// 明亮的漸變填充
const gradient = ctx.createLinearGradient(this.x, this.y, this.x, this.y + this.height);
if (this.type === 'top_wall') {
gradient.addColorStop(0, '#FF0000');
gradient.addColorStop(1, '#FF6B6B');
} else {
gradient.addColorStop(0, '#FF6B6B');
gradient.addColorStop(1, '#FF0000');
}
ctx.fillStyle = gradient;
ctx.fillRect(this.x, this.y, this.width, this.height);
// 明顯的邊框
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 2;
ctx.strokeRect(this.x, this.y, this.width, this.height);
// 調試信息 - 顯示障礙物位置
ctx.fillStyle = '#FFFFFF';
ctx.font = '10px Arial';
ctx.fillText(`${this.type}`, this.x + 5, this.y + 15);
// 重置陰影
ctx.shadowBlur = 0;
}
isColliding(player) {
return player.x < this.x + this.width - 5 &&
player.x + player.width > this.x + 5 &&
player.y < this.y + this.height - 5 &&
player.y + player.height > this.y + 5;
}
}
// 粒子效果類
class Particle {
constructor(x, y, type = 'explosion') {
this.x = x;
this.y = y;
this.type = type;
this.velocityX = (Math.random() - 0.5) * 10;
this.velocityY = (Math.random() - 0.5) * 10;
this.life = 60;
this.maxLife = 60;
this.size = Math.random() * 5 + 2;
this.color = `hsl(${Math.random() * 360}, 70%, 60%)`;
this.rotation = Math.random() * Math.PI * 2;
this.rotationSpeed = (Math.random() - 0.5) * 0.2;
}
update() {
this.x += this.velocityX;
this.y += this.velocityY;
this.velocityY += 0.3;
this.life--;
this.rotation += this.rotationSpeed;
if (this.type === 'trail') {
this.velocityX *= 0.98;
this.velocityY *= 0.98;
}
}
draw() {
const alpha = this.life / this.maxLife;
ctx.globalAlpha = alpha;
ctx.fillStyle = this.color;
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
if (this.type === 'trail') {
ctx.fillRect(-this.size/2, -this.size/2, this.size, this.size);
} else {
ctx.beginPath();
ctx.arc(0, 0, this.size, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
ctx.globalAlpha = 1;
}
}
// 背景星星
function initStars() {
game.stars = [];
for(let i = 0; i < 100; i++) {
game.stars.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height * 0.7,
size: Math.random() * 2 + 0.5,
speed: Math.random() * 0.5 + 0.2,
twinkle: Math.random() * Math.PI * 2
});
}
}
// 控制輸入 - 連續跳躍
function handleInput() {
if (gameState === 'playing') {
// 允許連續跳躍,不需要落地
player.velocityY = game.jumpStrength;
// 添加跳躍粒子效果
for(let i = 0; i < 3; i++) {
game.particles.push(new Particle(
player.x + player.width/2,
player.y + player.height/2,
'trail'
));
}
}
}
// 事件監聽
canvas.addEventListener('click', handleInput);
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
handleInput();
}
});
// 更新玩家 - 修復邊界檢測
function updatePlayer() {
// 重力持續作用
player.velocityY += game.gravity;
player.y += player.velocityY;
// 旋轉效果(根據速度方向)
if (player.velocityY < 0) {
player.rotation = Math.max(player.rotation - 0.1, -0.3); // 向上時逐漸旋轉
} else {
player.rotation = Math.min(player.rotation + 0.08, 0.5); // 向下時逐漸旋轉
}
// 上下邊界碰撞 - 修復邊界檢測
if (player.y <= 10) { // 給頂部留一些緩衝
console.log('撞到頂部邊界');
gameOver();
return;
}
if (player.y + player.height >= game.gameHeight - 10) { // 給底部留一些緩衝
console.log('撞到底部邊界');
gameOver();
return;
}
// 添加軌跡效果
if (Math.random() < 0.4) {
game.particles.push(new Particle(
player.x + Math.random() * player.width,
player.y + Math.random() * player.height,
'trail'
));
}
}
// 繪製玩家 - 增強可見性
function drawPlayer() {
ctx.save();
ctx.translate(player.x + player.width/2, player.y + player.height/2);
ctx.rotate(player.rotation);
// 強烈發光效果
ctx.shadowColor = '#FFD700';
ctx.shadowBlur = 20;
// 明亮的漸變填充
const gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, player.width/2);
gradient.addColorStop(0, '#FFFF00'); // 明黃色中心
gradient.addColorStop(0.7, '#FF6B6B'); // 紅色
gradient.addColorStop(1, '#FF0000'); // 深紅邊緣
ctx.fillStyle = gradient;
ctx.fillRect(-player.width/2, -player.height/2, player.width, player.height);
// 明顯的邊框
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 3;
ctx.strokeRect(-player.width/2, -player.height/2, player.width, player.height);
// 額外的外邊框
ctx.strokeStyle = '#FFD700';
ctx.lineWidth = 1;
ctx.strokeRect(-player.width/2 - 2, -player.height/2 - 2, player.width + 4, player.height + 4);
ctx.restore();
ctx.shadowBlur = 0;
// 調試信息
ctx.fillStyle = '#FFFFFF';
ctx.font = '12px Arial';
ctx.fillText(`Player: ${Math.round(player.x)}, ${Math.round(player.y)}`, 10, 50);
}
// 繪製背景 - 簡化版本
function drawBackground() {
// 簡單的深色背景
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 繪製星星
ctx.fillStyle = 'white';
game.stars.forEach(star => {
star.x -= star.speed;
if (star.x < -10) star.x = canvas.width + 10;
star.twinkle += 0.1;
const alpha = (Math.sin(star.twinkle) + 1) * 0.5;
ctx.globalAlpha = alpha * 0.8;
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fill();
});
ctx.globalAlpha = 1;
// 簡單的參考線(中間的安全區域)
ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
ctx.lineWidth = 1;
ctx.setLineDash([5, 5]);
const centerY = canvas.height / 2;
ctx.beginPath();
ctx.moveTo(0, centerY);
ctx.lineTo(canvas.width, centerY);
ctx.stroke();
ctx.setLineDash([]);
}
// 更新遊戲
function updateGame() {
if (gameState !== 'playing') return;
// 確保畫布已初始化
if (!game.gameHeight || game.gameHeight <= 0) {
game.gameHeight = canvas.height;
}
// 更新距離和分數
distance += game.speed * 0.1;
score = Math.floor(distance);
// 更新玩家
updatePlayer();
// 檢查遊戲是否結束(在updatePlayer中可能觸發)
if (gameState !== 'playing') return;
// 生成新障礙物
levelGenerator.generateNextObstacles();
// 更新障礙物
game.obstacles = game.obstacles.filter(obstacle => {
obstacle.update();
// 碰撞檢測
if (obstacle.isColliding(player)) {
console.log('與障礙物碰撞');
gameOver();
return false;
}
return obstacle.x > -obstacle.width;
});
// 更新粒子
game.particles = game.particles.filter(particle => {
particle.update();
return particle.life > 0;
});
// 增加遊戲速度 - 降低加速度
game.speed = Math.min(3 + distance * 0.005, 6); // 更慢的加速,最大速度6
// 更新UI
updateUI();
}
// 繪製遊戲
function drawGame() {
// 清除畫布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 繪製背景
drawBackground();
// 繪製障礙物
game.obstacles.forEach(obstacle => obstacle.draw());
// 繪製粒子
game.particles.forEach(particle => particle.draw());
// 繪製玩家
drawPlayer();
// 調試信息
ctx.fillStyle = '#FFFFFF';
ctx.font = '14px Arial';
ctx.fillText(`障礙物數量: ${game.obstacles.length}`, 10, 70);
ctx.fillText(`遊戲狀態: ${gameState}`, 10, 90);
ctx.fillText(`畫布尺寸: ${canvas.width}x${canvas.height}`, 10, 110);
}
// 遊戲循環
function gameLoop() {
updateGame();
drawGame();
animationId = requestAnimationFrame(gameLoop);
}
// 開始遊戲
function startGame() {
try {
console.log('開始遊戲...');
gameState = 'playing';
score = 0;
distance = 0;
// 確保畫布尺寸正確初始化
resizeCanvas();
// 重置玩家 - 確保在安全位置
player.x = 100;
player.y = Math.max(50, Math.min(canvas.height / 2, canvas.height - 80)); // 確保在安全範圍內
player.velocityY = 0;
player.rotation = 0;
console.log(`玩家初始位置: ${player.x}, ${player.y}`);
console.log(`畫布尺寸: ${canvas.width}x${canvas.height}`);
console.log(`安全範圍: 10 到 ${canvas.height - 40}`);
// 重置遊戲
game.speed = 3; // 從更慢的速度開始
game.obstacles = [];
game.particles = [];
game.lastObstacleX = 300; // 給玩家更多準備時間
game.difficultyLevel = 1;
// 重置關卡生成器
levelGenerator.lastPattern = '';
levelGenerator.patternCooldown = 0;
// 立即生成第一組障礙物
levelGenerator.generateNextObstacles();
// 初始化星星
initStars();
// 隱藏菜單
document.getElementById('startScreen').style.display = 'none';
document.getElementById('gameOverScreen').style.display = 'none';
// 開始遊戲循環
gameLoop();
console.log('遊戲已啓動');
} catch (error) {
console.error('遊戲啓動失敗:', error);
}
}
// 遊戲結束
function gameOver() {
console.log('遊戲結束被調用');
console.log('玩家位置:', player.x, player.y);
console.log('玩家速度:', player.velocityY);
console.log('畫布尺寸:', canvas.width, canvas.height);
gameState = 'gameOver';
cancelAnimationFrame(animationId);
// 爆炸效果
for(let i = 0; i < 20; i++) {
game.particles.push(new Particle(
player.x + player.width/2,
player.y + player.height/2
));
}
// 更新最佳分數
if (score > bestScore) {
bestScore = score;
localStorage.setItem('bestScore', bestScore);
}
// 顯示遊戲結束畫面
document.getElementById('finalScore').textContent = score;
document.getElementById('finalBestScore').textContent = bestScore;
document.getElementById('finalDistance').textContent = Math.floor(distance);
document.getElementById('gameOverScreen').style.display = 'flex';
}
// 重新開始遊戲
function restartGame() {
startGame();
}
// 返回菜單
function backToMenu() {
gameState = 'menu';
cancelAnimationFrame(animationId);
document.getElementById('startScreen').style.display = 'flex';
document.getElementById('gameOverScreen').style.display = 'none';
}
// 更新UI
function updateUI() {
document.getElementById('score').textContent = score;
document.getElementById('bestScore').textContent = bestScore;
document.getElementById('distance').textContent = Math.floor(distance);
// 更新難度顯示
const difficultyNames = ['簡單', '普通', '困難', '極難'];
const difficultyIndex = Math.min(game.difficultyLevel - 1, difficultyNames.length - 1);
document.getElementById('difficulty').textContent = difficultyNames[difficultyIndex];
}
// 全局函數定義 - 確保可以被 HTML 調用
window.startGame = startGame;
window.restartGame = restartGame;
window.backToMenu = backToMenu;
// 初始化
document.getElementById('bestScore').textContent = bestScore;
initStars();
// 在菜單狀態下也顯示背景動畫
function menuAnimation() {
if (gameState === 'menu') {
drawBackground();
requestAnimationFrame(menuAnimation);
}
}
menuAnimation();
})(); // 結束IIFE包裝
</script>
</body>
</html>