<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>董测浩解救许子昂 - 手机冒险游戏</title>
<style>
/* 所有样式保持不变(与之前相同) */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
overflow: hidden;
padding: 10px;
width: 100%;
height: 100%;
touch-action: none;
}
#gameContainer {
position: relative;
width: 100%;
max-width: 768px;
height: 100vh;
max-height: 100vh;
box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5);
border-radius: 10px;
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%;
height: 70%;
background: linear-gradient(to bottom, #87CEEB, #1E90FF);
}
/* 移动端控制按钮 */
#mobileControls {
position: absolute;
bottom: 20px;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 20px;
z-index: 100;
pointer-events: none;
}
.control-group {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
pointer-events: auto;
}
.direction-controls {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 8px;
}
.action-controls {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 8px;
}
.control-btn {
width: 60px;
height: 60px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.7);
border: 2px solid rgba(255, 255, 255, 0.3);
color: white;
font-size: 1.2rem;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
-webkit-user-select: none;
backdrop-filter: blur(5px);
transition: all 0.1s;
touch-action: manipulation;
}
.control-btn:active {
transform: scale(0.9);
background: rgba(0, 0, 0, 0.9);
border-color: rgba(255, 255, 255, 0.6);
}
.control-btn.move-btn {
background: rgba(52, 152, 219, 0.8);
}
.control-btn.jump-btn {
background: rgba(46, 204, 113, 0.8);
grid-column: 2;
grid-row: 1;
}
.control-btn.shoot-btn {
background: rgba(231, 76, 60, 0.8);
}
.control-btn.skill-btn {
background: rgba(241, 196, 15, 0.8);
}
.control-btn.ability-btn {
background: rgba(155, 89, 182, 0.8);
}
.control-btn.pause-btn {
background: rgba(52, 73, 94, 0.8);
width: 50px;
height: 50px;
font-size: 1rem;
}
.control-btn.long-btn {
width: 140px;
border-radius: 30px;
font-size: 1rem;
}
/* 顶部玩家信息栏 */
#topBar {
display: flex;
justify-content: space-between;
padding: 10px 15px;
background: rgba(0, 0, 0, 0.85);
color: white;
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: 25;
}
.player-status {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.player-info {
display: flex;
align-items: center;
gap: 6px;
background: rgba(255, 255, 255, 0.1);
padding: 6px 10px;
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.2);
font-size: 0.9rem;
}
.player-icon {
width: 28px;
height: 28px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
font-size: 0.9rem;
background: linear-gradient(135deg, #3498db, #2980b9);
}
.skill-status {
display: flex;
align-items: center;
gap: 4px;
font-size: 0.8rem;
}
.skill-indicator {
width: 10px;
height: 10px;
border-radius: 50%;
background: #2ecc71;
}
.skill-indicator.cooldown {
background: #e74c3c;
}
.level-info {
display: flex;
align-items: center;
gap: 8px;
background: rgba(255, 255, 255, 0.1);
padding: 6px 12px;
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.2);
font-size: 0.9rem;
}
/* 游戏开始界面 */
#startScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 30;
padding: 20px;
text-align: center;
}
#gameTitle {
margin-bottom: 20px;
text-align: center;
}
h1 {
font-size: 2.2rem;
margin-bottom: 10px;
color: #FFD700;
text-shadow: 2px 2px 0 #FF5722, 3px 3px 0 rgba(0, 0, 0, 0.2);
letter-spacing: 1px;
font-weight: 800;
}
h2 {
font-size: 1.3rem;
color: #4FC3F7;
text-shadow: 1px 1px 0 #0288D1;
font-weight: 600;
}
.game-description {
max-width: 90%;
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 15px;
margin: 15px 0 20px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
line-height: 1.5;
font-size: 1rem;
}
.mobile-controls-info {
display: flex;
flex-direction: column;
gap: 15px;
margin: 15px 0 25px;
width: 90%;
}
.mobile-control-set {
background: rgba(255, 255, 255, 0.1);
padding: 15px;
border-radius: 15px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
.control-title {
font-size: 1.1rem;
margin-bottom: 10px;
color: #FFD700;
font-weight: 600;
}
.mobile-control-row {
display: flex;
align-items: center;
gap: 10px;
margin: 8px 0;
}
.mobile-btn-demo {
width: 50px;
height: 50px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 1rem;
border: 2px solid rgba(255, 255, 255, 0.3);
}
.mobile-btn-demo.move {
background: rgba(52, 152, 219, 0.8);
}
.mobile-btn-demo.jump {
background: rgba(46, 204, 113, 0.8);
}
.mobile-btn-demo.shoot {
background: rgba(231, 76, 60, 0.8);
}
.mobile-btn-demo.skill {
background: rgba(241, 196, 15, 0.8);
}
button {
background: linear-gradient(to bottom, #FF5722, #E64A19);
border: none;
color: white;
padding: 14px 35px;
border-radius: 50px;
cursor: pointer;
font-size: 1.2rem;
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;
min-height: 50px;
min-width: 200px;
}
button:hover {
background: linear-gradient(to bottom, #FF7043, #F4511E);
transform: translateY(-3px);
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.4);
}
button:active {
transform: translateY(-1px);
}
/* 公告屏幕 */
#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: 35;
padding: 20px;
text-align: center;
}
#announcementContent {
max-width: 90%;
background: rgba(255, 255, 255, 0.1);
padding: 25px;
border-radius: 20px;
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.2);
margin-bottom: 20px;
}
#announcementContent h2 {
font-size: 1.8rem;
margin-bottom: 15px;
color: #FFD700;
}
#announcementContent p {
margin: 10px 0;
line-height: 1.6;
font-size: 1rem;
}
.copyright {
margin-top: 20px;
color: rgba(255, 255, 255, 0.7);
font-size: 0.9rem;
}
/* 游戏UI */
#ui {
position: absolute;
top: 70px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
color: white;
font-size: 1rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
z-index: 10;
}
#levelComplete {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.95);
color: white;
padding: 25px 35px;
border-radius: 20px;
text-align: center;
display: none;
z-index: 25;
backdrop-filter: blur(10px);
border: 3px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 0 40px rgba(0, 0, 0, 0.7);
width: 90%;
max-width: 500px;
}
#levelComplete h2 {
font-size: 2rem;
margin-bottom: 15px;
color: #FFD700;
text-shadow: 2px 2px 0 #FF5722;
}
/* 响应式设计 */
@media (max-width: 768px) {
body {
padding: 5px;
}
#gameContainer {
max-width: 100%;
height: 100vh;
border-radius: 0;
}
h1 {
font-size: 1.8rem;
}
h2 {
font-size: 1.1rem;
}
.game-description {
font-size: 0.9rem;
padding: 12px;
}
button {
padding: 12px 30px;
font-size: 1.1rem;
min-height: 44px;
}
#levelComplete {
padding: 20px 25px;
}
#levelComplete h2 {
font-size: 1.6rem;
}
.control-btn {
width: 55px;
height: 55px;
font-size: 1.1rem;
}
.control-btn.long-btn {
width: 130px;
font-size: 0.9rem;
}
}
/* 小屏幕设备 */
@media (max-width: 480px) {
h1 {
font-size: 1.6rem;
}
h2 {
font-size: 1rem;
}
.control-title {
font-size: 1rem;
}
.player-info, .level-info {
font-size: 0.8rem;
padding: 5px 8px;
}
button {
padding: 10px 25px;
font-size: 1rem;
min-width: 180px;
}
.control-btn {
width: 50px;
height: 50px;
font-size: 1rem;
}
.control-btn.long-btn {
width: 120px;
font-size: 0.9rem;
}
#mobileControls {
padding: 0 15px;
bottom: 15px;
}
}
/* 横屏优化 */
@media (orientation: landscape) {
#gameCanvas {
height: 80%;
}
#mobileControls {
bottom: 10px;
}
.control-btn {
width: 45px;
height: 45px;
font-size: 0.9rem;
}
.control-btn.long-btn {
width: 100px;
font-size: 0.8rem;
}
#topBar {
padding: 8px 10px;
}
}
/* 动画效果 */
@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(-8px); }
100% { transform: translateY(0px); }
}
/* 游戏UI元素 */
#pauseScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 40;
padding: 20px;
text-align: center;
}
#pauseScreen h2 {
font-size: 2.2rem;
margin-bottom: 20px;
color: #FFD700;
}
#pauseScreen button {
margin: 8px;
width: 200px;
max-width: 80%;
}
#gameStats {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 15px;
background: rgba(255, 255, 255, 0.1);
padding: 12px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
.stat-item {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
}
#bossHealthBar {
position: absolute;
top: 8px;
left: 50%;
transform: translateX(-50%);
width: 250px;
height: 16px;
background: rgba(0, 0, 0, 0.5);
border-radius: 8px;
overflow: hidden;
display: none;
z-index: 20;
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: -20px;
left: 0;
width: 100%;
text-align: center;
color: white;
font-weight: bold;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
font-size: 0.9rem;
}
#powerUpDisplay {
position: absolute;
bottom: 180px;
left: 10px;
display: flex;
gap: 8px;
color: white;
font-size: 0.8rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 8px 12px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
.powerUp-item {
display: flex;
align-items: center;
gap: 4px;
}
.powerUp-icon {
width: 14px;
height: 14px;
border-radius: 50%;
}
.laser-icon {
background: #2196F3;
}
.shield-icon {
background: #4CAF50;
}
#scoreDisplay {
position: absolute;
top: 60px;
right: 10px;
color: white;
font-size: 1rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 8px 12px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
}
#comboDisplay {
position: absolute;
top: 60px;
left: 10px;
color: white;
font-size: 1rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 8px 12px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
display: none;
}
.damage-popup {
position: absolute;
color: #ff5555;
font-weight: bold;
font-size: 14px;
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(-40px);
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;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 0.8rem;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 10px 20px;
border-radius: 10px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255, 255, 255, 0.2);
display: none;
z-index: 30;
}
/* 对话系统 */
#dialogueScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 50;
padding: 20px;
text-align: center;
}
#dialogueContent {
max-width: 90%;
background: rgba(255, 255, 255, 0.1);
padding: 20px;
border-radius: 20px;
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.2);
margin-bottom: 20px;
}
#dialogueText {
font-size: 1.1rem;
line-height: 1.5;
margin-bottom: 15px;
text-align: left;
}
#dialogueSpeaker {
font-size: 1rem;
color: #FFD700;
text-align: left;
margin-bottom: 10px;
font-weight: bold;
}
#dialogueNext {
background: linear-gradient(to bottom, #4CAF50, #2E7D32);
border: none;
color: white;
padding: 10px 25px;
border-radius: 50px;
cursor: pointer;
font-size: 1rem;
font-weight: 600;
transition: all 0.3s;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
border: 2px solid rgba(255, 255, 255, 0.2);
min-height: 44px;
}
#dialogueNext:hover {
background: linear-gradient(to bottom, #66BB6A, #388E3C);
transform: translateY(-3px);
}
/* 设置界面 */
#settingsScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
z-index: 60;
padding: 20px;
text-align: center;
}
#settingsContent {
max-width: 90%;
background: rgba(255, 255, 255, 0.1);
padding: 25px;
border-radius: 20px;
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.2);
margin-bottom: 20px;
}
.level-select {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin: 15px 0;
}
.level-btn {
padding: 12px;
background: rgba(255, 255, 255, 0.1);
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
color: white;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s;
min-height: 44px;
}
.level-btn:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-3px);
}
.level-btn.locked {
opacity: 0.5;
cursor: not-allowed;
}
.level-btn.completed {
background: rgba(76, 175, 80, 0.3);
border-color: #4CAF50;
}
/* 玩家名字显示 */
.player-name {
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
color: white;
font-weight: bold;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
background: rgba(0, 0, 0, 0.5);
padding: 2px 8px;
border-radius: 8px;
font-size: 0.8rem;
white-space: nowrap;
z-index: 5;
}
/* 被绑架的许子昂 */
.kidnapped-person {
position: absolute;
width: 35px;
height: 50px;
background: #9C27B0;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 0.7rem;
text-align: center;
z-index: 10;
}
/* 天神效果 */
.god-effect {
position: absolute;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(255, 215, 0, 0.3) 0%, transparent 70%);
z-index: 5;
pointer-events: none;
animation: godPulse 2s infinite;
}
@keyframes godPulse {
0% { opacity: 0.5; }
50% { opacity: 0.8; }
100% { opacity: 0.5; }
}
/* 天神降临效果 */
.god-arrival {
position: absolute;
top: -80px;
left: 50%;
transform: translateX(-50%);
color: #FFD700;
font-size: 1.5rem;
font-weight: bold;
text-shadow: 0 0 10px rgba(255, 215, 0, 0.8);
animation: fallDown 1s ease-out forwards;
z-index: 100;
}
@keyframes fallDown {
0% { top: -80px; opacity: 0; }
100% { top: 50%; opacity: 1; }
}
/* 触摸设备优化 */
@media (hover: none) and (pointer: coarse) {
button, .level-btn, .control-btn {
min-height: 44px;
}
.mobile-btn-demo {
width: 45px;
height: 45px;
}
}
/* 隐藏的提示 */
.hidden-hint {
color: rgba(255, 255, 255, 0.3);
font-size: 0.7rem;
margin-top: 5px;
}
/* 竖屏优化 */
@media (orientation: portrait) and (max-height: 700px) {
#gameCanvas {
height: 65%;
}
#powerUpDisplay {
bottom: 160px;
}
}
/* 超大屏幕优化 */
@media (min-width: 768px) and (min-height: 1024px) {
#gameContainer {
max-width: 768px;
max-height: 1024px;
}
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 1.5rem;
}
.game-description {
font-size: 1.2rem;
}
button {
padding: 15px 40px;
font-size: 1.3rem;
}
.control-btn {
width: 70px;
height: 70px;
font-size: 1.3rem;
}
.control-btn.long-btn {
width: 160px;
font-size: 1.1rem;
}
}
/* 防止长按菜单 */
.no-context-menu {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>
</head>
<body class="no-context-menu">
<div id="gameContainer">
<div id="topBar">
<div class="player-status">
<div class="player-info">
<div class="player-icon">董</div>
<div>生命: <span id="playerLives">3</span></div>
<div class="skill-status">
| 射击:
<div class="skill-indicator" id="playerSkill"></div>
<span id="playerSkillText">可用</span>
</div>
</div>
</div>
<div class="level-info">
<div>关卡: <span id="currentLevel">1</span>/4</div>
<button id="settingsBtn" style="margin-left: 10px; padding: 4px 12px; font-size: 0.8rem; min-height: 30px;">设置</button>
</div>
</div>
<canvas id="gameCanvas" width="768" height="432"></canvas>
<!-- 移动端控制按钮 -->
<div id="mobileControls">
<div class="control-group">
<div class="direction-controls">
<div class="control-btn move-btn" id="mobileLeft">←</div>
<div class="control-btn jump-btn" id="mobileJump">↑</div>
<div class="control-btn move-btn" id="mobileRight">→</div>
</div>
</div>
<div class="control-group">
<div class="action-controls">
<div class="control-btn shoot-btn" id="mobileShoot">射击</div>
<div class="control-btn skill-btn" id="mobileSkill">技能</div>
<div class="control-btn ability-btn" id="mobileAbility">能力</div>
<div class="control-btn pause-btn" id="mobilePause">暂停</div>
</div>
</div>
</div>
<!-- 游戏UI元素 -->
<div id="bossHealthBar">
<div id="bossHealthFill"></div>
<div id="bossName">金文翔</div>
<div id="bossHitCount" style="position: absolute; top: -35px; left: 0; width: 100%; text-align: center; color: white; font-size: 0.8rem;">击中: <span id="bossHits">0</span>/50</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 class="powerUp-item">
<div class="powerUp-icon" style="background: #FFD700;"></div>
<span id="godTimer">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="checkpointIndicator">检查点已激活!</div>
<!-- 游戏界面 -->
<div id="levelComplete">
<h2 id="levelCompleteTitle">关卡完成!</h2>
<p id="levelCompleteText">恭喜你通过了当前关卡!</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>
<button id="menuBtn2">主菜单</button>
</div>
<div id="pauseScreen">
<h2>游戏暂停</h2>
<button id="resumeBtn">继续游戏</button>
<button id="restartBtn">重新开始</button>
<button id="menuBtn">返回主菜单</button>
<button id="settingsBtn2">关卡选择</button>
</div>
<!-- 对话系统 -->
<div id="dialogueScreen">
<div id="dialogueContent">
<div id="dialogueSpeaker">对话</div>
<div id="dialogueText">这里是对话内容...</div>
<button id="dialogueNext">继续</button>
</div>
</div>
<!-- 设置界面 -->
<div id="settingsScreen">
<div id="settingsContent">
<h2>关卡选择</h2>
<p>选择要游玩的关卡:</p>
<div class="level-select" id="levelSelect">
<!-- 关卡按钮将通过JS动态生成 -->
</div>
<button id="backToGameBtn">返回游戏</button>
<button id="backToMenuBtn">返回主菜单</button>
</div>
</div>
<!-- 公告屏幕最先显示 -->
<div id="announcementScreen">
<div id="announcementContent">
<h2>游戏公告</h2>
<p>亲爱的用户,本次更新,适配移动端,受同学委托,本游戏完全由同学定制,游戏中出现的名字全部由本班同学,本版本为第7代游戏版本。</p>
<p>优化内容:</p>
<p>1. 修复了对话完成后不显示画面的问题</p>
<p>2. 为所有角色添加了眼睛、手臂等细节</p>
<p>3. 添加陈浩然天神剧情:按10下跳跃键触发隐藏技能</p>
<p>4. 最后一关许子昂被关在牢笼中</p>
<p>5. 优化了Boss战体验,Boss不会连发,但会触发对话</p>
<p>6. 改进了移动端操作体验</p>
<p>7. 增强了视觉效果和游戏稳定性</p>
<p>8. 删除了虚空死亡机制,横屏模式下不会无限死亡</p>
<p>如有疑问,反馈快手号:s20120405</p>
<p>希望你们喜欢这个游戏!</p>
</div>
<button id="continueBtn">开始游戏</button>
<div class="copyright">© 2023 欣欣向然 版权所有 - 第7代版本</div>
</div>
<!-- 开始游戏屏幕(主菜单) -->
<div id="startScreen">
<div id="gameTitle" class="floating">
<h1>董测浩解救许子昂</h1>
<h2>手机冒险游戏</h2>
</div>
<div class="game-description">
董测浩的好友许子昂被金文翔绑架了!帮助董测浩通过所有关卡,击败金文翔,解救许子昂!
</div>
<div class="mobile-controls-info">
<div class="mobile-control-set">
<div class="control-title">游戏控制</div>
<div class="mobile-control-row">
<div class="mobile-btn-demo move">←</div>
<span>左右移动</span>
</div>
<div class="mobile-control-row">
<div class="mobile-btn-demo jump">↑</div>
<span>跳跃</span>
</div>
<div class="mobile-control-row">
<div class="mobile-btn-demo shoot">射击</div>
<span>发射子弹</span>
</div>
<div class="mobile-control-row">
<div class="mobile-btn-demo skill">技能</div>
<span>特殊技能</span>
</div>
<div class="hidden-hint">隐藏技能:连续按10次跳跃键触发陈浩然天神剧情</div>
</div>
</div>
<button id="startBtn" class="pulse">开始冒险</button>
</div>
<!-- 开发者致谢界面 -->
<div id="thanksScreen" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.95); display: none; flex-direction: column; justify-content: center; align-items: center; color: white; z-index: 100; padding: 20px; text-align: center;">
<div style="max-width: 90%; background: rgba(255, 255, 255, 0.1); padding: 25px; border-radius: 20px; backdrop-filter: blur(10px); border: 2px solid rgba(255, 255, 255, 0.2); margin-bottom: 20px;">
<h2 style="color: #FFD700; margin-bottom: 20px;">感谢游玩!</h2>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">恭喜你,屏幕前的朋友!</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">感谢你的使用,如需反馈,请联系开头时所给的联系方式。</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">制作软件: bI.cooL</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">制作人员: 欣欣向然</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">特殊错误修复: 由DeepSeek辅助修复</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">除错误以外,均为本人开发</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">累计代码: 4500行,小型游戏</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem;">制作代码: HTML5, JavaScript, CSS3</p>
<p style="margin: 10px 0; line-height: 1.6; font-size: 1rem; color: #FFD700;">感谢您的游玩,我将不负众望,继续前行。</p>
</div>
<button id="thanksBackBtn">返回主菜单</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 menuBtn2 = document.getElementById('menuBtn2');
const settingsBtn = document.getElementById('settingsBtn');
const settingsBtn2 = document.getElementById('settingsBtn2');
const bossHealthBar = document.getElementById('bossHealthBar');
const bossHealthFill = document.getElementById('bossHealthFill');
const bossName = document.getElementById('bossName');
const bossHitsElement = document.getElementById('bossHits');
const laserTimerElement = document.getElementById('laserTimer');
const shieldCountElement = document.getElementById('shieldCount');
const godTimerElement = document.getElementById('godTimer');
const scoreDisplay = document.getElementById('scoreDisplay');
const scoreValue = document.getElementById('scoreValue');
const comboDisplay = document.getElementById('comboDisplay');
const comboValue = document.getElementById('comboValue');
const maxComboElement = document.getElementById('maxCombo');
const levelScoreElement = document.getElementById('levelScore');
const levelCompleteTitle = document.getElementById('levelCompleteTitle');
const levelCompleteText = document.getElementById('levelCompleteText');
const checkpointIndicator = document.getElementById('checkpointIndicator');
const dialogueScreen = document.getElementById('dialogueScreen');
const dialogueText = document.getElementById('dialogueText');
const dialogueSpeaker = document.getElementById('dialogueSpeaker');
const dialogueNextBtn = document.getElementById('dialogueNext');
const settingsScreen = document.getElementById('settingsScreen');
const levelSelect = document.getElementById('levelSelect');
const backToGameBtn = document.getElementById('backToGameBtn');
const backToMenuBtn = document.getElementById('backToMenuBtn');
const thanksScreen = document.getElementById('thanksScreen');
const thanksBackBtn = document.getElementById('thanksBackBtn');
// 移动控制按钮
const mobileLeft = document.getElementById('mobileLeft');
const mobileRight = document.getElementById('mobileRight');
const mobileJump = document.getElementById('mobileJump');
const mobileShoot = document.getElementById('mobileShoot');
const mobileSkill = document.getElementById('mobileSkill');
const mobileAbility = document.getElementById('mobileAbility');
const mobilePause = document.getElementById('mobilePause');
// 获取所有需要的UI元素
const playerLivesElement = document.getElementById('playerLives');
const playerSkillElement = document.getElementById('playerSkill');
const playerSkillTextElement = document.getElementById('playerSkillText');
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 = 4;
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
};
// 对话系统
let currentDialogue = 0;
let dialogueSequence = [];
let dialogueCallback = null;
// 天神系统 - 陈浩然
let chenHaoranMode = false;
let chenHaoranTimer = 0;
let jumpCount = 0;
let lastJumpTime = 0;
let godEffectElement = null;
let allLevelsUnlocked = false; // 天神模式下解锁所有关卡
// 解锁的关卡
let unlockedLevels = [1];
// 键盘状态管理
const keys = {
'a': false, 'd': false, 'w': false, 'j': false, 'k': false, 'q': false, 'p': false
};
// 移动端触摸状态
const touchState = {
left: false,
right: false,
jump: false,
shoot: false,
skill: false,
ability: false
};
// 游戏对象
let player, platforms, enemies, coins, hazards, goal, powerUps, checkpoints, kidnappedPerson;
// 初始化移动端控制
function initMobileControls() {
// 左方向键
mobileLeft.addEventListener('touchstart', (e) => {
e.preventDefault();
touchState.left = true;
keys['a'] = true;
});
mobileLeft.addEventListener('touchend', (e) => {
e.preventDefault();
touchState.left = false;
keys['a'] = false;
});
// 右方向键
mobileRight.addEventListener('touchstart', (e) => {
e.preventDefault();
touchState.right = true;
keys['d'] = true;
});
mobileRight.addEventListener('touchend', (e) => {
e.preventDefault();
touchState.right = false;
keys['d'] = false;
});
// 跳跃键
mobileJump.addEventListener('touchstart', (e) => {
e.preventDefault();
touchState.jump = true;
keys['w'] = true;
// 跳跃计数检测
const currentTime = Date.now();
if (currentTime - lastJumpTime < 500) { // 500ms内算连续跳跃
jumpCount++;
} else {
jumpCount = 1;
}
lastJumpTime = currentTime;
// 检测10次跳跃触发陈浩然天神
if (jumpCount >= 10 && !chenHaoranMode) {
activateChenHaoranMode();
jumpCount = 0;
}
});
mobileJump.addEventListener('touchend', (e) => {
e.preventDefault();
touchState.jump = false;
keys['w'] = false;
});
// 射击键
mobileShoot.addEventListener('touchstart', (e) => {
e.preventDefault();
touchState.shoot = true;
keys['j'] = true;
});
mobileShoot.addEventListener('touchend', (e) => {
e.preventDefault();
touchState.shoot = false;
keys['j'] = false;
});
// 技能键
mobileSkill.addEventListener('touchstart', (e) => {
e.preventDefault();
touchState.skill = true;
keys['k'] = true;
});
mobileSkill.addEventListener('touchend', (e) => {
e.preventDefault();
touchState.skill = false;
keys['k'] = false;
});
// 能力键
mobileAbility.addEventListener('touchstart', (e) => {
e.preventDefault();
touchState.ability = true;
keys['q'] = true;
});
mobileAbility.addEventListener('touchend', (e) => {
e.preventDefault();
touchState.ability = false;
keys['q'] = false;
});
// 暂停键
mobilePause.addEventListener('click', (e) => {
e.preventDefault();
if (gameRunning) {
togglePause();
}
});
// 防止页面滚动
document.addEventListener('touchmove', function(e) {
if (gameRunning && !gamePaused) {
e.preventDefault();
}
}, { passive: false });
}
// 屏幕尺寸适配
function adjustForScreenSize() {
const container = document.getElementById('gameContainer');
const canvas = document.getElementById('gameCanvas');
// 获取容器实际尺寸
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
// 设置画布尺寸为容器尺寸
const canvasWidth = Math.floor(containerWidth);
const canvasHeight = Math.floor(containerHeight * 0.7);
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvas.style.width = canvasWidth + 'px';
canvas.style.height = canvasHeight + 'px';
// 更新UI元素位置
updateUIPositions();
// 如果游戏没有运行,绘制一次背景
if (!gameRunning) {
drawBackground();
}
}
// 更新UI元素位置
function updateUIPositions() {
// 更新被绑架的许子昂位置
if (kidnappedPerson && kidnappedPerson.element) {
kidnappedPerson.updateElementPosition();
}
// 更新玩家名字位置
if (player && player.nameElement) {
player.updateNamePosition();
}
}
// 窗口大小变化时调整
window.addEventListener('resize', adjustForScreenSize);
window.addEventListener('orientationchange', function() {
setTimeout(adjustForScreenSize, 100);
});
// 键盘事件
window.addEventListener('keydown', (e) => {
const key = e.key.toLowerCase();
if (keys.hasOwnProperty(key)) {
keys[key] = true;
if (key === 'p' && gameRunning) {
togglePause();
}
// 跳跃计数检测
if (key === 'w') {
const currentTime = Date.now();
if (currentTime - lastJumpTime < 500) { // 500ms内算连续跳跃
jumpCount++;
} else {
jumpCount = 1;
}
lastJumpTime = currentTime;
// 检测10次跳跃触发陈浩然天神
if (jumpCount >= 10 && !chenHaoranMode) {
activateChenHaoranMode();
jumpCount = 0;
}
}
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 14px 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);
}
// 陈浩然天神模式
function activateChenHaoranMode() {
if (chenHaoranMode) return;
chenHaoranMode = true;
chenHaoranTimer = 900; // 15秒持续时间
// 解锁所有关卡
allLevelsUnlocked = true;
for (let i = 1; i <= totalLevels; i++) {
if (!unlockedLevels.includes(i)) {
unlockedLevels.push(i);
}
}
// 创建天神降临效果
const godArrival = document.createElement('div');
godArrival.className = 'god-arrival';
godArrival.textContent = '陈浩然天神降临!';
document.getElementById('gameContainer').appendChild(godArrival);
// 创建天神效果
godEffectElement = document.createElement('div');
godEffectElement.className = 'god-effect';
document.getElementById('gameContainer').appendChild(godEffectElement);
// 播放陈浩然对话
showDialogue([
{ speaker: "陈浩然", text: "老78头子,看在你这么用力的份上,我就暂且帮助你一下。" },
{ speaker: "陈浩然", text: "你将获得神力,可以随意启动关卡,也可以无限发射子弹,射速加快两倍,伤害加倍!" },
{ speaker: "陈浩然", text: "这如果死了,你就直接在地里面呆着别活了。" }
], function() {
// 对话结束后继续游戏
});
// 移除天神降临文字
setTimeout(() => {
if (godArrival.parentNode) {
godArrival.parentNode.removeChild(godArrival);
}
}, 2000);
// 更新UI
godTimerElement.textContent = Math.ceil(chenHaoranTimer / 60);
}
// 粒子效果类
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 : (chenHaoranMode ? 20 : 10); // 陈浩然模式下速度加倍
this.direction = direction;
this.color = color;
this.type = type;
this.particles = [];
this.damage = type === 'laser' ? 2 : (chenHaoranMode ? 2 : 1); // 陈浩然模式下伤害加倍
}
update() {
this.x += this.speed * this.direction;
// 激光子弹的特殊效果
if (this.type === 'laser' || chenHaoranMode) {
// 添加粒子效果
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' || chenHaoranMode) {
// 绘制激光子弹
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 = chenHaoranMode ? 999 : 3; // 陈浩然模式下无限子弹
this.powerUps = {
laser: 0,
shield: 0,
speed: 0
};
this.particles = [];
this.abilityCooldown = 0;
this.abilityActive = false;
this.abilityDuration = 0;
this.name = "董测浩";
this.nameElement = null;
this.createNameElement();
}
createNameElement() {
this.nameElement = document.createElement('div');
this.nameElement.className = 'player-name';
this.nameElement.textContent = this.name;
document.getElementById('gameContainer').appendChild(this.nameElement);
}
updateNamePosition() {
if (this.nameElement) {
const scaleX = canvas.clientWidth / canvas.width;
const scaleY = canvas.clientHeight / canvas.height;
this.nameElement.style.left = ((this.x + this.width/2) * scaleX) + 'px';
this.nameElement.style.top = ((this.y - 10) * scaleY) + 'px';
}
}
update(platforms, enemies, coins, hazards, powerUps, checkpoints) {
if (gamePaused) return;
// 更新动画帧
this.animationFrame++;
// 无敌时间减少
if (this.invincible > 0) {
this.invincible--;
}
// 陈浩然天神模式时间减少
if (chenHaoranMode) {
chenHaoranTimer--;
godTimerElement.textContent = Math.ceil(chenHaoranTimer / 60);
if (chenHaoranTimer <= 0) {
chenHaoranMode = false;
this.maxBullets = 3;
if (godEffectElement && godEffectElement.parentNode) {
godEffectElement.parentNode.removeChild(godEffectElement);
}
godTimerElement.textContent = "0";
}
}
// 应用重力
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--;
}
// 特殊能力持续时间
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 + this.height > canvas.height) {
this.y = canvas.height - this.height;
this.velocityY = 0;
this.onGround = true;
this.jumping = false;
}
// 平台碰撞检测
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 && !chenHaoranMode) { // 陈浩然模式下无敌
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 && !chenHaoranMode) { // 陈浩然模式下无敌
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);
playerLivesElement.textContent = this.lives;
} 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
));
}
}
}
// 处理玩家输入(移动端使用touchState)
if (touchState.left || keys['a']) {
this.move('left');
} else if (touchState.right || keys['d']) {
this.move('right');
} else {
this.move('stop');
}
if (touchState.jump || keys['w']) {
this.jump();
}
if (touchState.shoot || keys['j']) {
this.useSkill();
}
if ((touchState.ability || keys['q']) && 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--;
}
// 更新名字位置
this.updateNamePosition();
// 更新UI
if (playerSkillElement) {
playerSkillElement.className = this.skillCooldown > 0 ? 'skill-indicator cooldown' : 'skill-indicator';
}
if (playerSkillTextElement) {
playerSkillTextElement.textContent = this.skillCooldown > 0 ? '冷却' : '可用';
}
}
draw() {
// 绘制玩家角色
ctx.save();
// 无敌闪烁效果
if (this.invincible > 0 && Math.floor(this.invincible / 10) % 2 === 0) {
ctx.globalAlpha = 0.5;
}
// 陈浩然天神模式效果
if (chenHaoranMode) {
ctx.globalAlpha = 0.8;
ctx.fillStyle = '#FFD700';
} else {
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 = 'black';
ctx.fillRect(this.facingRight ? this.x + 22 : this.x + 10, this.y + 14, 4, 4);
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.fillRect(this.x + 12, this.y + 28, 8, 4);
// 绘制手臂
ctx.fillStyle = chenHaoranMode ? '#FFD700' : this.color;
let armOffset = Math.sin(this.animationFrame * 0.2) * 3;
if (this.velocityX !== 0 && this.onGround) {
// 行走时手臂摆动
ctx.fillRect(this.x - 5, this.y + 15, 8, 10);
ctx.fillRect(this.x + this.width - 3, this.y + 15, 8, 10);
} else {
// 静止时手臂
ctx.fillRect(this.x - 5, this.y + 15, 8, 10);
ctx.fillRect(this.x + this.width - 3, this.y + 15, 8, 10);
}
// 绘制腿(动画效果)
ctx.fillStyle = chenHaoranMode ? '#FFD700' : 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() {
// 陈浩然模式下无冷却时间,无限子弹
const canShoot = chenHaoranMode ? true : (this.skillCooldown === 0 && this.bullets.length < this.maxBullets);
if (canShoot) {
this.skillActive = true;
this.skillCooldown = this.powerUps.laser > 0 ? 10 : (chenHaoranMode ? 0 : 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 = chenHaoranMode ? '#FFD700' : this.color;
let bulletType = (this.powerUps.laser > 0 || chenHaoranMode) ? 'laser' : 'normal';
this.bullets.push(new Bullet(bulletX, bulletY, direction, bulletColor, bulletType));
// 陈浩然模式下可以连续发射多颗子弹
if (chenHaoranMode && Math.random() < 0.3) {
this.bullets.push(new Bullet(bulletX, bulletY + 10, direction, bulletColor, bulletType));
this.bullets.push(new Bullet(bulletX, bulletY - 10, direction, bulletColor, bulletType));
}
}
}
useAbility() {
if (this.abilityCooldown === 0) {
this.abilityActive = true;
this.abilityDuration = 180; // 3秒持续时间
this.abilityCooldown = 600; // 10秒冷却时间
// 能力:范围爆炸
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
));
}
// 屏幕震动
screenShake();
}
}
respawn() {
// 如果有激活的检查点,就在检查点重生
if (checkpoint.active) {
this.x = checkpoint.x;
this.y = checkpoint.y;
} else {
this.x = 50;
this.y = canvas.height * 0.6; // 根据画布高度调整
}
// 确保重生点不超出底部
if (this.y + this.height > canvas.height) {
this.y = canvas.height - this.height;
}
this.velocityX = 0;
this.velocityY = 0;
this.bullets = [];
this.invincible = 120;
}
removeNameElement() {
if (this.nameElement && this.nameElement.parentNode) {
this.nameElement.parentNode.removeChild(this.nameElement);
}
}
}
// 平台类
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 Cage {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.broken = false;
this.bars = [];
this.createBars();
}
createBars() {
// 创建牢笼的栏杆
for (let i = 0; i < 5; i++) {
this.bars.push({
x: this.x + i * (this.width / 4),
y: this.y,
width: 8,
height: this.height
});
}
// 创建横杆
this.bars.push({x: this.x, y: this.y, width: this.width, height: 8});
this.bars.push({x: this.x, y: this.y + this.height - 8, width: this.width, height: 8});
}
draw() {
if (this.broken) return;
ctx.save();
// 绘制牢笼栏杆
ctx.fillStyle = '#795548';
for (let bar of this.bars) {
ctx.fillRect(bar.x, bar.y, bar.width, bar.height);
}
// 绘制锁
ctx.fillStyle = '#FFD700';
ctx.fillRect(this.x + this.width/2 - 10, this.y + this.height/2 - 5, 20, 10);
ctx.fillStyle = '#B8860B';
ctx.fillRect(this.x + this.width/2 - 8, this.y + this.height/2 - 3, 16, 6);
ctx.restore();
}
checkCollision(player) {
if (this.broken) return false;
// 检查玩家是否接触到牢笼
for (let bar of this.bars) {
if (player.x < bar.x + bar.width &&
player.x + player.width > bar.x &&
player.y < bar.y + bar.height &&
player.y + player.height > bar.y) {
return true;
}
}
return false;
}
break() {
this.broken = true;
// 添加破碎效果
if (player) {
for (let bar of this.bars) {
for (let i = 0; i < 10; i++) {
player.particles.push(new Particle(
bar.x + bar.width/2,
bar.y + bar.height/2,
'#795548',
Math.random() * 3 + 1,
(Math.random() - 0.5) * 5,
(Math.random() - 0.5) * 5,
Math.random() * 30 + 20
));
}
}
}
}
}
// 被绑架的许子昂类
class KidnappedPerson {
constructor(x, y) {
this.x = x;
this.y = y;
this.width = 40;
this.height = 60;
this.color = '#9C27B0';
this.name = "许子昂";
this.rescued = false;
this.element = null;
this.cage = new Cage(x - 20, y - 20, this.width + 40, this.height + 40);
this.createElement();
}
createElement() {
this.element = document.createElement('div');
this.element.className = 'kidnapped-person';
this.element.textContent = this.name;
document.getElementById('gameContainer').appendChild(this.element);
this.updateElementPosition();
}
draw() {
if (this.rescued) return;
// 绘制牢笼
this.cage.draw();
ctx.save();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
// 绘制脸部 - 改进版
ctx.fillStyle = 'white';
ctx.fillRect(this.x + 10, this.y + 15, 8, 8);
ctx.fillRect(this.x + 22, this.y + 15, 8, 8);
// 绘制眼睛
ctx.fillStyle = 'black';
ctx.fillRect(this.x + 12, this.y + 17, 4, 4);
ctx.fillRect(this.x + 24, this.y + 17, 4, 4);
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.fillRect(this.x + 15, this.y + 30, 10, 5);
// 绘制手臂
ctx.fillStyle = this.color;
ctx.fillRect(this.x - 5, this.y + 20, 8, 10);
ctx.fillRect(this.x + this.width - 3, this.y + 20, 8, 10);
// 绘制腿
ctx.fillRect(this.x + 5, this.y + this.height, 8, -10);
ctx.fillRect(this.x + this.width - 13, this.y + this.height, 8, -10);
ctx.restore();
}
rescue() {
// 先打破牢笼
this.cage.break();
// 延迟解救效果
setTimeout(() => {
this.rescued = true;
if (this.element && this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
}
// 显示解救成功消息
showDialogue([
{ speaker: "许子昂", text: "董测浩!谢谢你救了我!" },
{ speaker: "董测浩", text: "不用谢,我们是最好的朋友!" }
], function() {
// 对话结束后继续游戏
});
}, 500);
}
updateElementPosition() {
if (this.element) {
const scaleX = canvas.clientWidth / canvas.width;
const scaleY = canvas.clientHeight / canvas.height;
this.element.style.left = (this.x * scaleX) + 'px';
this.element.style.top = (this.y * scaleY) + 'px';
this.element.style.width = (this.width * scaleX) + 'px';
this.element.style.height = (this.height * scaleY) + 'px';
this.element.style.fontSize = Math.max(10, 12 * Math.min(scaleX, scaleY)) + 'px';
}
}
checkCollision(player) {
// 检查玩家是否接触到许子昂
if (this.rescued) return false;
if (player.x < this.x + this.width &&
player.x + player.width > this.x &&
player.y < this.y + this.height &&
player.y + player.height > this.y) {
// 检查牢笼是否被打破
if (!this.cage.broken) {
// 打破牢笼
this.cage.break();
return false;
} else {
// 解救许子昂
this.rescue();
return true;
}
}
return false;
}
}
// 敌人类
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 = [];
this.hitCount = 0; // 用于Boss战计数
this.dialogueTriggered = false; // 对话触发标记
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 = 50; // 需要击中50次
this.maxHealth = 50;
this.attackPattern = 0;
this.attackTimer = 0;
this.hitCount = 0; // 记录被击中的次数
this.rageMode = false; // 狂暴模式
this.rageTimer = 0;
this.dialogueCooldown = 0; // 对话冷却
}
}
update(platforms, players) {
if (this.dead || gamePaused) return;
// 对话冷却
if (this.dialogueCooldown > 0) {
this.dialogueCooldown--;
}
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.health <= this.maxHealth * 0.3 && !this.rageMode) {
this.rageMode = true;
this.rageTimer = 300; // 5秒狂暴模式
this.speed *= 1.5;
this.color = '#FF0000'; // 变红
// 触发对话
if (this.dialogueCooldown === 0) {
showDialogue([
{ speaker: "金文翔", text: "可恶!你竟然把我逼到这种地步!" }
], function() {
// 对话结束后继续游戏
});
this.dialogueCooldown = 300; // 5秒冷却
}
}
if (this.rageMode) {
this.rageTimer--;
if (this.rageTimer <= 0) {
this.rageMode = false;
this.speed /= 1.5;
this.color = '#D32F2F';
}
}
// 随机触发对话
if (Math.random() < 0.001 && this.dialogueCooldown === 0 && !this.dialogueTriggered) { // 低概率触发
const dialogues = [
{ speaker: "金文翔", text: "哈哈哈,宾犬就这点本事吗?" },
{ speaker: "金文翔", text: "许子昂是我的,你休想救走他!" },
{ speaker: "金文翔", text: "看我的绝招!" }
];
const randomDialogue = dialogues[Math.floor(Math.random() * dialogues.length)];
showDialogue([randomDialogue], function() {
// 对话结束后继续游戏
});
this.dialogueCooldown = 300; // 5秒冷却
this.dialogueTriggered = true;
}
// 边界检查
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 > 90) { // 每1.5秒射击一次
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}%`;
bossHitsElement.textContent = this.hitCount;
}
// 边界检查
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);
ctx.fillStyle = 'black';
ctx.fillRect(this.direction > 0 ? this.x + this.width - 13 : this.x + 7, this.y + 12, 4, 4);
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.fillRect(this.x + 12, this.y + 25, 10, 4);
// 绘制手臂
ctx.fillStyle = this.color;
ctx.fillRect(this.x - 5, this.y + 10, 8, 10);
ctx.fillRect(this.x + this.width - 3, this.y + 10, 8, 10);
}
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();
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(this.direction > 0 ? this.x + this.width - 10 : this.x + 10, this.y + 12, 2, 0, Math.PI * 2);
ctx.fill();
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + 20, 6, 0, Math.PI);
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();
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + 12, 2, 0, Math.PI * 2);
ctx.fill();
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + 20, 5, 0, Math.PI);
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();
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(this.direction > 0 ? this.x + this.width - 10 : this.x + 10, this.y + 12, 2, 0, Math.PI * 2);
ctx.fill();
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + 20, 5, 0, Math.PI);
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);
ctx.fillStyle = 'black';
ctx.fillRect(this.direction > 0 ? this.x + this.width - 13 : this.x + 7, this.y + 12, 4, 4);
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.fillRect(this.x + 12, this.y + 25, 10, 4);
// 绘制手臂
ctx.fillStyle = this.color;
ctx.fillRect(this.x - 5, this.y + 10, 8, 10);
ctx.fillRect(this.x + this.width - 3, this.y + 10, 8, 10);
// 绘制子弹
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 = 'black';
ctx.fillRect(this.x + 24, this.y + 29, 7, 7);
ctx.fillRect(this.x + this.width - 31, this.y + 29, 7, 7);
// 绘制嘴巴
ctx.fillStyle = '#FF5252';
ctx.fillRect(this.x + 30, this.y + 50, this.width - 60, 10);
// 绘制牙齿
ctx.fillStyle = 'white';
for (let i = 0; i < 5; i++) {
ctx.fillRect(this.x + 32 + i * 10, this.y + 50, 6, 4);
}
// 绘制手臂
ctx.fillStyle = this.color;
ctx.fillRect(this.x - 10, this.y + 20, 12, 20);
ctx.fillRect(this.x + this.width - 2, this.y + 20, 12, 20);
// 绘制狂暴模式效果
if (this.rageMode) {
ctx.strokeStyle = '#FF0000';
ctx.lineWidth = 3;
ctx.strokeRect(this.x - 5, this.y - 5, this.width + 10, this.height + 10);
// 绘制狂暴粒子
if (Math.random() < 0.3) {
this.particles.push(new Particle(
this.x + Math.random() * this.width,
this.y + Math.random() * this.height,
'#FF0000',
Math.random() * 3 + 1,
(Math.random() - 0.5) * 2,
(Math.random() - 0.5) * 2,
Math.random() * 20 + 10
));
}
}
// 绘制子弹
for (let bullet of this.bullets) {
bullet.draw();
}
// 绘制名字 - 金文翔
ctx.fillStyle = 'white';
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.fillText('金文翔', this.x + this.width/2, this.y - 10);
}
// 绘制粒子
for (let particle of this.particles) {
particle.draw();
}
}
hitByBullet(bulletType) {
// 激光子弹造成双倍伤害
const damage = bulletType === 'laser' ? 2 : bulletType === 'ability' ? 3 : 1;
this.health -= damage;
this.hitCount++;
// 显示伤害数字
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' ? 1000 : 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';
// 显示通关消息
setTimeout(() => {
showDialogue([
{ speaker: "系统", text: "666,你竟然通关了!" },
{ speaker: "董测浩", text: "太好了!我击败了金文翔!" },
{ speaker: "旁白", text: "现在可以去解救许子昂了!" }
], function() {
// 对话结束后继续游戏
});
}, 1000);
}
}
}
}
// 金币类
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;
this.glow = 0;
}
update() {
this.pulse += 0.05;
this.glow = 0.5 + 0.5 * Math.sin(this.pulse * 2);
}
draw() {
// 绘制传送门发光效果
ctx.save();
// 外发光
ctx.fillStyle = `rgba(0, 255, 255, ${0.3 * this.glow})`;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width * 0.8, 0, Math.PI * 2);
ctx.fill();
// 内发光
ctx.fillStyle = `rgba(0, 200, 255, ${0.6 * this.glow})`;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width * 0.6, 0, Math.PI * 2);
ctx.fill();
// 传送门核心
ctx.fillStyle = '#00FFFF';
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width * 0.4, 0, Math.PI * 2);
ctx.fill();
// 传送门内部旋转效果
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width * 0.3, 0 + this.pulse, Math.PI + this.pulse);
ctx.stroke();
ctx.beginPath();
ctx.arc(this.x + this.width/2, this.y + this.height/2, this.width * 0.25, Math.PI + this.pulse, Math.PI * 2 + this.pulse);
ctx.stroke();
ctx.restore();
// 添加脉冲效果
ctx.strokeStyle = `rgba(0, 255, 255, ${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);
}
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);
}
}
// 对话系统
function showDialogue(dialogueArray, callback) {
dialogueSequence = dialogueArray;
currentDialogue = 0;
dialogueCallback = callback;
dialogueScreen.style.display = 'flex';
showNextDialogue();
}
function showNextDialogue() {
if (currentDialogue >= dialogueSequence.length) {
dialogueScreen.style.display = 'none';
// 如果有回调函数,则调用
if (dialogueCallback) {
dialogueCallback();
}
return;
}
const dialogue = dialogueSequence[currentDialogue];
dialogueSpeaker.textContent = dialogue.speaker;
dialogueText.textContent = dialogue.text;
currentDialogue++;
}
// 初始化关卡选择界面
function initLevelSelect() {
levelSelect.innerHTML = '';
for (let i = 1; i <= totalLevels; i++) {
const levelBtn = document.createElement('button');
levelBtn.className = 'level-btn';
levelBtn.textContent = `关卡 ${i}`;
if (allLevelsUnlocked || unlockedLevels.includes(i)) {
if (i < currentLevel) {
levelBtn.classList.add('completed');
}
levelBtn.onclick = () => {
if (gameRunning) {
togglePause();
}
startLevel(i);
};
} else {
levelBtn.classList.add('locked');
levelBtn.textContent += ' (锁定)';
}
levelSelect.appendChild(levelBtn);
}
}
// 关卡配置 - 4个关卡,重新设置传送门位置
const levelConfigs = [
// 关卡1:开始冒险 - 传送门放在右上角平台上
{
platforms: [
{x: 0, y: 380, width: 768, height: 40},
{x: 100, y: 320, width: 200, height: 20},
{x: 400, y: 260, width: 150, height: 20},
{x: 600, y: 200, width: 100, height: 20},
{x: 200, y: 140, width: 150, height: 20},
{x: 500, y: 80, width: 200, height: 20}
],
enemies: [
{x: 300, y: 300, type: 'walker', patrolRange: 100},
{x: 500, y: 250, type: 'walker', patrolRange: 80},
{x: 400, y: 150, type: 'flyer', patrolRange: 150}
],
coins: [
{x: 150, y: 290},
{x: 450, y: 240},
{x: 250, y: 140}
],
hazards: [],
powerUps: [
{x: 350, y: 250, type: 'score'}
],
checkpoints: [
{x: 300, y: 350, width: 50, height: 30}
],
goal: {x: 550, y: 40, width: 50, height: 50}, // 放在最后一个平台上
kidnappedPerson: null
},
// 关卡2:追踪线索 - 传送门放在中间平台上
{
platforms: [
{x: 0, y: 380, width: 768, height: 40},
{x: 100, y: 320, width: 150, height: 20},
{x: 300, y: 260, width: 150, height: 20},
{x: 500, y: 200, width: 150, height: 20},
{x: 200, y: 140, width: 150, height: 20},
{x: 400, y: 80, width: 150, height: 20},
{x: 600, y: 20, width: 150, height: 20}
],
enemies: [
{x: 200, y: 300, type: 'jumper', patrolRange: 80},
{x: 400, y: 250, type: 'walker', patrolRange: 80},
{x: 550, y: 200, type: 'jumper', patrolRange: 80},
{x: 450, y: 60, type: 'flyer', patrolRange: 100}
],
coins: [
{x: 150, y: 290},
{x: 350, y: 240},
{x: 550, y: 190},
{x: 250, y: 140},
{x: 450, y: 70}
],
hazards: [],
powerUps: [
{x: 400, y: 260, type: 'health'},
{x: 200, y: 140, type: 'score'}
],
checkpoints: [
{x: 400, y: 350, width: 50, height: 30}
],
goal: {x: 400, y: 30, width: 50, height: 50}, // 放在中间平台
kidnappedPerson: null
},
// 关卡3:接近目标 - 传送门放在左上角
{
platforms: [
{x: 0, y: 380, width: 768, height: 40},
{x: 100, y: 320, width: 100, height: 20},
{x: 250, y: 260, width: 100, height: 20},
{x: 400, y: 200, width: 100, height: 20},
{x: 550, y: 140, width: 100, height: 20},
{x: 400, y: 80, width: 100, height: 20},
{x: 250, y: 20, width: 100, height: 20},
{x: 100, y: -40, width: 100, height: 20}
],
enemies: [
{x: 200, y: 300, type: 'chaser'},
{x: 350, y: 250, type: 'jumper', patrolRange: 60},
{x: 500, y: 200, type: 'chaser'},
{x: 350, y: 10, type: 'flyer', patrolRange: 120}
],
coins: [
{x: 140, y: 290},
{x: 290, y: 240},
{x: 440, y: 190},
{x: 440, y: 70},
{x: 290, y: 20}
],
hazards: [],
powerUps: [
{x: 550, y: 140, type: 'laser'},
{x: 100, y: 300, type: 'score'}
],
checkpoints: [
{x: 400, y: 350, width: 50, height: 30}
],
goal: {x: 100, y: -60, width: 50, height: 50}, // 放在左上角平台上方
kidnappedPerson: null
},
// 关卡4:最终决战 - 传送门放在中间上方
{
platforms: [
{x: 0, y: 380, width: 768, height: 40},
{x: 300, y: 260, width: 200, height: 20},
{x: 200, y: 160, width: 100, height: 20},
{x: 500, y: 160, width: 100, height: 20},
{x: 100, y: 60, width: 80, height: 20},
{x: 620, y: 60, width: 80, height: 20}
],
enemies: [
{x: 360, y: 190, type: 'boss'}
],
coins: [
{x: 250, y: 250},
{x: 550, y: 250},
{x: 150, y: 150},
{x: 650, y: 150},
{x: 50, y: 50},
{x: 750, y: 50}
],
hazards: [
{x: 0, y: 350, width: 100, height: 30, type: 'fire'},
{x: 700, y: 350, width: 100, height: 30, type: 'fire'},
{x: 200, y: 350, width: 100, height: 30, type: 'spike'},
{x: 500, y: 350, width: 100, height: 30, type: 'spike'}
],
powerUps: [
{x: 100, y: 260, type: 'health'},
{x: 700, y: 260, type: 'health'},
{x: 400, y: 60, type: 'laser'},
{x: 300, y: 240, type: 'score'}
],
checkpoints: [
{x: 400, y: 350, width: 50, height: 30}
],
goal: {x: 400, y: 30, width: 50, height: 50}, // 放在中间上方
kidnappedPerson: {x: 400, y: 100}
}
];
// 初始化关卡
function initLevel(level) {
// 移除之前的玩家名字元素
if (player) {
player.removeNameElement();
}
// 移除之前的许子昂元素
if (kidnappedPerson && kidnappedPerson.element) {
kidnappedPerson.element.parentNode.removeChild(kidnappedPerson.element);
}
// 移除天神效果
if (godEffectElement && godEffectElement.parentNode) {
godEffectElement.parentNode.removeChild(godEffectElement);
godEffectElement = null;
}
platforms = [];
enemies = [];
coins = [];
hazards = [];
powerUps = [];
checkpoints = [];
kidnappedPerson = null;
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
));
}
// 创建金币
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);
// 创建被绑架的许子昂(只在最后一关)
if (config.kidnappedPerson) {
kidnappedPerson = new KidnappedPerson(config.kidnappedPerson.x, config.kidnappedPerson.y);
}
// 初始化玩家 - 根据屏幕尺寸调整初始位置
const startX = Math.min(50, canvas.width * 0.1);
const startY = canvas.height * 0.6; // 根据画布高度调整
player = new Player(startX, startY, '#3498db',
{left: 'a', right: 'd', up: 'w', skill: 'j', ability: 'q'},
'shoot');
// 重置游戏统计
gameStats = {
collectedCoins: 0,
killedEnemies: 0,
remainingLives: player.lives
};
// 重置检查点
checkpoint.active = false;
// 更新UI
playerLivesElement.textContent = player.lives;
currentLevelElement.textContent = currentLevel;
scoreValue.textContent = score;
// 调整屏幕尺寸
adjustForScreenSize();
}
// 开始特定关卡
function startLevel(level) {
currentLevel = level;
if (!unlockedLevels.includes(level)) {
unlockedLevels.push(level);
}
settingsScreen.style.display = 'none';
levelCompleteScreen.style.display = 'none';
pauseScreen.style.display = 'none';
dialogueScreen.style.display = 'none'; // 确保对话屏幕隐藏
initLevel(currentLevel);
gameRunning = true;
gamePaused = false;
// 显示剧情对话
if (currentLevel === 1) {
showDialogue([
{ speaker: "电话", text: "叮叮叮..." },
{ speaker: "董测浩", text: "喂喂喂!哪位?" },
{ speaker: "金文翔", text: "就你是许子昂大哥是吧?我跟你告诉你,你这个臭傻子,许子昂已经被我抓住了,杜宾犬级别,老弟,有本事就来抓我!" },
{ speaker: "董测浩", text: "可以,你这个老傻子还骂我杜宾犬是吧?行,老弟你等着,我这就过来了。" },
{ speaker: "旁白", text: "于是董测浩踏上了解救许子昂的旅程。" }
], function() {
// 对话结束后开始游戏
requestAnimationFrame(gameLoop);
});
} else if (currentLevel === 2) {
showDialogue([
{ speaker: "董测浩", text: "继续前进,我一定要救出许子昂!" }
], function() {
// 对话结束后开始游戏
requestAnimationFrame(gameLoop);
});
} else if (currentLevel === 3) {
showDialogue([
{ speaker: "董测浩", text: "快接近目标了,许子昂坚持住!" }
], function() {
// 对话结束后开始游戏
requestAnimationFrame(gameLoop);
});
} else if (currentLevel === 4) {
showDialogue([
{ speaker: "金文翔", text: "哟,宾犬竟然追过来了" },
{ speaker: "董测浩", text: "老狗屎头子,接受我的制裁吧。" },
{ speaker: "金文翔", text: "哈哈哈,许子昂就在牢笼里,有本事就来救他!" }
], function() {
// 对话结束后开始游戏
requestAnimationFrame(gameLoop);
});
} else {
showDialogue([
{ speaker: "董测浩", text: `第${currentLevel}关,离许子昂又近了一步!` }
], function() {
// 对话结束后开始游戏
requestAnimationFrame(gameLoop);
});
}
}
// 绘制背景
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(canvas.width, canvas.height - 100);
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(0, canvas.height);
ctx.closePath();
ctx.fill();
// 绘制太阳
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(canvas.width - 70, 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(canvas.width - 70, 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() {
// 显示玩家的道具状态
laserTimerElement.textContent = Math.ceil(player.powerUps.laser / 60);
shieldCountElement.textContent = player.powerUps.shield;
// 显示陈浩然天神模式时间
if (chenHaoranMode) {
godTimerElement.textContent = Math.ceil(chenHaoranTimer / 60);
} else {
godTimerElement.textContent = "0";
}
}
// 增加分数
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();
}
player.update(platforms, enemies, coins, hazards, powerUps, checkpoints);
for (let enemy of enemies) {
enemy.update(platforms, [player]);
// 检查玩家子弹与敌人碰撞
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();
// 更新被绑架的许子昂位置
if (kidnappedPerson) {
kidnappedPerson.updateElementPosition();
// 检查玩家是否接触到许子昂
kidnappedPerson.checkCollision(player);
}
// 更新伤害数字
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();
}
// 绘制被绑架的许子昂
if (kidnappedPerson) {
kidnappedPerson.draw();
}
goal.draw();
player.draw();
// 绘制伤害数字
drawDamagePopups();
// 更新道具显示
updatePowerUpDisplay();
// 检查关卡完成条件
if (goal.checkCollision(player)) {
// 如果是最后一关,需要击败Boss并且解救许子昂才能完成
if (currentLevel === totalLevels) {
let bossDefeated = true;
for (let enemy of enemies) {
if (enemy.type === 'boss' && !enemy.dead) {
bossDefeated = false;
break;
}
}
// 检查许子昂是否被解救
let rescued = kidnappedPerson ? kidnappedPerson.rescued : false;
if (bossDefeated && rescued) {
levelComplete();
}
} else {
levelComplete();
}
}
// 继续游戏循环
requestAnimationFrame(gameLoop);
}
// 关卡完成
function levelComplete() {
gameRunning = false;
// 解锁下一关
if (!unlockedLevels.includes(currentLevel + 1) && currentLevel < totalLevels) {
unlockedLevels.push(currentLevel + 1);
}
// 更新游戏统计
gameStats.remainingLives = player.lives;
collectedCoinsElement.textContent = gameStats.collectedCoins;
killedEnemiesElement.textContent = gameStats.killedEnemies;
remainingLivesElement.textContent = gameStats.remainingLives;
maxComboElement.textContent = maxCombo;
levelScoreElement.textContent = score;
// 如果是最后一关,显示特殊消息和开发者致谢
if (currentLevel === totalLevels) {
levelCompleteTitle.textContent = "大获全胜!";
levelCompleteText.textContent = "恭喜你成功解救许子昂!";
// 显示开发者致谢界面
setTimeout(() => {
levelCompleteScreen.style.display = 'none';
thanksScreen.style.display = 'flex';
}, 2000);
} else {
levelCompleteTitle.textContent = "关卡完成!";
levelCompleteText.textContent = "恭喜你通过了当前关卡!";
levelCompleteScreen.style.display = 'block';
}
}
// 游戏结束
function gameOver() {
gameRunning = false;
// 显示失败消息
showDialogue([
{ speaker: "金文翔", text: "哈哈哈,你这个老狗屎头子杜宾犬董测浩还想通关?" },
{ speaker: "董测浩", text: "可恶!我一定会再来的!" }
], function() {
// 延迟返回主菜单
setTimeout(() => {
startScreen.style.display = 'flex';
}, 2000);
});
}
// 从公告进入主菜单
function showMainMenu() {
announcementScreen.style.display = 'none';
startScreen.style.display = 'flex';
}
// 开始游戏(从主菜单开始)
function startGame() {
startScreen.style.display = 'none';
levelCompleteScreen.style.display = 'none';
pauseScreen.style.display = 'none';
currentLevel = 1;
score = 0;
scoreValue.textContent = score;
unlockedLevels = [1];
allLevelsUnlocked = false;
// 开始第一关
startLevel(currentLevel);
}
// 下一关
function nextLevel() {
currentLevel++;
if (currentLevel > totalLevels) {
alert('恭喜!你完成了所有关卡!');
startScreen.style.display = 'flex';
return;
}
levelCompleteScreen.style.display = 'none';
startLevel(currentLevel);
}
// 暂停游戏
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';
startLevel(currentLevel);
}
// 返回主菜单
function returnToMenu() {
pauseScreen.style.display = 'none';
settingsScreen.style.display = 'none';
thanksScreen.style.display = 'none';
startScreen.style.display = 'flex';
gameRunning = false;
// 移除玩家名字元素
if (player) {
player.removeNameElement();
}
}
// 打开设置界面
function openSettings() {
pauseScreen.style.display = 'none';
initLevelSelect();
settingsScreen.style.display = 'flex';
}
// 事件监听
continueBtn.addEventListener('click', showMainMenu);
startBtn.addEventListener('click', startGame);
nextLevelBtn.addEventListener('click', nextLevel);
resumeBtn.addEventListener('click', () => togglePause());
restartBtn.addEventListener('click', restartLevel);
menuBtn.addEventListener('click', returnToMenu);
menuBtn2.addEventListener('click', returnToMenu);
settingsBtn.addEventListener('click', openSettings);
settingsBtn2.addEventListener('click', openSettings);
dialogueNextBtn.addEventListener('click', showNextDialogue);
backToGameBtn.addEventListener('click', () => {
settingsScreen.style.display = 'none';
if (gameRunning) {
togglePause();
}
});
backToMenuBtn.addEventListener('click', returnToMenu);
thanksBackBtn.addEventListener('click', returnToMenu);
// 初始化移动端控制
initMobileControls();
// 初始化:显示公告屏幕
announcementScreen.style.display = 'flex';
// 初始调整屏幕尺寸
adjustForScreenSize();
// 页面加载完成后初始化
window.onload = function() {
adjustForScreenSize();
drawBackground(); // 绘制初始背景
};
</script>
</body>
</html>
index.html
style.css
index.js
md
README.md
index.html