<!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;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
overflow: hidden;
padding: 20px;
}
#gameContainer {
position: relative;
width: 100%;
max-width: 900px;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5);
border-radius: 20px;
overflow: hidden;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
#gameCanvas {
display: block;
width: 100%;
background: linear-gradient(to bottom, #87CEEB, #1E90FF);
}
/* 顶部玩家信息栏 */
#topBar {
display: flex;
justify-content: space-between;
padding: 15px 25px;
background: rgba(0, 0, 0, 0.7);
color: white;
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
}
.player-status {
display: flex;
align-items: center;
gap: 15px;
}
.player-info {
display: flex;
align-items: center;
gap: 8px;
background: rgba(255, 255, 255, 0.1);
padding: 8px 15px;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
.player-icon {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
}
.player1-icon {
background: linear-gradient(135deg, #3498db, #2980b9);
}
.player2-icon {
background: linear-gradient(135deg, #e74c3c, #c0392b);
}
.skill-status {
display: flex;
align-items: center;
gap: 5px;
font-size: 14px;
}
.skill-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background: #2ecc71;
}
.skill-indicator.cooldown {
background: #e74c3c;
}
.level-info {
display: flex;
align-items: center;
gap: 10px;
background: rgba(255, 255, 255, 0.1);
padding: 8px 20px;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* 游戏开始界面 */
#startScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.85);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 25;
padding: 30px;
text-align: center;
}
#gameTitle {
margin-bottom: 40px;
text-align: center;
}
h1 {
font-size: 60px;
margin-bottom: 15px;
color: #FFD700;
text-shadow: 4px 4px 0 #FF5722, 8px 8px 0 rgba(0, 0, 0, 0.2);
letter-spacing: 2px;
font-weight: 800;
}
h2 {
font-size: 28px;
color: #4FC3F7;
text-shadow: 2px 2px 0 #0288D1;
font-weight: 600;
}
.game-description {
max-width: 600px;
background: rgba(255, 255, 255, 0.1);
padding: 25px;
border-radius: 15px;
margin: 20px 0 30px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
line-height: 1.6;
font-size: 18px;
}
.controls-info {
display: flex;
justify-content: center;
gap: 40px;
margin: 25px 0 40px;
flex-wrap: wrap;
}
.control-set {
background: rgba(255, 255, 255, 0.1);
padding: 20px;
border-radius: 15px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
min-width: 220px;
}
.control-title {
font-size: 20px;
margin-bottom: 15px;
color: #FFD700;
font-weight: 600;
}
.key {
display: inline-block;
background: rgba(0, 0, 0, 0.5);
padding: 5px 10px;
border-radius: 8px;
margin: 5px;
border: 1px solid rgba(255, 255, 255, 0.2);
font-family: monospace;
min-width: 30px;
text-align: center;
}
button {
background: linear-gradient(to bottom, #FF5722, #E64A19);
border: none;
color: white;
padding: 15px 40px;
border-radius: 50px;
cursor: pointer;
font-size: 20px;
font-weight: 600;
margin-top: 10px;
transition: all 0.3s;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
border: 2px solid rgba(255, 255, 255, 0.2);
letter-spacing: 1px;
}
button:hover {
background: linear-gradient(to bottom, #FF7043, #F4511E);
transform: translateY(-5px);
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.4);
}
button:active {
transform: translateY(-2px);
}
/* 公告屏幕 */
#announcementScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 30;
padding: 30px;
text-align: center;
}
#announcementContent {
max-width: 700px;
background: rgba(255, 255, 255, 0.1);
padding: 40px;
border-radius: 20px;
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.2);
margin-bottom: 30px;
}
#announcementContent h2 {
font-size: 36px;
margin-bottom: 25px;
color: #FFD700;
}
#announcementContent p {
margin: 15px 0;
line-height: 1.7;
font-size: 18px;
}
.copyright {
margin-top: 30px;
color: rgba(255, 255, 255, 0.7);
font-size: 16px;
}
/* 游戏UI */
#ui {
position: absolute;
top: 80px;
left: 15px;
right: 15px;
display: flex;
justify-content: space-between;
color: white;
font-size: 18px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
z-index: 10;
}
#controls {
position: absolute;
bottom: 15px;
left: 15px;
color: white;
font-size: 14px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 10px 15px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
#levelComplete {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.85);
color: white;
padding: 40px 60px;
border-radius: 20px;
text-align: center;
display: none;
z-index: 20;
backdrop-filter: blur(10px);
border: 3px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 0 40px rgba(0, 0, 0, 0.7);
}
#levelComplete h2 {
font-size: 40px;
margin-bottom: 20px;
color: #FFD700;
text-shadow: 2px 2px 0 #FF5722;
}
/* 响应式设计 */
@media (max-width: 768px) {
h1 {
font-size: 40px;
}
h2 {
font-size: 22px;
}
.controls-info {
flex-direction: column;
gap: 20px;
}
.control-set {
min-width: auto;
width: 100%;
}
#topBar {
flex-direction: column;
gap: 15px;
align-items: center;
}
}
/* 动画效果 */
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s infinite;
}
.floating {
animation: floating 3s ease-in-out infinite;
}
@keyframes floating {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
/* 新添加的样式 */
#pauseScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.85);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 40;
padding: 30px;
text-align: center;
}
#pauseScreen h2 {
font-size: 50px;
margin-bottom: 30px;
color: #FFD700;
}
#pauseScreen button {
margin: 10px;
}
#gameStats {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 20px;
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
.stat-item {
display: flex;
justify-content: space-between;
}
#bossHealthBar {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
width: 300px;
height: 20px;
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
overflow: hidden;
display: none;
z-index: 15;
border: 2px solid rgba(255, 255, 255, 0.2);
}
#bossHealthFill {
height: 100%;
background: linear-gradient(to right, #FF5722, #FFD700);
width: 100%;
transition: width 0.3s;
}
#bossName {
position: absolute;
top: -25px;
left: 0;
width: 100%;
text-align: center;
color: white;
font-weight: bold;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
}
#powerUpDisplay {
position: absolute;
bottom: 60px;
left: 15px;
display: flex;
gap: 10px;
color: white;
font-size: 14px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 10px 15px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
.powerUp-item {
display: flex;
align-items: center;
gap: 5px;
}
.powerUp-icon {
width: 16px;
height: 16px;
border-radius: 50%;
}
.laser-icon {
background: #2196F3;
}
.shield-icon {
background: #4CAF50;
}
/* 新添加的样式 - 升级版 */
#comboDisplay {
position: absolute;
top: 20px;
right: 20px;
color: white;
font-size: 18px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 10px 15px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
display: none;
}
#scoreDisplay {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-size: 18px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 10px 15px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
#abilityBar {
position: absolute;
bottom: 15px;
right: 15px;
display: flex;
gap: 10px;
}
.ability-button {
width: 50px;
height: 50px;
border-radius: 10px;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
cursor: pointer;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
transition: all 0.2s;
}
.ability-button:hover {
transform: scale(1.1);
background: rgba(0, 0, 0, 0.7);
}
.ability-button:active {
transform: scale(0.95);
}
.ability-button.cooldown {
opacity: 0.5;
cursor: not-allowed;
}
.player1-ability {
background: linear-gradient(135deg, #3498db, #2980b9);
}
.player2-ability {
background: linear-gradient(135deg, #e74c3c, #c0392b);
}
.damage-popup {
position: absolute;
color: #ff5555;
font-weight: bold;
font-size: 16px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
animation: floatUp 1s ease-out forwards;
pointer-events: none;
}
@keyframes floatUp {
0% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-50px);
opacity: 0;
}
}
.screen-shake {
animation: shake 0.5s ease-in-out;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
#checkpointIndicator {
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 14px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 8px 15px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
display: none;
}
</style>
</head>
<body>
<div id="gameContainer">
<div id="topBar">
<div class="player-status">
<div class="player-info">
<div class="player-icon player1-icon">P1</div>
<div>生命: <span id="player1Lives">3</span></div>
<div class="skill-status">
| 射击:
<div class="skill-indicator" id="player1Skill"></div>
<span id="player1SkillText">可用</span>
</div>
</div>
<div class="player-info">
<div class="player-icon player2-icon">P2</div>
<div>生命: <span id="player2Lives">3</span></div>
<div class="skill-status">
| 射击:
<div class="skill-indicator" id="player2Skill"></div>
<span id="player2SkillText">可用</span>
</div>
</div>
</div>
<div class="level-info">
<i class="fas fa-map-marker-alt"></i>
<div>关卡: <span id="currentLevel">1</span>/10</div>
</div>
</div>
<canvas id="gameCanvas" width="800" height="500"></canvas>
<div id="bossHealthBar">
<div id="bossHealthFill"></div>
<div id="bossName">Boss</div>
</div>
<div id="powerUpDisplay">
<div class="powerUp-item">
<div class="powerUp-icon laser-icon"></div>
<span id="laserTimer">0</span>
</div>
<div class="powerUp-item">
<div class="powerUp-icon shield-icon"></div>
<span id="shieldCount">0</span>
</div>
</div>
<div id="scoreDisplay">分数: <span id="scoreValue">0</span></div>
<div id="comboDisplay">连击: <span id="comboValue">0</span>x</div>
<div id="abilityBar">
<div class="ability-button player1-ability" id="player1Ability">Q</div>
<div class="ability-button player2-ability" id="player2Ability">P</div>
</div>
<div id="checkpointIndicator">检查点已激活!</div>
<div id="ui">
<!-- 游戏中的UI元素 -->
</div>
<div id="controls">
<div>玩家1: WAD移动, S射击, Q技能 | 玩家2: IGL移动, O射击, P技能 | P暂停</div>
</div>
<div id="levelComplete">
<h2>关卡完成!</h2>
<p>恭喜你们通过了当前关卡!</p>
<div id="gameStats">
<div class="stat-item">
<span>收集金币:</span>
<span id="collectedCoins">0</span>
</div>
<div class="stat-item">
<span>消灭敌人:</span>
<span id="killedEnemies">0</span>
</div>
<div class="stat-item">
<span>剩余生命:</span>
<span id="remainingLives">0</span>
</div>
<div class="stat-item">
<span>连击次数:</span>
<span id="maxCombo">0</span>
</div>
<div class="stat-item">
<span>获得分数:</span>
<span id="levelScore">0</span>
</div>
</div>
<button id="nextLevelBtn">下一关</button>
</div>
<div id="pauseScreen">
<h2>游戏暂停</h2>
<button id="resumeBtn">继续游戏</button>
<button id="restartBtn">重新开始</button>
<button id="menuBtn">返回主菜单</button>
</div>
<div id="announcementScreen">
<div id="announcementContent">
<h2>游戏公告</h2>
<p>欢迎大家来游玩我的新作品,我是曙光深海独行!</p>
<p>本游戏为电脑游戏,请使用键盘操作。</p>
<p>本人因为学业问题已退出工作室,感谢大家一直以来的支持。</p>
<p>希望你们喜欢这个游戏!</p>
</div>
<button id="continueBtn">继续游戏</button>
<div class="copyright">© 2023 曙光深海独行 版权所有</div>
</div>
<div id="startScreen">
<div id="gameTitle" class="floating">
<h1>卡通冒险岛</h1>
<h2>双人射击闯关游戏</h2>
</div>
<div class="game-description">
帮助两位英雄通过所有关卡,收集金币,避开敌人!使用射击技能消灭敌人。
</div>
<div class="controls-info">
<div class="control-set">
<div class="control-title">玩家1控制</div>
<div>移动: <span class="key">W</span> <span class="key">A</span> <span class="key">D</span></div>
<div>射击: <span class="key">S</span></div>
<div>特殊技能: <span class="key">Q</span></div>
</div>
<div class="control-set">
<div class="control-title">玩家2控制</div>
<div>移动: <span class="key">I</span> <span class="key">G</span> <span class="key">L</span></div>
<div>射击: <span class="key">O</span></div>
<div>特殊技能: <span class="key">P</span></div>
</div>
</div>
<button id="startBtn" class="pulse">开始游戏</button>
</div>
</div>
<script>
// 游戏初始化
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const announcementScreen = document.getElementById('announcementScreen');
const startScreen = document.getElementById('startScreen');
const startBtn = document.getElementById('startBtn');
const continueBtn = document.getElementById('continueBtn');
const levelCompleteScreen = document.getElementById('levelComplete');
const nextLevelBtn = document.getElementById('nextLevelBtn');
const pauseScreen = document.getElementById('pauseScreen');
const resumeBtn = document.getElementById('resumeBtn');
const restartBtn = document.getElementById('restartBtn');
const menuBtn = document.getElementById('menuBtn');
const bossHealthBar = document.getElementById('bossHealthBar');
const bossHealthFill = document.getElementById('bossHealthFill');
const bossName = document.getElementById('bossName');
const laserTimerElement = document.getElementById('laserTimer');
const shieldCountElement = document.getElementById('shieldCount');
const scoreDisplay = document.getElementById('scoreDisplay');
const scoreValue = document.getElementById('scoreValue');
const comboDisplay = document.getElementById('comboDisplay');
const comboValue = document.getElementById('comboValue');
const player1AbilityBtn = document.getElementById('player1Ability');
const player2AbilityBtn = document.getElementById('player2Ability');
const maxComboElement = document.getElementById('maxCombo');
const levelScoreElement = document.getElementById('levelScore');
const checkpointIndicator = document.getElementById('checkpointIndicator');
// 获取所有需要的UI元素
const player1LivesElement = document.getElementById('player1Lives');
const player2LivesElement = document.getElementById('player2Lives');
const player1SkillElement = document.getElementById('player1Skill');
const player2SkillElement = document.getElementById('player2Skill');
const player1SkillTextElement = document.getElementById('player1SkillText');
const player2SkillTextElement = document.getElementById('player2SkillText');
const currentLevelElement = document.getElementById('currentLevel');
const collectedCoinsElement = document.getElementById('collectedCoins');
const killedEnemiesElement = document.getElementById('killedEnemies');
const remainingLivesElement = document.getElementById('remainingLives');
// 游戏状态
let gameRunning = false;
let gamePaused = false;
let currentLevel = 1;
let totalLevels = 10;
let score = 0;
let combo = 0;
let maxCombo = 0;
let comboTimeout = null;
let gameStats = {
collectedCoins: 0,
killedEnemies: 0,
remainingLives: 0
};
// 检查点系统
let checkpoint = {
x: 50,
y: 300,
active: false
};
// 键盘状态管理
const keys = {
'w': false, 'a': false, 'd': false, 's': false, 'q': false,
'i': false, 'g': false, 'l': false, 'o': false, 'p': false,
'pause': false
};
// 键盘事件监听
window.addEventListener('keydown', (e) => {
const key = e.key.toLowerCase();
if (keys.hasOwnProperty(key)) {
keys[key] = true;
// 暂停游戏
if (key === 'pause' && gameRunning) {
togglePause();
}
e.preventDefault();
}
});
window.addEventListener('keyup', (e) => {
const key = e.key.toLowerCase();
if (keys.hasOwnProperty(key)) {
keys[key] = false;
e.preventDefault();
}
});
// 伤害数字显示
const damagePopups = [];
function createDamagePopup(x, y, damage) {
damagePopups.push({
x: x,
y: y,
text: damage.toString(),
life: 60,
maxLife: 60
});
}
function updateDamagePopups() {
for (let i = damagePopups.length - 1; i >= 0; i--) {
damagePopups[i].life--;
damagePopups[i].y -= 1;
if (damagePopups[i].life <= 0) {
damagePopups.splice(i, 1);
}
}
}
function drawDamagePopups() {
ctx.save();
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
for (let popup of damagePopups) {
const alpha = popup.life / popup.maxLife;
ctx.fillStyle = `rgba(255, 85, 85, ${alpha})`;
ctx.fillText(popup.text, popup.x, popup.y);
}
ctx.restore();
}
// 屏幕震动效果
function screenShake() {
document.getElementById('gameContainer').classList.add('screen-shake');
setTimeout(() => {
document.getElementById('gameContainer').classList.remove('screen-shake');
}, 500);
}
// 连击系统
function addCombo() {
combo++;
if (combo > maxCombo) {
maxCombo = combo;
}
comboValue.textContent = combo;
comboDisplay.style.display = 'block';
// 清除之前的计时器
if (comboTimeout) {
clearTimeout(comboTimeout);
}
// 设置连击重置计时器
comboTimeout = setTimeout(() => {
combo = 0;
comboDisplay.style.display = 'none';
}, 3000);
}
// 检查点系统
function activateCheckpoint(x, y) {
checkpoint.x = x;
checkpoint.y = y;
checkpoint.active = true;
// 显示检查点激活提示
checkpointIndicator.style.display = 'block';
setTimeout(() => {
checkpointIndicator.style.display = 'none';
}, 2000);
}
// 粒子效果类
class Particle {
constructor(x, y, color, size, speedX, speedY, life) {
this.x = x;
this.y = y;
this.color = color;
this.size = size;
this.speedX = speedX;
this.speedY = speedY;
this.life = life;
this.maxLife = life;
}
update() {
this.x += this.speedX;
this.y += this.speedY;
this.life--;
// 添加重力效果
this.speedY += 0.1;
return this.life > 0;
}
draw() {
const alpha = this.life / this.maxLife;
ctx.save();
ctx.globalAlpha = alpha;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
// 子弹类
class Bullet {
constructor(x, y, direction, color, type = 'normal') {
this.x = x;
this.y = y;
this.width = 8;
this.height = 8;
this.speed = type === 'laser' ? 15 : 10;
this.direction = direction;
this.color = color;
this.type = type;
this.particles = [];
this.damage = type === 'laser' ? 2 : 1;
}
update() {
this.x += this.speed * this.direction;
// 激光子弹的特殊效果
if (this.type === 'laser') {
// 添加粒子效果
if (Math.random() < 0.7) {
this.particles.push(new Particle(
this.x,
this.y + (Math.random() - 0.5) * 10,
this.color,
Math.random() * 3 + 1,
(Math.random() - 0.5) * 2,
(Math.random() - 0.5) * 2,
Math.random() * 20 + 10
));
}
// 更新粒子
for (let i = this.particles.length - 1; i >= 0; i--) {
if (!this.particles[i].update()) {
this.particles.splice(i, 1);
}
}
}
}
draw() {
if (this.type === 'laser') {
// 绘制激光子弹
ctx.fillStyle = this.color;
ctx.fillRect(this.x - 10, this.y - 2, 20, 4);
// 绘制发光效果
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.fillRect(this.x - 8, this.y - 1, 16, 2);
// 绘制粒子
for (let particle of this.particles) {
particle.draw();
}
} else {
// 普通子弹
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.width/2, 0, Math.PI * 2);
ctx.fill();
// 添加发光效果
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(this.x - 2 * this.direction, this.y, this.width/4, 0, Math.PI * 2);
ctx.fill();
}
}
isOffScreen() {
return this.x < 0 || this.x > canvas.width;
}
}
// 道具类
class PowerUp {
constructor(x, y, type) {
this.x = x;
this.y = y;
this.width = 20;
this.height = 20;
this.type = type;
this.collected = false;
this.animation = 0;
// 根据类型设置颜色
if (type === 'health') {
this.color = '#FF5252';
} else if (type === 'laser') {
this.color = '#2196F3';
} else if (type === 'shield') {
this.color = '#4CAF50';
} else if (type === 'score') {
this.color = '#FFD700';
} else if (type === 'speed') {
this.color = '#9C27B0';
}
}
update() {
this.animation += 0.05;
this.y += Math.sin(this.animation) * 0.5; // 上下浮动效果
}
draw() {
ctx.save();
// 闪烁效果
const alpha = 0.7 + 0.3 * Math.sin(this.animation * 3);
ctx.globalAlpha = alpha;
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.width/2, 0, Math.PI * 2);
ctx.fill();
// 绘制内部图标
ctx.fillStyle = 'white';
if (this.type === 'health') {
// 心形
ctx.beginPath();
ctx.moveTo(this.x, this.y - 3);
ctx.bezierCurveTo(
this.x + 5, this.y - 8,
this.x + 8, this.y - 3,
this.x, this.y + 5
);
ctx.bezierCurveTo(
this.x - 8, this.y - 3,
this.x - 5, this.y - 8,
this.x, this.y - 3
);
ctx.fill();
} else if (this.type === 'laser') {
// 闪电
ctx.beginPath();
ctx.moveTo(this.x - 3, this.y - 5);
ctx.lineTo(this.x + 3, this.y);
ctx.lineTo(this.x - 3, this.y);
ctx.lineTo(this.x + 3, this.y + 5);
ctx.fill();
} else if (this.type === 'shield') {
// 盾牌
ctx.beginPath();
ctx.arc(this.x, this.y, 6, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, 4, 0, Math.PI * 2);
ctx.fill();
} else if (this.type === 'score') {
// 星星
ctx.beginPath();
ctx.moveTo(this.x, this.y - 5);
ctx.lineTo(this.x + 2, this.y - 2);
ctx.lineTo(this.x + 5, this.y);
ctx.lineTo(this.x + 2, this.y + 2);
ctx.lineTo(this.x, this.y + 5);
ctx.lineTo(this.x - 2, this.y + 2);
ctx.lineTo(this.x - 5, this.y);
ctx.lineTo(this.x - 2, this.y - 2);
ctx.closePath();
ctx.fill();
} else if (this.type === 'speed') {
// 闪电
ctx.beginPath();
ctx.moveTo(this.x - 3, this.y - 5);
ctx.lineTo(this.x + 3, this.y);
ctx.lineTo(this.x - 3, this.y);
ctx.lineTo(this.x + 3, this.y + 5);
ctx.fill();
}
ctx.restore();
}
checkCollision(player) {
return !this.collected &&
this.x < player.x + player.width &&
this.x + this.width > player.x &&
this.y < player.y + player.height &&
this.y + this.height > player.y;
}
}
// 玩家类
class Player {
constructor(x, y, color, controls, skillType) {
this.x = x;
this.y = y;
this.width = 32;
this.height = 48;
this.color = color;
this.velocityX = 0;
this.velocityY = 0;
this.jumping = false;
this.onGround = false;
this.lives = 3;
this.skillCooldown = 0;
this.skillActive = false;
this.skillDuration = 0;
this.controls = controls;
this.skillType = skillType;
this.facingRight = true;
this.collectedCoins = 0;
this.invincible = 0;
this.animationFrame = 0;
this.bullets = [];
this.maxBullets = 3;
this.powerUps = {
laser: 0,
shield: 0,
speed: 0
};
this.particles = [];
this.abilityCooldown = 0;
this.abilityActive = false;
this.abilityDuration = 0;
}
update(platforms, enemies, coins, hazards, powerUps, checkpoints) {
if (gamePaused) return;
// 更新动画帧
this.animationFrame++;
// 无敌时间减少
if (this.invincible > 0) {
this.invincible--;
}
// 应用重力
if (!this.onGround) {
this.velocityY += 0.4;
}
// 限制下落速度
if (this.velocityY > 10) {
this.velocityY = 10;
}
// 更新位置
this.x += this.velocityX;
this.y += this.velocityY;
// 技能冷却
if (this.skillCooldown > 0) {
this.skillCooldown--;
}
// 技能持续时间
if (this.skillActive) {
this.skillDuration--;
if (this.skillDuration <= 0) {
this.skillActive = false;
}
}
// 特殊能力冷却
if (this.abilityCooldown > 0) {
this.abilityCooldown--;
// 更新UI
if (this.color === '#3498db') {
player1AbilityBtn.textContent = Math.ceil(this.abilityCooldown / 60);
player1AbilityBtn.classList.add('cooldown');
} else {
player2AbilityBtn.textContent = Math.ceil(this.abilityCooldown / 60);
player2AbilityBtn.classList.add('cooldown');
}
} else {
// 更新UI
if (this.color === '#3498db') {
player1AbilityBtn.textContent = 'Q';
player1AbilityBtn.classList.remove('cooldown');
} else {
player2AbilityBtn.textContent = 'P';
player2AbilityBtn.classList.remove('cooldown');
}
}
// 特殊能力持续时间
if (this.abilityActive) {
this.abilityDuration--;
if (this.abilityDuration <= 0) {
this.abilityActive = false;
}
}
// 边界检查
if (this.x < 0) this.x = 0;
if (this.x + this.width > canvas.width) this.x = canvas.width - this.width;
if (this.y > canvas.height) {
this.respawn();
this.lives--;
if (this.lives <= 0) {
gameOver();
}
}
// 平台碰撞检测
this.onGround = false;
for (let platform of platforms) {
if (this.x < platform.x + platform.width &&
this.x + this.width > platform.x &&
this.y + this.height > platform.y &&
this.y + this.height < platform.y + platform.height &&
this.velocityY > 0) {
this.y = platform.y - this.height;
this.velocityY = 0;
this.onGround = true;
this.jumping = false;
}
}
// 检查点碰撞检测
for (let cp of checkpoints) {
if (this.x < cp.x + cp.width &&
this.x + this.width > cp.x &&
this.y < cp.y + cp.height &&
this.y + this.height > cp.y) {
if (!cp.activated) {
cp.activated = true;
activateCheckpoint(cp.x, cp.y);
}
}
}
// 敌人碰撞检测
if (this.invincible === 0) {
for (let enemy of enemies) {
if (!enemy.dead && this.x < enemy.x + enemy.width &&
this.x + this.width > enemy.x &&
this.y < enemy.y + enemy.height &&
this.y + this.height > enemy.y) {
// 检查是否从上方踩到敌人
if (this.velocityY > 0 && this.y + this.height < enemy.y + enemy.height/2) {
// 踩死敌人
enemy.dead = true;
gameStats.killedEnemies++;
this.velocityY = -10; // 反弹
// 添加粒子效果
for (let i = 0; i < 10; i++) {
this.particles.push(new Particle(
enemy.x + enemy.width/2,
enemy.y + enemy.height/2,
enemy.color,
Math.random() * 3 + 1,
(Math.random() - 0.5) * 5,
(Math.random() - 0.5) * 5,
Math.random() * 30 + 20
));
}
// 增加分数和连击
addScore(50);
addCombo();
} else {
// 如果玩家有护盾道具,则不受伤害
if (this.powerUps.shield > 0) {
this.powerUps.shield--;
// 反弹敌人
if (this.x < enemy.x) {
enemy.velocityX = 5;
} else {
enemy.velocityX = -5;
}
} else {
this.respawn();
this.lives--;
this.invincible = 120; // 2秒无敌时间
if (this.lives <= 0) {
gameOver();
}
}
}
}
}
}
// 危险物品碰撞检测
if (this.invincible === 0) {
for (let hazard of hazards) {
if (this.x < hazard.x + hazard.width &&
this.x + this.width > hazard.x &&
this.y < hazard.y + hazard.height &&
this.y + this.height > hazard.y) {
this.respawn();
this.lives--;
this.invincible = 120;
if (this.lives <= 0) {
gameOver();
}
}
}
}
// 金币碰撞检测
for (let i = coins.length - 1; i >= 0; i--) {
let coin = coins[i];
if (this.x < coin.x + coin.width &&
this.x + this.width > coin.x &&
this.y < coin.y + coin.height &&
this.y + this.height > coin.y) {
this.collectedCoins++;
gameStats.collectedCoins++;
coins.splice(i, 1);
// 增加分数
addScore(10);
// 添加粒子效果
for (let i = 0; i < 5; i++) {
this.particles.push(new Particle(
coin.x + coin.width/2,
coin.y + coin.height/2,
coin.color,
Math.random() * 2 + 1,
(Math.random() - 0.5) * 3,
(Math.random() - 0.5) * 3,
Math.random() * 20 + 10
));
}
}
}
// 道具碰撞检测
for (let i = powerUps.length - 1; i >= 0; i--) {
let powerUp = powerUps[i];
if (powerUp.checkCollision(this)) {
powerUp.collected = true;
powerUps.splice(i, 1);
if (powerUp.type === 'health') {
this.lives = Math.min(this.lives + 1, 5);
} else if (powerUp.type === 'laser') {
this.powerUps.laser = 300; // 5秒激光子弹
} else if (powerUp.type === 'shield') {
this.powerUps.shield = 3; // 3次护盾
} else if (powerUp.type === 'score') {
addScore(100);
} else if (powerUp.type === 'speed') {
this.powerUps.speed = 300; // 5秒加速
}
// 添加粒子效果
for (let i = 0; i < 15; i++) {
this.particles.push(new Particle(
powerUp.x,
powerUp.y,
powerUp.color,
Math.random() * 3 + 1,
(Math.random() - 0.5) * 4,
(Math.random() - 0.5) * 4,
Math.random() * 40 + 20
));
}
}
}
// 处理玩家输入
if (keys[this.controls.left]) {
this.move('left');
} else if (keys[this.controls.right]) {
this.move('right');
} else {
this.move('stop');
}
if (keys[this.controls.up]) {
this.jump();
}
if (keys[this.controls.skill]) {
this.useSkill();
}
if (keys[this.controls.ability] && this.abilityCooldown === 0) {
this.useAbility();
}
// 更新子弹
for (let i = this.bullets.length - 1; i >= 0; i--) {
this.bullets[i].update();
// 检查子弹是否超出屏幕
if (this.bullets[i].isOffScreen()) {
this.bullets.splice(i, 1);
}
}
// 更新粒子
for (let i = this.particles.length - 1; i >= 0; i--) {
if (!this.particles[i].update()) {
this.particles.splice(i, 1);
}
}
// 更新道具持续时间
if (this.powerUps.laser > 0) {
this.powerUps.laser--;
}
if (this.powerUps.speed > 0) {
this.powerUps.speed--;
}
}
draw() {
// 绘制玩家角色
ctx.save();
// 无敌闪烁效果
if (this.invincible > 0 && Math.floor(this.invincible / 10) % 2 === 0) {
ctx.globalAlpha = 0.5;
}
// 绘制身体
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
// 绘制面部特征
ctx.fillStyle = 'white';
ctx.fillRect(this.facingRight ? this.x + 20 : this.x + 8, this.y + 12, 8, 8);
// 绘制腿(动画效果)
ctx.fillStyle = this.color;
let legOffset = Math.sin(this.animationFrame * 0.2) * 3;
if (this.velocityX !== 0 && this.onGround) {
ctx.fillRect(this.x + 5, this.y + this.height, 8, -10 + legOffset);
ctx.fillRect(this.x + this.width - 13, this.y + this.height, 8, -10 - legOffset);
} else {
ctx.fillRect(this.x + 5, this.y + this.height, 8, -10);
ctx.fillRect(this.x + this.width - 13, this.y + this.height, 8, -10);
}
// 绘制子弹
for (let bullet of this.bullets) {
bullet.draw();
}
// 绘制粒子
for (let particle of this.particles) {
particle.draw();
}
// 绘制护盾效果
if (this.powerUps.shield > 0) {
ctx.strokeStyle = '#4CAF50';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width, 0, Math.PI * 2);
ctx.stroke();
}
// 绘制加速效果
if (this.powerUps.speed > 0) {
ctx.strokeStyle = '#9C27B0';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width + 5, 0, Math.PI * 2);
ctx.stroke();
}
// 绘制特殊能力效果
if (this.abilityActive) {
ctx.strokeStyle = '#FFD700';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width + 10, 0, Math.PI * 2);
ctx.stroke();
}
ctx.restore();
}
move(direction) {
const baseSpeed = 4;
const speedMultiplier = this.powerUps.speed > 0 ? 1.5 : 1;
if (direction === 'left') {
this.velocityX = -baseSpeed * speedMultiplier;
this.facingRight = false;
} else if (direction === 'right') {
this.velocityX = baseSpeed * speedMultiplier;
this.facingRight = true;
} else if (direction === 'stop') {
this.velocityX = 0;
}
}
jump() {
if (this.onGround && !this.jumping) {
this.velocityY = -10;
this.jumping = true;
this.onGround = false;
}
}
useSkill() {
if (this.skillCooldown === 0 && this.bullets.length < this.maxBullets) {
this.skillActive = true;
this.skillCooldown = this.powerUps.laser > 0 ? 10 : 20; // 激光子弹冷却时间更短
// 创建子弹
let bulletX = this.facingRight ? this.x + this.width : this.x;
let bulletY = this.y + this.height / 2;
let direction = this.facingRight ? 1 : -1;
let bulletColor = this.color === '#3498db' ? '#3498db' : '#e74c3c';
let bulletType = this.powerUps.laser > 0 ? 'laser' : 'normal';
this.bullets.push(new Bullet(bulletX, bulletY, direction, bulletColor, bulletType));
}
}
useAbility() {
if (this.abilityCooldown === 0) {
this.abilityActive = true;
this.abilityDuration = 180; // 3秒持续时间
this.abilityCooldown = 600; // 10秒冷却时间
// 根据玩家颜色执行不同的能力
if (this.color === '#3498db') {
// 玩家1能力:范围爆炸
for (let enemy of enemies) {
if (!enemy.dead) {
const distance = Math.sqrt(
Math.pow(this.x - enemy.x, 2) +
Math.pow(this.y - enemy.y, 2)
);
if (distance < 150) {
enemy.hitByBullet('ability');
createDamagePopup(enemy.x + enemy.width/2, enemy.y, 3);
addScore(30);
addCombo();
}
}
}
// 添加爆炸粒子效果
for (let i = 0; i < 50; i++) {
this.particles.push(new Particle(
this.x + this.width/2,
this.y + this.height/2,
'#3498db',
Math.random() * 5 + 2,
(Math.random() - 0.5) * 10,
(Math.random() - 0.5) * 10,
Math.random() * 40 + 20
));
}
} else {
// 玩家2能力:治疗和无敌
this.lives = Math.min(this.lives + 1, 5);
this.invincible = 180; // 3秒无敌
// 添加治疗粒子效果
for (let i = 0; i < 30; i++) {
this.particles.push(new Particle(
this.x + this.width/2,
this.y + this.height/2,
'#e74c3c',
Math.random() * 4 + 1,
(Math.random() - 0.5) * 6,
(Math.random() - 0.5) * 6,
Math.random() * 30 + 20
));
}
}
// 屏幕震动
screenShake();
}
}
respawn() {
// 如果有激活的检查点,就在检查点重生
if (checkpoint.active) {
this.x = checkpoint.x;
this.y = checkpoint.y;
} else {
this.x = 50;
this.y = 300;
}
this.velocityX = 0;
this.velocityY = 0;
this.bullets = [];
this.invincible = 120;
}
}
// 平台类
class Platform {
constructor(x, y, width, height, color = '#8B4513', moving = false, moveRange = 0, moveSpeed = 0, vertical = false) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.moving = moving;
this.moveRange = moveRange;
this.moveSpeed = moveSpeed;
this.direction = 1;
this.originalX = x;
this.originalY = y;
this.vertical = vertical;
}
update() {
if (this.moving) {
if (this.vertical) {
this.y += this.moveSpeed * this.direction;
if (this.y <= this.originalY - this.moveRange || this.y >= this.originalY + this.moveRange) {
this.direction *= -1;
}
} else {
this.x += this.moveSpeed * this.direction;
if (this.x <= this.originalX - this.moveRange || this.x >= this.originalX + this.moveRange) {
this.direction *= -1;
}
}
}
}
draw() {
// 绘制平台主体
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
// 添加平台纹理
ctx.fillStyle = '#A0522D';
for (let i = 0; i < this.width; i += 15) {
ctx.fillRect(this.x + i, this.y, 8, 5);
}
// 绘制平台阴影
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(this.x, this.y + this.height, this.width, 5);
}
}
// 检查点类
class Checkpoint {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.activated = false;
}
draw() {
ctx.save();
if (this.activated) {
ctx.fillStyle = '#00FF00';
} else {
ctx.fillStyle = '#FFFF00';
}
ctx.fillRect(this.x, this.y, this.width, this.height);
// 绘制旗帜
ctx.fillStyle = '#FF0000';
ctx.beginPath();
ctx.moveTo(this.x + this.width/2, this.y);
ctx.lineTo(this.x + this.width/2, this.y - 20);
ctx.lineTo(this.x + this.width/2 + 15, this.y - 10);
ctx.closePath();
ctx.fill();
ctx.restore();
}
}
// 敌人类
class Enemy {
constructor(x, y, type, patrolRange = 100) {
this.x = x;
this.y = y;
this.type = type;
this.patrolRange = patrolRange;
this.startX = x;
this.startY = y;
this.dead = false;
this.particles = [];
if (type === 'walker') {
this.width = 36;
this.height = 36;
this.speed = 1.5;
this.color = '#FF5252';
this.direction = 1;
this.velocityX = this.speed * this.direction;
this.velocityY = 0;
this.health = 1;
} else if (type === 'jumper') {
this.width = 32;
this.height = 32;
this.speed = 1;
this.color = '#FF9800';
this.direction = 1;
this.velocityX = this.speed * this.direction;
this.velocityY = 0;
this.jumpTimer = 0;
this.health = 1;
} else if (type === 'chaser') {
this.width = 28;
this.height = 28;
this.speed = 2;
this.color = '#E91E63';
this.velocityX = 0;
this.velocityY = 0;
this.aggroRange = 150;
this.health = 1;
} else if (type === 'flyer') {
this.width = 30;
this.height = 30;
this.speed = 1.5;
this.color = '#9C27B0';
this.direction = 1;
this.velocityX = this.speed * this.direction;
this.velocityY = 0;
this.patrolRange = patrolRange;
this.health = 1;
} else if (type === 'shooter') {
this.width = 35;
this.height = 35;
this.speed = 1;
this.color = '#795548';
this.direction = 1;
this.velocityX = this.speed * this.direction;
this.velocityY = 0;
this.shootTimer = 0;
this.bullets = [];
this.health = 2;
} else if (type === 'boss') {
this.width = 80;
this.height = 80;
this.speed = 1;
this.color = '#D32F2F';
this.direction = 1;
this.velocityX = this.speed * this.direction;
this.velocityY = 0;
this.shootTimer = 0;
this.bullets = [];
this.health = 20;
this.maxHealth = 20;
this.attackPattern = 0;
this.attackTimer = 0;
}
}
update(platforms, players) {
if (this.dead || gamePaused) return;
if (this.type === 'walker') {
this.velocityX = this.speed * this.direction;
this.x += this.velocityX;
// 巡逻范围限制
if (this.x <= this.startX - this.patrolRange || this.x >= this.startX + this.patrolRange) {
this.direction *= -1;
}
// 平台边缘检测
let onPlatform = false;
for (let platform of platforms) {
if (this.x < platform.x + platform.width &&
this.x + this.width > platform.x &&
this.y + this.height > platform.y &&
this.y + this.height < platform.y + platform.height &&
this.velocityX * this.direction > 0) {
onPlatform = true;
}
}
if (!onPlatform) {
this.direction *= -1;
}
}
else if (this.type === 'jumper') {
this.velocityX = this.speed * this.direction;
this.x += this.velocityX;
// 巡逻范围限制
if (this.x <= this.startX - this.patrolRange || this.x >= this.startX + this.patrolRange) {
this.direction *= -1;
}
// 平台边缘检测
let onPlatform = false;
for (let platform of platforms) {
if (this.x < platform.x + platform.width &&
this.x + this.width > platform.x &&
this.y + this.height > platform.y &&
this.y + this.height < platform.y + platform.height &&
this.velocityX * this.direction > 0) {
onPlatform = true;
}
}
if (!onPlatform) {
this.direction *= -1;
}
// 跳跃逻辑
this.jumpTimer++;
if (this.jumpTimer > 120 && onPlatform) {
this.velocityY = -12;
this.jumpTimer = 0;
}
// 应用重力
this.velocityY += 0.5;
this.y += this.velocityY;
// 平台碰撞
for (let platform of platforms) {
if (this.x < platform.x + platform.width &&
this.x + this.width > platform.x &&
this.y + this.height > platform.y &&
this.y + this.height < platform.y + platform.height &&
this.velocityY > 0) {
this.y = platform.y - this.height;
this.velocityY = 0;
}
}
}
else if (this.type === 'chaser') {
// 追踪最近的玩家
let closestPlayer = null;
let minDistance = this.aggroRange;
for (let player of players) {
let distance = Math.sqrt(
Math.pow(this.x - player.x, 2) +
Math.pow(this.y - player.y, 2)
);
if (distance < minDistance) {
minDistance = distance;
closestPlayer = player;
}
}
if (closestPlayer) {
// 追踪逻辑
if (this.x < closestPlayer.x) {
this.velocityX = this.speed;
} else if (this.x > closestPlayer.x) {
this.velocityX = -this.speed;
}
if (this.y < closestPlayer.y) {
this.velocityY = this.speed;
} else if (this.y > closestPlayer.y) {
this.velocityY = -this.speed;
}
} else {
// 没有玩家在范围内,随机移动
this.velocityX *= 0.9;
this.velocityY *= 0.9;
}
// 限制速度
if (this.velocityX > this.speed) this.velocityX = this.speed;
if (this.velocityX < -this.speed) this.velocityX = -this.speed;
if (this.velocityY > this.speed) this.velocityY = this.speed;
if (this.velocityY < -this.speed) this.velocityY = -this.speed;
this.x += this.velocityX;
this.y += this.velocityY;
}
else if (this.type === 'flyer') {
// 飞行敌人,可以在空中移动
this.velocityX = this.speed * this.direction;
this.x += this.velocityX;
// 巡逻范围限制
if (this.x <= this.startX - this.patrolRange || this.x >= this.startX + this.patrolRange) {
this.direction *= -1;
}
// 上下浮动
this.y = this.startY + Math.sin(Date.now() / 500) * 20;
}
else if (this.type === 'shooter') {
// 射手敌人
this.velocityX = this.speed * this.direction;
this.x += this.velocityX;
// 巡逻范围限制
if (this.x <= this.startX - this.patrolRange || this.x >= this.startX + this.patrolRange) {
this.direction *= -1;
}
// 平台边缘检测
let onPlatform = false;
for (let platform of platforms) {
if (this.x < platform.x + platform.width &&
this.x + this.width > platform.x &&
this.y + this.height > platform.y &&
this.y + this.height < platform.y + platform.height &&
this.velocityX * this.direction > 0) {
onPlatform = true;
}
}
if (!onPlatform) {
this.direction *= -1;
}
// 射击逻辑
this.shootTimer++;
if (this.shootTimer > 180) { // 每3秒射击一次
let bulletX = this.direction > 0 ? this.x + this.width : this.x;
let bulletY = this.y + this.height / 2;
this.bullets.push(new Bullet(bulletX, bulletY, this.direction, '#795548'));
this.shootTimer = 0;
}
// 更新子弹
for (let i = this.bullets.length - 1; i >= 0; i--) {
this.bullets[i].update();
// 检查子弹是否超出屏幕
if (this.bullets[i].isOffScreen()) {
this.bullets.splice(i, 1);
} else {
// 检查子弹与玩家碰撞
for (let player of players) {
if (this.bullets[i].x < player.x + player.width &&
this.bullets[i].x + this.bullets[i].width > player.x &&
this.bullets[i].y < player.y + player.height &&
this.bullets[i].y + this.bullets[i].height > player.y) {
player.respawn();
player.lives--;
player.invincible = 120;
this.bullets.splice(i, 1);
if (player.lives <= 0) {
gameOver();
}
break;
}
}
}
}
}
else if (this.type === 'boss') {
// Boss敌人
this.velocityX = this.speed * this.direction;
this.x += this.velocityX;
// 边界检查
if (this.x <= 0 || this.x + this.width >= canvas.width) {
this.direction *= -1;
}
// 上下浮动
this.y = this.startY + Math.sin(Date.now() / 300) * 30;
// 攻击模式
this.attackTimer++;
if (this.attackTimer > 120) {
this.attackPattern = Math.floor(Math.random() * 3);
this.attackTimer = 0;
}
// 射击逻辑
this.shootTimer++;
if (this.shootTimer > 60) { // 每1秒射击一次
if (this.attackPattern === 0) {
// 单发子弹
let bulletX = this.direction > 0 ? this.x + this.width : this.x;
let bulletY = this.y + this.height / 2;
this.bullets.push(new Bullet(bulletX, bulletY, this.direction, '#D32F2F'));
} else if (this.attackPattern === 1) {
// 三发散射
for (let i = -1; i <= 1; i++) {
let bulletX = this.direction > 0 ? this.x + this.width : this.x;
let bulletY = this.y + this.height / 2 + i * 20;
this.bullets.push(new Bullet(bulletX, bulletY, this.direction, '#D32F2F'));
}
} else if (this.attackPattern === 2) {
// 五发散射
for (let i = -2; i <= 2; i++) {
let bulletX = this.direction > 0 ? this.x + this.width : this.x;
let bulletY = this.y + this.height / 2 + i * 15;
this.bullets.push(new Bullet(bulletX, bulletY, this.direction, '#D32F2F'));
}
}
this.shootTimer = 0;
}
// 更新子弹
for (let i = this.bullets.length - 1; i >= 0; i--) {
this.bullets[i].update();
// 检查子弹是否超出屏幕
if (this.bullets[i].isOffScreen()) {
this.bullets.splice(i, 1);
} else {
// 检查子弹与玩家碰撞
for (let player of players) {
if (this.bullets[i].x < player.x + player.width &&
this.bullets[i].x + this.bullets[i].width > player.x &&
this.bullets[i].y < player.y + player.height &&
this.bullets[i].y + this.bullets[i].height > player.y) {
player.respawn();
player.lives--;
player.invincible = 120;
this.bullets.splice(i, 1);
if (player.lives <= 0) {
gameOver();
}
break;
}
}
}
}
// 更新Boss血条
if (bossHealthBar.style.display !== 'block') {
bossHealthBar.style.display = 'block';
}
bossHealthFill.style.width = `${(this.health / this.maxHealth) * 100}%`;
}
// 边界检查
if (this.x < 0) this.x = 0;
if (this.x + this.width > canvas.width) this.x = canvas.width - this.width;
if (this.y < 0) this.y = 0;
if (this.y + this.height > canvas.height) this.y = canvas.height - this.height;
// 更新粒子
for (let i = this.particles.length - 1; i >= 0; i--) {
if (!this.particles[i].update()) {
this.particles.splice(i, 1);
}
}
}
draw() {
if (this.dead) return;
ctx.fillStyle = this.color;
if (this.type === 'walker') {
ctx.fillRect(this.x, this.y, this.width, this.height);
// 绘制眼睛
ctx.fillStyle = 'white';
ctx.fillRect(this.direction > 0 ? this.x + this.width - 15 : this.x + 5, this.y + 10, 8, 8);
}
else if (this.type === 'jumper') {
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width/2, 0, Math.PI * 2);
ctx.fill();
// 绘制眼睛
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(this.direction > 0 ? this.x + this.width - 10 : this.x + 10, this.y + 12, 4, 0, Math.PI * 2);
ctx.fill();
}
else if (this.type === 'chaser') {
ctx.beginPath();
ctx.moveTo(this.x + this.width/2, this.y);
ctx.lineTo(this.x + this.width, this.y + this.height);
ctx.lineTo(this.x, this.y + this.height);
ctx.closePath();
ctx.fill();
// 绘制眼睛
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + 12, 4, 0, Math.PI * 2);
ctx.fill();
}
else if (this.type === 'flyer') {
// 绘制飞行敌人(蝙蝠形状)
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width/2, 0, Math.PI * 2);
ctx.fill();
// 绘制翅膀
ctx.fillStyle = '#7B1FA2';
ctx.beginPath();
ctx.ellipse(this.x + this.width/2, this.y + this.height/2, this.width, this.height/3, 0, 0, Math.PI * 2);
ctx.fill();
// 绘制眼睛
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(this.direction > 0 ? this.x + this.width - 10 : this.x + 10, this.y + 12, 4, 0, Math.PI * 2);
ctx.fill();
}
else if (this.type === 'shooter') {
// 绘制射手敌人
ctx.fillRect(this.x, this.y, this.width, this.height);
// 绘制炮管
ctx.fillStyle = '#5D4037';
ctx.fillRect(this.direction > 0 ? this.x + this.width : this.x - 10, this.y + this.height/2 - 3, 10, 6);
// 绘制眼睛
ctx.fillStyle = 'white';
ctx.fillRect(this.direction > 0 ? this.x + this.width - 15 : this.x + 5, this.y + 10, 8, 8);
// 绘制子弹
for (let bullet of this.bullets) {
bullet.draw();
}
}
else if (this.type === 'boss') {
// 绘制Boss敌人
ctx.fillRect(this.x, this.y, this.width, this.height);
// 绘制装饰
ctx.fillStyle = '#B71C1C';
ctx.fillRect(this.x + 10, this.y + 10, this.width - 20, 10);
ctx.fillRect(this.x + 10, this.y + this.height - 20, this.width - 20, 10);
// 绘制眼睛
ctx.fillStyle = 'white';
ctx.fillRect(this.x + 20, this.y + 25, 15, 15);
ctx.fillRect(this.x + this.width - 35, this.y + 25, 15, 15);
// 绘制嘴巴
ctx.fillStyle = 'white';
ctx.fillRect(this.x + 30, this.y + 50, this.width - 60, 10);
// 绘制子弹
for (let bullet of this.bullets) {
bullet.draw();
}
}
// 绘制粒子
for (let particle of this.particles) {
particle.draw();
}
}
hitByBullet(bulletType) {
// 激光子弹造成双倍伤害
const damage = bulletType === 'laser' ? 2 : bulletType === 'ability' ? 3 : 1;
this.health -= damage;
// 显示伤害数字
createDamagePopup(this.x + this.width/2, this.y, damage);
// 添加粒子效果
for (let i = 0; i < 5; i++) {
this.particles.push(new Particle(
this.x + this.width/2,
this.y + this.height/2,
this.color,
Math.random() * 3 + 1,
(Math.random() - 0.5) * 3,
(Math.random() - 0.5) * 3,
Math.random() * 20 + 10
));
}
if (this.health <= 0) {
this.dead = true;
gameStats.killedEnemies++;
// 增加分数和连击
addScore(this.type === 'boss' ? 500 : 100);
addCombo();
// 添加更多粒子效果
for (let i = 0; i < 15; i++) {
this.particles.push(new Particle(
this.x + this.width/2,
this.y + this.height/2,
this.color,
Math.random() * 4 + 2,
(Math.random() - 0.5) * 5,
(Math.random() - 0.5) * 5,
Math.random() * 30 + 20
));
}
// 如果是Boss,隐藏血条
if (this.type === 'boss') {
bossHealthBar.style.display = 'none';
}
}
}
}
// 金币类
class Coin {
constructor(x, y) {
this.x = x;
this.y = y;
this.width = 15;
this.height = 15;
this.color = '#FFD700';
this.animation = 0;
}
update() {
this.animation += 0.1;
}
draw() {
ctx.save();
ctx.translate(this.x + this.width/2, this.y + this.height/2);
ctx.rotate(this.animation);
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(0, 0, this.width/2, 0, Math.PI * 2);
ctx.fill();
// 添加光泽效果
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.beginPath();
ctx.arc(-3, -3, 3, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
// 危险物品类
class Hazard {
constructor(x, y, width, height, type = 'spike') {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
this.color = type === 'spike' ? '#FF0000' : '#FF9800';
this.animation = 0;
}
update() {
this.animation += 0.05;
}
draw() {
ctx.fillStyle = this.color;
if (this.type === 'spike') {
// 绘制尖刺
ctx.beginPath();
ctx.moveTo(this.x, this.y + this.height);
ctx.lineTo(this.x + this.width/2, this.y);
ctx.lineTo(this.x + this.width, this.y + this.height);
ctx.closePath();
ctx.fill();
} else if (this.type === 'fire') {
// 绘制火焰
const pulse = 0.5 + 0.5 * Math.sin(this.animation * 3);
const size = this.width/2 * (0.8 + 0.2 * pulse);
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, size, 0, Math.PI * 2);
ctx.fill();
// 火焰效果
ctx.fillStyle = 'orange';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, size * 0.6, 0, Math.PI * 2);
ctx.fill();
}
}
}
// 终点类
class Goal {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = '#00FF00';
this.pulse = 0;
}
update() {
this.pulse += 0.05;
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
// 添加脉冲效果
ctx.strokeStyle = `rgba(0, 255, 0, ${0.5 + 0.5 * Math.sin(this.pulse)})`;
ctx.lineWidth = 3;
ctx.strokeRect(this.x - 5, this.y - 5, this.width + 10, this.height + 10);
// 添加旗帜
ctx.fillStyle = '#FF0000';
ctx.beginPath();
ctx.moveTo(this.x + this.width/2, this.y);
ctx.lineTo(this.x + this.width/2, this.y - 30);
ctx.lineTo(this.x + this.width/2 + 20, this.y - 15);
ctx.closePath();
ctx.fill();
}
checkCollision(player) {
return (player.x < this.x + this.width &&
player.x + player.width > this.x &&
player.y < this.y + this.height &&
player.y + player.height > this.y);
}
}
// 游戏对象
let player1, player2, platforms, enemies, coins, hazards, goal, powerUps, checkpoints;
// 关卡配置 - 优化后的10个关卡
const levelConfigs = [
// 关卡1:基础关卡 - 简单敌人和平台
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 200, height: 20},
{x: 400, y: 350, width: 150, height: 20},
{x: 600, y: 300, width: 100, height: 20},
{x: 200, y: 250, width: 150, height: 20},
{x: 500, y: 200, width: 200, height: 20}
],
enemies: [
{x: 300, y: 380, type: 'walker', patrolRange: 100},
{x: 500, y: 330, type: 'walker', patrolRange: 80},
{x: 400, y: 230, type: 'flyer', patrolRange: 150}
],
coins: [
{x: 150, y: 370},
{x: 450, y: 320},
{x: 250, y: 220}
],
hazards: [],
powerUps: [
{x: 350, y: 330, type: 'score'}
],
checkpoints: [
{x: 300, y: 430, width: 50, height: 30}
],
goal: {x: 650, y: 150, width: 50, height: 50}
},
// 关卡2:添加跳跃敌人 - 中等难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 150, height: 20},
{x: 300, y: 350, width: 150, height: 20},
{x: 500, y: 300, width: 150, height: 20},
{x: 200, y: 250, width: 150, height: 20},
{x: 400, y: 200, width: 150, height: 20},
{x: 600, y: 150, width: 150, height: 20}
],
enemies: [
{x: 200, y: 380, type: 'jumper', patrolRange: 80},
{x: 400, y: 330, type: 'walker', patrolRange: 80},
{x: 550, y: 280, type: 'jumper', patrolRange: 80},
{x: 450, y: 180, type: 'flyer', patrolRange: 100}
],
coins: [
{x: 150, y: 370},
{x: 350, y: 320},
{x: 550, y: 270},
{x: 250, y: 220},
{x: 450, y: 170}
],
hazards: [],
powerUps: [
{x: 400, y: 350, type: 'health'},
{x: 200, y: 230, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 650, y: 100, width: 50, height: 50}
},
// 关卡3:添加追踪敌人 - 增加难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 100, height: 20},
{x: 250, y: 350, width: 100, height: 20},
{x: 400, y: 300, width: 100, height: 20},
{x: 550, y: 250, width: 100, height: 20},
{x: 400, y: 200, width: 100, height: 20},
{x: 250, y: 150, width: 100, height: 20},
{x: 100, y: 100, width: 100, height: 20}
],
enemies: [
{x: 200, y: 380, type: 'chaser'},
{x: 350, y: 330, type: 'jumper', patrolRange: 60},
{x: 500, y: 280, type: 'chaser'},
{x: 350, y: 130, type: 'flyer', patrolRange: 120}
],
coins: [
{x: 140, y: 370},
{x: 290, y: 320},
{x: 440, y: 270},
{x: 440, y: 170},
{x: 290, y: 120}
],
hazards: [],
powerUps: [
{x: 550, y: 230, type: 'laser'},
{x: 100, y: 380, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 120, y: 50, width: 50, height: 50}
},
// 关卡4:移动平台和更多敌人 - 中等难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 100, height: 20, moving: true, moveRange: 100, moveSpeed: 1},
{x: 350, y: 350, width: 100, height: 20, moving: true, moveRange: 80, moveSpeed: 1.5},
{x: 600, y: 300, width: 100, height: 20},
{x: 200, y: 250, width: 150, height: 20, moving: true, moveRange: 120, moveSpeed: 1},
{x: 450, y: 200, width: 150, height: 20},
{x: 100, y: 150, width: 100, height: 20, moving: true, moveRange: 150, moveSpeed: 1}
],
enemies: [
{x: 150, y: 380, type: 'walker', patrolRange: 80},
{x: 380, y: 330, type: 'jumper', patrolRange: 60},
{x: 620, y: 280, type: 'chaser'},
{x: 250, y: 230, type: 'flyer', patrolRange: 100},
{x: 500, y: 180, type: 'walker', patrolRange: 80}
],
coins: [
{x: 150, y: 370},
{x: 380, y: 320},
{x: 620, y: 270},
{x: 250, y: 220},
{x: 500, y: 170},
{x: 150, y: 120}
],
hazards: [
{x: 300, y: 430, width: 40, height: 30, type: 'spike'},
{x: 500, y: 430, width: 40, height: 30, type: 'spike'}
],
powerUps: [
{x: 600, y: 280, type: 'shield'},
{x: 200, y: 230, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 650, y: 100, width: 50, height: 50}
},
// 关卡5:垂直移动平台 - 高难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 100, height: 20},
{x: 250, y: 350, width: 100, height: 20, moving: true, moveRange: 80, moveSpeed: 1, vertical: true},
{x: 400, y: 300, width: 100, height: 20},
{x: 550, y: 250, width: 100, height: 20, moving: true, moveRange: 100, moveSpeed: 1.5, vertical: true},
{x: 700, y: 200, width: 80, height: 20},
{x: 550, y: 150, width: 100, height: 20},
{x: 400, y: 100, width: 100, height: 20, moving: true, moveRange: 60, moveSpeed: 1, vertical: true}
],
enemies: [
{x: 120, y: 380, type: 'chaser'},
{x: 270, y: 330, type: 'flyer', patrolRange: 120},
{x: 420, y: 280, type: 'jumper', patrolRange: 60},
{x: 570, y: 230, type: 'walker', patrolRange: 80},
{x: 720, y: 180, type: 'chaser'},
{x: 570, y: 130, type: 'flyer', patrolRange: 100}
],
coins: [
{x: 140, y: 370},
{x: 290, y: 320},
{x: 440, y: 270},
{x: 590, y: 220},
{x: 740, y: 170},
{x: 590, y: 120},
{x: 440, y: 70}
],
hazards: [
{x: 200, y: 430, width: 40, height: 30, type: 'fire'},
{x: 400, y: 430, width: 40, height: 30, type: 'fire'},
{x: 600, y: 430, width: 40, height: 30, type: 'fire'}
],
powerUps: [
{x: 700, y: 180, type: 'laser'},
{x: 100, y: 380, type: 'health'},
{x: 400, y: 280, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 420, y: 50, width: 50, height: 50}
},
// 关卡6:复杂平台布局 - 高难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 50, y: 400, width: 80, height: 20},
{x: 180, y: 350, width: 80, height: 20},
{x: 300, y: 300, width: 80, height: 20},
{x: 450, y: 250, width: 80, height: 20},
{x: 600, y: 200, width: 80, height: 20},
{x: 700, y: 150, width: 80, height: 20},
{x: 600, y: 100, width: 80, height: 20},
{x: 450, y: 150, width: 80, height: 20},
{x: 300, y: 200, width: 80, height: 20},
{x: 180, y: 250, width: 80, height: 20},
{x: 50, y: 300, width: 80, height: 20}
],
enemies: [
{x: 80, y: 380, type: 'walker', patrolRange: 50},
{x: 210, y: 330, type: 'jumper', patrolRange: 50},
{x: 330, y: 280, type: 'chaser'},
{x: 480, y: 230, type: 'flyer', patrolRange: 80},
{x: 630, y: 180, type: 'walker', patrolRange: 50},
{x: 730, y: 130, type: 'jumper', patrolRange: 50},
{x: 630, y: 80, type: 'chaser'},
{x: 480, y: 130, type: 'flyer', patrolRange: 80}
],
coins: [
{x: 80, y: 370},
{x: 210, y: 320},
{x: 330, y: 270},
{x: 480, y: 220},
{x: 630, y: 170},
{x: 730, y: 120},
{x: 630, y: 70},
{x: 480, y: 120},
{x: 330, y: 170},
{x: 210, y: 220},
{x: 80, y: 270}
],
hazards: [
{x: 150, y: 430, width: 40, height: 30, type: 'spike'},
{x: 350, y: 430, width: 40, height: 30, type: 'spike'},
{x: 550, y: 430, width: 40, height: 30, type: 'spike'},
{x: 750, y: 430, width: 40, height: 30, type: 'spike'}
],
powerUps: [
{x: 300, y: 280, type: 'shield'},
{x: 450, y: 130, type: 'health'},
{x: 150, y: 370, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 50, y: 250, width: 50, height: 50}
},
// 关卡7:危险重重 - 高难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 100, height: 20, moving: true, moveRange: 150, moveSpeed: 2},
{x: 300, y: 350, width: 100, height: 20},
{x: 500, y: 300, width: 100, height: 20, moving: true, moveRange: 120, moveSpeed: 1.5},
{x: 200, y: 250, width: 100, height: 20},
{x: 400, y: 200, width: 100, height: 20, moving: true, moveRange: 100, moveSpeed: 2},
{x: 600, y: 150, width: 100, height: 20},
{x: 300, y: 100, width: 100, height: 20, moving: true, moveRange: 80, moveSpeed: 1}
],
enemies: [
{x: 150, y: 380, type: 'chaser'},
{x: 330, y: 330, type: 'flyer', patrolRange: 120},
{x: 530, y: 280, type: 'chaser'},
{x: 230, y: 230, type: 'jumper', patrolRange: 60},
{x: 430, y: 180, type: 'flyer', patrolRange: 100},
{x: 630, y: 130, type: 'chaser'},
{x: 330, y: 80, type: 'walker', patrolRange: 70}
],
coins: [
{x: 150, y: 370},
{x: 330, y: 320},
{x: 530, y: 270},
{x: 230, y: 220},
{x: 430, y: 170},
{x: 630, y: 120},
{x: 330, y: 70}
],
hazards: [
{x: 50, y: 430, width: 40, height: 30, type: 'fire'},
{x: 150, y: 430, width: 40, height: 30, type: 'fire'},
{x: 250, y: 430, width: 40, height: 30, type: 'fire'},
{x: 350, y: 430, width: 40, height: 30, type: 'fire'},
{x: 450, y: 430, width: 40, height: 30, type: 'fire'},
{x: 550, y: 430, width: 40, height: 30, type: 'fire'},
{x: 650, y: 430, width: 40, height: 30, type: 'fire'},
{x: 750, y: 430, width: 40, height: 30, type: 'fire'}
],
powerUps: [
{x: 500, y: 280, type: 'laser'},
{x: 200, y: 230, type: 'shield'},
{x: 600, y: 130, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 650, y: 50, width: 50, height: 50}
},
// 关卡8:最终关卡 - 非常高难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 80, height: 20, moving: true, moveRange: 100, moveSpeed: 1.5},
{x: 250, y: 350, width: 80, height: 20, moving: true, moveRange: 80, moveSpeed: 2, vertical: true},
{x: 400, y: 300, width: 80, height: 20},
{x: 550, y: 250, width: 80, height: 20, moving: true, moveRange: 120, moveSpeed: 1.5},
{x: 700, y: 200, width: 80, height: 20},
{x: 550, y: 150, width: 80, height: 20, moving: true, moveRange: 100, moveSpeed: 2, vertical: true},
{x: 400, y: 100, width: 80, height: 20},
{x: 250, y: 150, width: 80, height: 20, moving: true, moveRange: 80, moveSpeed: 1.5},
{x: 100, y: 200, width: 80, height: 20}
],
enemies: [
{x: 140, y: 380, type: 'chaser'},
{x: 290, y: 330, type: 'flyer', patrolRange: 100},
{x: 440, y: 280, type: 'jumper', patrolRange: 60},
{x: 590, y: 230, type: 'chaser'},
{x: 740, y: 180, type: 'flyer', patrolRange: 80},
{x: 590, y: 130, type: 'jumper', patrolRange: 60},
{x: 440, y: 80, type: 'chaser'},
{x: 290, y: 130, type: 'flyer', patrolRange: 100},
{x: 140, y: 180, type: 'jumper', patrolRange: 60}
],
coins: [
{x: 140, y: 370},
{x: 290, y: 320},
{x: 440, y: 270},
{x: 590, y: 220},
{x: 740, y: 170},
{x: 590, y: 120},
{x: 440, y: 70},
{x: 290, y: 120},
{x: 140, y: 170}
],
hazards: [
{x: 50, y: 430, width: 40, height: 30, type: 'spike'},
{x: 150, y: 430, width: 40, height: 30, type: 'spike'},
{x: 250, y: 430, width: 40, height: 30, type: 'spike'},
{x: 350, y: 430, width: 40, height: 30, type: 'spike'},
{x: 450, y: 430, width: 40, height: 30, type: 'spike'},
{x: 550, y: 430, width: 40, height: 30, type: 'spike'},
{x: 650, y: 430, width: 40, height: 30, type: 'spike'},
{x: 750, y: 430, width: 40, height: 30, type: 'spike'},
{x: 200, y: 200, width: 40, height: 30, type: 'fire'},
{x: 400, y: 200, width: 40, height: 30, type: 'fire'},
{x: 600, y: 200, width: 40, height: 30, type: 'fire'}
],
powerUps: [
{x: 400, y: 280, type: 'laser'},
{x: 100, y: 380, type: 'shield'},
{x: 700, y: 180, type: 'health'},
{x: 400, y: 80, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 400, y: 30, width: 50, height: 50}
},
// 关卡9:Boss前哨站 - 非常高难度
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 100, y: 400, width: 120, height: 20},
{x: 300, y: 350, width: 120, height: 20},
{x: 500, y: 300, width: 120, height: 20},
{x: 200, y: 250, width: 120, height: 20},
{x: 400, y: 200, width: 120, height: 20},
{x: 600, y: 150, width: 120, height: 20},
{x: 350, y: 100, width: 120, height: 20}
],
enemies: [
{x: 130, y: 380, type: 'shooter', patrolRange: 60},
{x: 330, y: 330, type: 'shooter', patrolRange: 60},
{x: 530, y: 280, type: 'shooter', patrolRange: 60},
{x: 230, y: 230, type: 'shooter', patrolRange: 60},
{x: 430, y: 180, type: 'shooter', patrolRange: 60},
{x: 630, y: 130, type: 'shooter', patrolRange: 60},
{x: 380, y: 80, type: 'shooter', patrolRange: 60}
],
coins: [
{x: 150, y: 370},
{x: 350, y: 320},
{x: 550, y: 270},
{x: 250, y: 220},
{x: 450, y: 170},
{x: 650, y: 120},
{x: 400, y: 70}
],
hazards: [
{x: 50, y: 430, width: 40, height: 30, type: 'spike'},
{x: 250, y: 430, width: 40, height: 30, type: 'spike'},
{x: 450, y: 430, width: 40, height: 30, type: 'spike'},
{x: 650, y: 430, width: 40, height: 30, type: 'spike'},
{x: 150, y: 200, width: 40, height: 30, type: 'fire'},
{x: 350, y: 200, width: 40, height: 30, type: 'fire'},
{x: 550, y: 200, width: 40, height: 30, type: 'fire'}
],
powerUps: [
{x: 100, y: 380, type: 'laser'},
{x: 700, y: 130, type: 'shield'},
{x: 400, y: 80, type: 'health'},
{x: 500, y: 280, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 400, y: 30, width: 50, height: 50}
},
// 关卡10:Boss战 - 终极挑战
{
platforms: [
{x: 0, y: 460, width: 800, height: 40},
{x: 300, y: 350, width: 200, height: 20},
{x: 200, y: 250, width: 100, height: 20},
{x: 500, y: 250, width: 100, height: 20},
{x: 100, y: 150, width: 80, height: 20},
{x: 620, y: 150, width: 80, height: 20}
],
enemies: [
{x: 360, y: 280, type: 'boss'}
],
coins: [
{x: 250, y: 340},
{x: 550, y: 340},
{x: 150, y: 240},
{x: 650, y: 240},
{x: 50, y: 140},
{x: 750, y: 140}
],
hazards: [
{x: 0, y: 430, width: 100, height: 30, type: 'fire'},
{x: 700, y: 430, width: 100, height: 30, type: 'fire'},
{x: 200, y: 430, width: 100, height: 30, type: 'spike'},
{x: 500, y: 430, width: 100, height: 30, type: 'spike'}
],
powerUps: [
{x: 100, y: 350, type: 'health'},
{x: 700, y: 350, type: 'health'},
{x: 400, y: 150, type: 'laser'},
{x: 300, y: 330, type: 'score'}
],
checkpoints: [
{x: 400, y: 430, width: 50, height: 30}
],
goal: {x: 400, y: 30, width: 50, height: 50}
}
];
// 初始化关卡
function initLevel(level) {
platforms = [];
enemies = [];
coins = [];
hazards = [];
powerUps = [];
checkpoints = [];
const config = levelConfigs[level - 1] || levelConfigs[0];
// 创建平台
for (let platformConfig of config.platforms) {
platforms.push(new Platform(
platformConfig.x,
platformConfig.y,
platformConfig.width,
platformConfig.height,
platformConfig.color,
platformConfig.moving,
platformConfig.moveRange,
platformConfig.moveSpeed,
platformConfig.vertical
));
}
// 创建敌人
for (let enemyConfig of config.enemies) {
enemies.push(new Enemy(
enemyConfig.x,
enemyConfig.y,
enemyConfig.type,
enemyConfig.patrolRange
));
// 设置Boss名称
if (enemyConfig.type === 'boss') {
bossName.textContent = '最终Boss';
}
}
// 创建金币
for (let coinConfig of config.coins) {
coins.push(new Coin(coinConfig.x, coinConfig.y));
}
// 创建危险物品
for (let hazardConfig of config.hazards) {
hazards.push(new Hazard(
hazardConfig.x,
hazardConfig.y,
hazardConfig.width,
hazardConfig.height,
hazardConfig.type
));
}
// 创建道具
for (let powerUpConfig of config.powerUps) {
powerUps.push(new PowerUp(
powerUpConfig.x,
powerUpConfig.y,
powerUpConfig.type
));
}
// 创建检查点
for (let checkpointConfig of config.checkpoints) {
checkpoints.push(new Checkpoint(
checkpointConfig.x,
checkpointConfig.y,
checkpointConfig.width,
checkpointConfig.height
));
}
// 创建终点
goal = new Goal(config.goal.x, config.goal.y, config.goal.width, config.goal.height);
// 初始化玩家
player1 = new Player(50, 300, '#3498db',
{left: 'a', right: 'd', up: 'w', skill: 's', ability: 'q'},
'shoot');
player2 = new Player(100, 300, '#e74c3c',
{left: 'g', right: 'l', up: 'i', skill: 'o', ability: 'p'},
'shoot');
// 重置游戏统计
gameStats = {
collectedCoins: 0,
killedEnemies: 0,
remainingLives: player1.lives + player2.lives
};
// 重置检查点
checkpoint.active = false;
}
// 绘制背景
function drawBackground() {
// 绘制天空渐变
const skyGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
skyGradient.addColorStop(0, '#87CEEB');
skyGradient.addColorStop(1, '#1E90FF');
ctx.fillStyle = skyGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制云朵
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
drawCloud(100, 80, 1);
drawCloud(600, 120, 1.2);
drawCloud(300, 60, 0.8);
// 绘制远处山脉
ctx.fillStyle = 'rgba(0, 100, 0, 0.3)';
ctx.beginPath();
ctx.moveTo(0, canvas.height - 100);
ctx.lineTo(150, canvas.height - 150);
ctx.lineTo(300, canvas.height - 120);
ctx.lineTo(450, canvas.height - 180);
ctx.lineTo(600, canvas.height - 140);
ctx.lineTo(800, canvas.height - 100);
ctx.lineTo(800, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.fill();
// 绘制太阳
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(700, 70, 30, 0, Math.PI * 2);
ctx.fill();
// 绘制太阳光芒
ctx.strokeStyle = 'rgba(255, 215, 0, 0.5)';
ctx.lineWidth = 3;
for (let i = 0; i < 12; i++) {
ctx.save();
ctx.translate(700, 70);
ctx.rotate(i * Math.PI / 6);
ctx.beginPath();
ctx.moveTo(35, 0);
ctx.lineTo(50, 0);
ctx.stroke();
ctx.restore();
}
}
// 绘制云朵
function drawCloud(x, y, scale) {
ctx.save();
ctx.translate(x, y);
ctx.scale(scale, scale);
ctx.beginPath();
ctx.arc(0, 0, 20, 0, Math.PI * 2);
ctx.arc(20, -10, 25, 0, Math.PI * 2);
ctx.arc(40, 0, 20, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
// 更新道具显示
function updatePowerUpDisplay() {
// 显示玩家1的道具状态
laserTimerElement.textContent = Math.ceil(player1.powerUps.laser / 60);
shieldCountElement.textContent = player1.powerUps.shield;
}
// 增加分数
function addScore(points) {
score += points;
scoreValue.textContent = score;
}
// 游戏循环
function gameLoop() {
if (!gameRunning || gamePaused) return;
// 清除画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制背景
drawBackground();
// 更新游戏对象
for (let platform of platforms) {
platform.update();
}
player1.update(platforms, enemies, coins, hazards, powerUps, checkpoints);
player2.update(platforms, enemies, coins, hazards, powerUps, checkpoints);
for (let enemy of enemies) {
enemy.update(platforms, [player1, player2]);
// 检查玩家子弹与敌人碰撞
for (let player of [player1, player2]) {
for (let i = player.bullets.length - 1; i >= 0; i--) {
let bullet = player.bullets[i];
if (!enemy.dead &&
bullet.x < enemy.x + enemy.width &&
bullet.x + bullet.width > enemy.x &&
bullet.y < enemy.y + enemy.height &&
bullet.y + bullet.height > enemy.y) {
enemy.hitByBullet(bullet.type);
player.bullets.splice(i, 1);
break;
}
}
}
}
for (let coin of coins) {
coin.update();
}
for (let hazard of hazards) {
hazard.update();
}
for (let powerUp of powerUps) {
powerUp.update();
}
goal.update();
// 更新伤害数字
updateDamagePopups();
// 绘制游戏对象
for (let platform of platforms) {
platform.draw();
}
for (let hazard of hazards) {
hazard.draw();
}
for (let powerUp of powerUps) {
powerUp.draw();
}
for (let coin of coins) {
coin.draw();
}
for (let checkpoint of checkpoints) {
checkpoint.draw();
}
for (let enemy of enemies) {
enemy.draw();
}
goal.draw();
player1.draw();
player2.draw();
// 绘制伤害数字
drawDamagePopups();
// 更新道具显示
updatePowerUpDisplay();
// 检查关卡完成条件
if (goal.checkCollision(player1) && goal.checkCollision(player2)) {
levelComplete();
}
// 更新UI
if (player1LivesElement) player1LivesElement.textContent = player1.lives;
if (player2LivesElement) player2LivesElement.textContent = player2.lives;
if (currentLevelElement) currentLevelElement.textContent = currentLevel;
// 更新技能指示器
if (player1SkillElement) {
player1SkillElement.className = player1.skillCooldown > 0 ? 'skill-indicator cooldown' : 'skill-indicator';
}
if (player2SkillElement) {
player2SkillElement.className = player2.skillCooldown > 0 ? 'skill-indicator cooldown' : 'skill-indicator';
}
// 更新技能文本
if (player1SkillTextElement) {
player1SkillTextElement.textContent = player1.skillCooldown > 0 ? '冷却' : '可用';
}
if (player2SkillTextElement) {
player2SkillTextElement.textContent = player2.skillCooldown > 0 ? '冷却' : '可用';
}
// 继续游戏循环
requestAnimationFrame(gameLoop);
}
// 关卡完成
function levelComplete() {
gameRunning = false;
// 更新游戏统计
gameStats.remainingLives = player1.lives + player2.lives;
collectedCoinsElement.textContent = gameStats.collectedCoins;
killedEnemiesElement.textContent = gameStats.killedEnemies;
remainingLivesElement.textContent = gameStats.remainingLives;
maxComboElement.textContent = maxCombo;
levelScoreElement.textContent = score;
levelCompleteScreen.style.display = 'block';
}
// 游戏结束
function gameOver() {
gameRunning = false;
alert('游戏结束!你们失败了。');
startScreen.style.display = 'flex';
}
// 开始游戏
function startGame() {
announcementScreen.style.display = 'none';
startScreen.style.display = 'flex';
}
// 继续游戏
function continueGame() {
startScreen.style.display = 'none';
levelCompleteScreen.style.display = 'none';
pauseScreen.style.display = 'none';
currentLevel = 1;
score = 0;
scoreValue.textContent = score;
initLevel(currentLevel);
gameRunning = true;
gamePaused = false;
requestAnimationFrame(gameLoop);
}
// 下一关
function nextLevel() {
currentLevel++;
if (currentLevel > totalLevels) {
alert('恭喜!你们完成了所有关卡!');
startScreen.style.display = 'flex';
return;
}
levelCompleteScreen.style.display = 'none';
initLevel(currentLevel);
gameRunning = true;
gamePaused = false;
requestAnimationFrame(gameLoop);
}
// 暂停游戏
function togglePause() {
gamePaused = !gamePaused;
if (gamePaused) {
pauseScreen.style.display = 'flex';
} else {
pauseScreen.style.display = 'none';
if (gameRunning) {
requestAnimationFrame(gameLoop);
}
}
}
// 重新开始当前关卡
function restartLevel() {
pauseScreen.style.display = 'none';
initLevel(currentLevel);
gameRunning = true;
gamePaused = false;
requestAnimationFrame(gameLoop);
}
// 返回主菜单
function returnToMenu() {
pauseScreen.style.display = 'none';
startScreen.style.display = 'flex';
gameRunning = false;
}
// 事件监听
continueBtn.addEventListener('click', startGame);
startBtn.addEventListener('click', continueGame);
nextLevelBtn.addEventListener('click', nextLevel);
resumeBtn.addEventListener('click', () => togglePause());
restartBtn.addEventListener('click', restartLevel);
menuBtn.addEventListener('click', returnToMenu);
// 初始化游戏
initLevel(1);
</script>
</body>
</html>
index.html
style.css
index.js
index.html