LLM-test/test/code/3/minimax2.1-web.html

2314 lines
80 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>星际文明探索者 - Star Civilization Explorer</title>
<!-- 引入 Three.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<!-- 引入 GSAP 动画库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<!-- 引入 Howler.js 音频库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.4/howler.min.js"></script>
<!-- 引入字体 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #4CC9F0;
--secondary-color: #7B2CBF;
--accent-color: #F72585;
--warning-color: #FFD60A;
--bg-color: #050510;
--glass-bg: rgba(255, 255, 255, 0.05);
--glass-border: rgba(255, 255, 255, 0.1);
}
body {
overflow: hidden;
background: var(--bg-color);
font-family: 'Orbitron', sans-serif;
color: white;
}
/* 游戏画布 */
#game-canvas {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
/* 游戏UI层 */
#game-ui {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
}
/* 所有UI元素 */
.ui-element {
pointer-events: auto;
}
/* 磨砂玻璃面板 */
.glass-panel {
background: var(--glass-bg);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid var(--glass-border);
border-radius: 12px;
padding: 20px;
}
/* 状态栏 - 左上角 */
#status-bar {
position: absolute;
top: 20px;
left: 20px;
display: flex;
flex-direction: column;
gap: 12px;
}
.status-item {
display: flex;
align-items: center;
gap: 12px;
}
.status-icon {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
}
.status-bar-container {
width: 200px;
height: 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
overflow: hidden;
}
.status-bar {
height: 100%;
border-radius: 4px;
transition: width 0.3s ease;
}
.shield-bar {
background: linear-gradient(90deg, #4CC9F0, #00d4ff);
box-shadow: 0 0 10px #4CC9F0;
}
.health-bar {
background: linear-gradient(90deg, #F72585, #ff006e);
box-shadow: 0 0 10px #F72585;
}
.energy-bar {
background: linear-gradient(90deg, #FFD60A, #ffaa00);
box-shadow: 0 0 10px #FFD60A;
}
/* 资源面板 - 右上角 */
#resource-panel {
position: absolute;
top: 20px;
right: 20px;
text-align: right;
}
.resource-item {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
margin-bottom: 8px;
font-family: 'Share Tech Mono', monospace;
}
.resource-icon {
font-size: 24px;
}
.resource-count {
font-size: 20px;
font-weight: 700;
color: var(--warning-color);
text-shadow: 0 0 10px rgba(255, 214, 10, 0.5);
}
/* 准星 - 屏幕中央 */
#crosshair {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
pointer-events: none;
}
.crosshair-ring {
width: 100%;
height: 100%;
border: 2px solid rgba(76, 201, 240, 0.6);
border-radius: 50%;
position: relative;
animation: crosshairPulse 2s infinite;
}
.crosshair-ring::before,
.crosshair-ring::after {
content: '';
position: absolute;
background: var(--primary-color);
}
.crosshair-ring::before {
width: 4px;
height: 4px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
.crosshair-line {
position: absolute;
background: linear-gradient(90deg, transparent, var(--primary-color), transparent);
height: 1px;
}
.crosshair-line.horizontal {
width: 60px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.crosshair-line.vertical {
width: 1px;
height: 60px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@keyframes crosshairPulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.1); }
}
/* 交互提示 - 中下方 */
#interaction-prompt {
position: absolute;
bottom: 120px;
left: 50%;
transform: translateX(-50%);
text-align: center;
opacity: 0;
transition: opacity 0.3s ease;
}
#interaction-prompt.visible {
opacity: 1;
}
.prompt-text {
font-size: 16px;
color: var(--primary-color);
text-shadow: 0 0 20px rgba(76, 201, 240, 0.8);
animation: promptGlow 1s infinite alternate;
}
@keyframes promptGlow {
from { text-shadow: 0 0 20px rgba(76, 201, 240, 0.8); }
to { text-shadow: 0 0 30px rgba(76, 201, 240, 1), 0 0 40px rgba(76, 201, 240, 0.5); }
}
/* 消息日志 - 左下角 */
#message-log {
position: absolute;
bottom: 20px;
left: 20px;
max-width: 400px;
display: flex;
flex-direction: column;
gap: 8px;
}
.log-message {
padding: 10px 15px;
background: rgba(0, 0, 0, 0.6);
border-radius: 8px;
font-size: 14px;
font-family: 'Share Tech Mono', monospace;
border-left: 3px solid var(--primary-color);
animation: logSlideIn 0.3s ease, logFadeOut 0.5s ease 4s forwards;
}
.log-message.success {
border-left-color: #00ff88;
}
.log-message.warning {
border-left-color: var(--warning-color);
}
.log-message.danger {
border-left-color: var(--accent-color);
}
@keyframes logSlideIn {
from { transform: translateX(-20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes logFadeOut {
to { opacity: 0; transform: translateX(-10px); }
}
/* 小地图 - 右下角 */
#minimap {
position: absolute;
bottom: 20px;
right: 20px;
width: 180px;
height: 180px;
border-radius: 50%;
overflow: hidden;
}
#minimap-canvas {
width: 100%;
height: 100%;
background: rgba(5, 5, 16, 0.8);
}
/* 升级面板 - 居中 */
#upgrade-panel {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.9);
opacity: 0;
pointer-events: none;
transition: all 0.3s ease;
z-index: 100;
}
#upgrade-panel.visible {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
pointer-events: auto;
}
.upgrade-title {
font-size: 28px;
font-weight: 900;
text-align: center;
margin-bottom: 30px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.upgrade-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.upgrade-card {
background: rgba(255, 255, 255, 0.03);
border: 1px solid var(--glass-border);
border-radius: 12px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.upgrade-card:hover {
background: rgba(255, 255, 255, 0.08);
border-color: var(--primary-color);
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(76, 201, 240, 0.2);
}
.upgrade-icon {
font-size: 40px;
margin-bottom: 10px;
}
.upgrade-name {
font-size: 14px;
font-weight: 700;
margin-bottom: 8px;
}
.upgrade-level {
font-size: 12px;
color: var(--primary-color);
margin-bottom: 10px;
}
.upgrade-cost {
font-size: 12px;
color: var(--warning-color);
}
.upgrade-btn {
margin-top: 20px;
padding: 12px 30px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
border: none;
border-radius: 8px;
color: white;
font-family: 'Orbitron', sans-serif;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
.upgrade-btn:hover {
transform: scale(1.05);
box-shadow: 0 0 20px rgba(76, 201, 240, 0.5);
}
/* 暂停菜单 */
#pause-menu {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
opacity: 0;
pointer-events: none;
transition: all 0.3s ease;
z-index: 100;
}
#pause-menu.visible {
opacity: 1;
pointer-events: auto;
}
.pause-title {
font-size: 48px;
font-weight: 900;
margin-bottom: 40px;
text-shadow: 0 0 30px var(--primary-color);
}
.pause-btn {
display: block;
width: 250px;
margin: 15px auto;
padding: 15px 30px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--glass-border);
border-radius: 8px;
color: white;
font-family: 'Orbitron', sans-serif;
font-size: 16px;
cursor: pointer;
transition: all 0.3s ease;
}
.pause-btn:hover {
background: rgba(255, 255, 255, 0.1);
border-color: var(--primary-color);
transform: scale(1.05);
}
/* 控制说明 */
#controls-info {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
text-align: center;
}
.key {
display: inline-block;
padding: 4px 8px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
margin: 0 4px;
font-family: 'Share Tech Mono', monospace;
}
/* 开始界面 */
#start-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(180deg, #050510 0%, #0a0a20 50%, #050510 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 1000;
transition: opacity 0.5s ease;
}
#start-screen.hidden {
opacity: 0;
pointer-events: none;
}
.game-title {
font-size: 64px;
font-weight: 900;
margin-bottom: 20px;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color), var(--accent-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: titleGlow 3s infinite alternate;
text-align: center;
}
.game-subtitle {
font-size: 18px;
color: rgba(255, 255, 255, 0.6);
margin-bottom: 50px;
}
@keyframes titleGlow {
from { filter: drop-shadow(0 0 20px rgba(76, 201, 240, 0.5)); }
to { filter: drop-shadow(0 0 40px rgba(123, 44, 191, 0.8)); }
}
.start-btn {
padding: 20px 60px;
font-size: 20px;
font-weight: 700;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
border: none;
border-radius: 50px;
color: white;
font-family: 'Orbitron', sans-serif;
cursor: pointer;
transition: all 0.3s ease;
margin: 10px;
}
.start-btn:hover {
transform: scale(1.1);
box-shadow: 0 0 40px rgba(76, 201, 240, 0.6);
}
.controls-list {
margin-top: 50px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
text-align: left;
}
.control-item {
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
}
.control-item .key {
background: rgba(76, 201, 240, 0.2);
color: var(--primary-color);
border: 1px solid rgba(76, 201, 240, 0.3);
}
/* 警告提示 */
#warning-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(ellipse at center, transparent 0%, rgba(247, 37, 133, 0) 100%);
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 50;
}
#warning-overlay.active {
opacity: 1;
animation: warningPulse 0.5s infinite;
}
@keyframes warningPulse {
0%, 100% { background: radial-gradient(ellipse at center, transparent 0%, rgba(247, 37, 133, 0.1) 100%); }
50% { background: radial-gradient(ellipse at center, transparent 0%, rgba(247, 37, 133, 0.3) 100%); }
}
/* 战斗统计 */
#combat-stats {
position: absolute;
top: 100px;
right: 20px;
font-family: 'Share Tech Mono', monospace;
text-align: right;
}
.combat-stat {
font-size: 14px;
margin-bottom: 5px;
opacity: 0.8;
}
.combat-stat-value {
color: var(--accent-color);
font-weight: 700;
}
/* 经验值显示 */
#exp-display {
position: absolute;
bottom: 60px;
left: 50%;
transform: translateX(-50%);
text-align: center;
}
.exp-bar-container {
width: 300px;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
overflow: hidden;
margin-bottom: 8px;
}
.exp-bar {
height: 100%;
background: linear-gradient(90deg, var(--secondary-color), var(--accent-color));
border-radius: 3px;
transition: width 0.3s ease;
}
.exp-text {
font-size: 12px;
color: rgba(255, 255, 255, 0.6);
}
/* 响应式设计 */
@media (max-width: 768px) {
.game-title {
font-size: 36px;
}
#status-bar {
top: 10px;
left: 10px;
}
.status-bar-container {
width: 120px;
}
#resource-panel {
top: 10px;
right: 10px;
}
.controls-list {
display: none;
}
}
</style>
</head>
<body>
<!-- 游戏画布 -->
<canvas id="game-canvas"></canvas>
<!-- 游戏UI层 -->
<div id="game-ui">
<!-- 开始界面 -->
<div id="start-screen">
<h1 class="game-title">星际文明探索者</h1>
<p class="game-subtitle">Star Civilization Explorer</p>
<button class="start-btn" id="start-btn">开始探索</button>
<div class="controls-list">
<div class="control-item"><span class="key">W</span><span class="key">A</span><span class="key">S</span><span class="key">D</span> 移动飞船</div>
<div class="control-item"><span class="key">鼠标</span> 瞄准方向</div>
<div class="control-item"><span class="key">左键</span> 发射激光</div>
<div class="control-item"><span class="key">E</span> 采集资源</div>
<div class="control-item"><span class="key">空格</span> 释放技能</div>
<div class="control-item"><span class="key">U</span> 升级面板</div>
<div class="control-item"><span class="key">ESC</span> 暂停游戏</div>
</div>
</div>
<!-- 状态栏 -->
<div id="status-bar" class="ui-element" style="display: none;">
<div class="status-item">
<div class="status-icon">🛡️</div>
<div class="status-bar-container">
<div class="status-bar shield-bar" id="shield-bar" style="width: 100%;"></div>
</div>
<span id="shield-text">100%</span>
</div>
<div class="status-item">
<div class="status-icon">❤️</div>
<div class="status-bar-container">
<div class="status-bar health-bar" id="health-bar" style="width: 100%;"></div>
</div>
<span id="health-text">100%</span>
</div>
<div class="status-item">
<div class="status-icon"></div>
<div class="status-bar-container">
<div class="status-bar energy-bar" id="energy-bar" style="width: 100%;"></div>
</div>
<span id="energy-text">100%</span>
</div>
</div>
<!-- 资源面板 -->
<div id="resource-panel" class="ui-element" style="display: none;">
<div class="resource-item">
<span class="resource-count" id="crystal-count">0</span>
<span class="resource-icon">💎</span>
</div>
<div class="resource-item">
<span class="resource-count" id="ore-count">0</span>
<span class="resource-icon">🪨</span>
</div>
<div class="resource-item">
<span class="resource-count" id="relic-count">0</span>
<span class="resource-icon">🔮</span>
</div>
</div>
<!-- 准星 -->
<div id="crosshair" style="display: none;">
<div class="crosshair-ring"></div>
<div class="crosshair-line horizontal"></div>
<div class="crosshair-line vertical"></div>
</div>
<!-- 交互提示 -->
<div id="interaction-prompt" class="ui-element">
<span class="prompt-text" id="prompt-text">按 E 采集资源</span>
</div>
<!-- 消息日志 -->
<div id="message-log"></div>
<!-- 战斗统计 -->
<div id="combat-stats" class="ui-element" style="display: none;">
<div class="combat-stat">击毁: <span class="combat-stat-value" id="kill-count">0</span></div>
<div class="combat-stat">伤害: <span class="combat-stat-value" id="damage-count">0</span></div>
</div>
<!-- 经验值显示 -->
<div id="exp-display" class="ui-element" style="display: none;">
<div class="exp-bar-container">
<div class="exp-bar" id="exp-bar" style="width: 0%;"></div>
</div>
<span class="exp-text">等级 <span id="level-text">1</span></span>
</div>
<!-- 升级面板 -->
<div id="upgrade-panel" class="glass-panel ui-element">
<h2 class="upgrade-title">🚀 飞船升级</h2>
<div class="upgrade-grid">
<div class="upgrade-card" data-upgrade="engine">
<div class="upgrade-icon">🔥</div>
<div class="upgrade-name">推进系统</div>
<div class="upgrade-level" id="engine-level">等级 1</div>
<div class="upgrade-cost" id="engine-cost">消耗: 10 晶体</div>
</div>
<div class="upgrade-card" data-upgrade="shield">
<div class="upgrade-icon">🛡️</div>
<div class="upgrade-name">能量护盾</div>
<div class="upgrade-level" id="shield-level">等级 1</div>
<div class="upgrade-cost" id="shield-cost">消耗: 10 晶体</div>
</div>
<div class="upgrade-card" data-upgrade="weapon">
<div class="upgrade-icon">🔫</div>
<div class="upgrade-name">激光武器</div>
<div class="upgrade-level" id="weapon-level">等级 1</div>
<div class="upgrade-cost" id="weapon-cost">消耗: 10 晶体</div>
</div>
<div class="upgrade-card" data-upgrade="scanner">
<div class="upgrade-icon">📡</div>
<div class="upgrade-name">扫描系统</div>
<div class="upgrade-level" id="scanner-level">等级 1</div>
<div class="upgrade-cost" id="scanner-cost">消耗: 10 晶体</div>
</div>
<div class="upgrade-card" data-upgrade="cargo">
<div class="upgrade-icon">📦</div>
<div class="upgrade-name">货舱容量</div>
<div class="upgrade-level" id="cargo-level">等级 1</div>
<div class="upgrade-cost" id="cargo-cost">消耗: 10 晶体</div>
</div>
<div class="upgrade-card" data-upgrade="skill">
<div class="upgrade-icon"></div>
<div class="upgrade-name">特殊技能</div>
<div class="upgrade-level" id="skill-level">等级 1</div>
<div class="upgrade-cost" id="skill-cost">消耗: 10 晶体</div>
</div>
</div>
<button class="upgrade-btn" id="close-upgrade">关闭</button>
</div>
<!-- 暂停菜单 -->
<div id="pause-menu" class="ui-element">
<h2 class="pause-title">⏸️ 暂停</h2>
<button class="pause-btn" id="resume-btn">继续游戏</button>
<button class="pause-btn" id="restart-btn">重新开始</button>
<button class="pause-btn" id="quit-btn">退出游戏</button>
</div>
<!-- 小地图 -->
<div id="minimap" class="ui-element" style="display: none;">
<canvas id="minimap-canvas"></canvas>
</div>
<!-- 控制说明 -->
<div id="controls-info" class="ui-element" style="display: none;">
<span class="key">WASD</span> 移动 |
<span class="key">鼠标</span> 瞄准 |
<span class="key">左键</span> 射击 |
<span class="key">E</span> 采集 |
<span class="key">U</span> 升级 |
<span class="key">ESC</span> 暂停
</div>
<!-- 警告遮罩 -->
<div id="warning-overlay"></div>
</div>
<script>
// ==================== 游戏主配置 ====================
const CONFIG = {
// 宇宙参数
UNIVERSE_SIZE: 5000,
STAR_COUNT: 3000,
PLANET_COUNT: 50,
ASTEROID_COUNT: 200,
ENEMY_COUNT: 30,
// 飞船参数
SHIP_SPEED: 50,
SHIP_ACCELERATION: 100,
SHIP_FRICTION: 0.98,
SHIP_TILT_FACTOR: 0.05,
// 战斗参数
LASER_SPEED: 200,
LASER_DAMAGE: 25,
LASER_COOLDOWN: 0.15,
SKILL_COOLDOWN: 30,
// 资源参数
RESOURCE_MAX_CARGO: 100,
HARVEST_SPEED: 10,
// 升级参数
BASE_UPGRADE_COST: 10,
UPGRADE_COST_MULTIPLIER: 1.5,
};
// ==================== 游戏状态 ====================
const gameState = {
isPlaying: false,
isPaused: false,
isUpgrading: false,
lastTime: 0,
// 玩家状态
player: {
health: 100,
maxHealth: 100,
shield: 100,
maxShield: 100,
energy: 100,
maxEnergy: 100,
exp: 0,
maxExp: 100,
level: 1,
// 资源
crystals: 0,
ores: 0,
relics: 0,
// 升级等级
upgrades: {
engine: 1,
shield: 1,
weapon: 1,
scanner: 1,
cargo: 1,
skill: 1
}
},
// 战斗统计
combat: {
kills: 0,
totalDamage: 0,
laserCooldown: 0,
skillCooldown: 0,
skillActive: false
},
// 交互状态
interaction: {
target: null,
type: null,
progress: 0
}
};
// ==================== Three.js 全局变量 ====================
let scene, camera, renderer;
let playerShip, playerLight;
let stars, starField;
let planets = [];
let asteroids = [];
let enemies = [];
let lasers = [];
let particles = [];
let spaceDust = [];
// ==================== 输入状态 ====================
const input = {
keys: {},
mouse: { x: 0, y: 0, down: false },
mouseWorld: new THREE.Vector3()
};
// ==================== 初始化 Three.js ====================
function initThree() {
const canvas = document.getElementById('game-canvas');
// 创建场景
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x050510, 0.0008);
// 创建相机
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 50, 100);
// 创建渲染器
renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setClearColor(0x050510);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;
// 添加光照
const ambientLight = new THREE.AmbientLight(0x404060, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(100, 100, 50);
scene.add(directionalLight);
// 创建星空背景
createStarField();
// 创建空间尘埃
createSpaceDust();
// 创建玩家飞船
createPlayerShip();
// 创建宇宙天体
createPlanets();
createAsteroids();
createEnemies();
// 事件监听
window.addEventListener('resize', onWindowResize);
// 开始渲染循环
animate();
}
// ==================== 星空背景 ====================
function createStarField() {
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const sizes = [];
for (let i = 0; i < CONFIG.STAR_COUNT; i++) {
const x = (Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE * 2;
const y = (Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE * 2;
const z = (Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE * 2;
positions.push(x, y, z);
// 星星颜色(蓝白色为主,带有彩色点缀)
const colorChoice = Math.random();
let color;
if (colorChoice < 0.6) {
color = new THREE.Color(0xffffff);
} else if (colorChoice < 0.8) {
color = new THREE.Color(0x4CC9F0);
} else if (colorChoice < 0.95) {
color = new THREE.Color(0xFFD60A);
} else {
color = new THREE.Color(0xF72585);
}
colors.push(color.r, color.g, color.b);
sizes.push(Math.random() * 2 + 0.5);
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1));
const material = new THREE.PointsMaterial({
size: 2,
vertexColors: true,
transparent: true,
opacity: 0.8,
sizeAttenuation: true
});
stars = new THREE.Points(geometry, material);
scene.add(stars);
}
// ==================== 空间尘埃 ====================
function createSpaceDust() {
const geometry = new THREE.BufferGeometry();
const positions = [];
for (let i = 0; i < 1000; i++) {
const x = (Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE * 2;
const y = (Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE * 2;
const z = (Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE * 2;
positions.push(x, y, z);
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
const material = new THREE.PointsMaterial({
size: 1,
color: 0x4CC9F0,
transparent: true,
opacity: 0.3,
sizeAttenuation: true
});
spaceDust = new THREE.Points(geometry, material);
scene.add(spaceDust);
}
// ==================== 玩家飞船 ====================
function createPlayerShip() {
const group = new THREE.Group();
// 飞船主体
const bodyGeometry = new THREE.ConeGeometry(2, 8, 8);
const bodyMaterial = new THREE.MeshStandardMaterial({
color: 0x4CC9F0,
metalness: 0.8,
roughness: 0.2,
emissive: 0x4CC9F0,
emissiveIntensity: 0.2
});
const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
body.rotation.x = Math.PI / 2;
group.add(body);
// 飞船机翼
const wingGeometry = new THREE.BoxGeometry(8, 0.2, 3);
const wingMaterial = new THREE.MeshStandardMaterial({
color: 0x7B2CBF,
metalness: 0.6,
roughness: 0.3
});
const wing = new THREE.Mesh(wingGeometry, wingMaterial);
wing.position.z = 1;
group.add(wing);
// 引擎发光部分
const engineGeometry = new THREE.CylinderGeometry(0.8, 1.2, 2, 8);
const engineMaterial = new THREE.MeshStandardMaterial({
color: 0xF72585,
emissive: 0xF72585,
emissiveIntensity: 1
});
const engine = new THREE.Mesh(engineGeometry, engineMaterial);
engine.rotation.x = Math.PI / 2;
engine.position.z = 4;
group.add(engine);
// 引擎光源
playerLight = new THREE.PointLight(0xF72585, 2, 30);
playerLight.position.z = 5;
group.add(playerLight);
// 飞船初始位置
group.position.set(0, 0, 0);
// 添加物理属性
group.userData = {
velocity: new THREE.Vector3(),
acceleration: new THREE.Vector3()
};
playerShip = group;
scene.add(playerShip);
}
// ==================== 行星创建 ====================
function createPlanets() {
for (let i = 0; i < CONFIG.PLANET_COUNT; i++) {
const planet = createRandomPlanet();
planets.push(planet);
scene.add(planet);
}
}
function createRandomPlanet() {
const group = new THREE.Group();
// 随机大小和颜色
const radius = Math.random() * 20 + 10;
const colors = [0x4CC9F0, 0x7B2CBF, 0xF72585, 0xFFD60A, 0x00ff88, 0xff6b6b, 0xc44dff];
const baseColor = colors[Math.floor(Math.random() * colors.length)];
// 行星主体
const geometry = new THREE.SphereGeometry(radius, 32, 32);
const material = new THREE.MeshStandardMaterial({
color: baseColor,
metalness: 0.3,
roughness: 0.7,
emissive: baseColor,
emissiveIntensity: 0.1
});
const planet = new THREE.Mesh(geometry, material);
group.add(planet);
// 大气层光环
const atmosphereGeometry = new THREE.SphereGeometry(radius * 1.2, 32, 32);
const atmosphereMaterial = new THREE.MeshBasicMaterial({
color: baseColor,
transparent: true,
opacity: 0.15,
side: THREE.BackSide
});
const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
group.add(atmosphere);
// 随机位置
group.position.set(
(Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE,
(Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE,
(Math.random() - 0.5) * CONFIG.UNIVERSE_SIZE
);
// 随机自转
group.userData = {
type: 'planet',
radius: radius,
color: baseColor,
rotationSpeed: (Math.random() - 0.5) * 0.01,
hasResources: Math.random() > 0.3,
resourceType: ['crystal', 'ore', 'relic'][Math.floor(Math.random() * 3)],
resourceAmount: Math.floor(Math.random() * 50) + 20,
name: `行星-${Math.floor(Math.random() * 9999)}`,
scanned: false
};
return group;
}
// ==================== 小行星带 ====================
function createAsteroids() {
for (let i = 0; i < CONFIG.ASTEROID_COUNT; i++) {
const asteroid = createRandomAsteroid();
asteroids.push(asteroid);
scene.add(asteroid);
}
}
function createRandomAsteroid() {
const geometry = new THREE.DodecahedronGeometry(Math.random() * 3 + 1, 0);
const material = new THREE.MeshStandardMaterial({
color: 0x666666,
metalness: 0.5,
roughness: 0.8
});
const asteroid = new THREE.Mesh(geometry, material);
// 在特定区域生成小行星
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * 500 + 200;
asteroid.position.set(
Math.cos(angle) * distance,
(Math.random() - 0.5) * 100,
Math.sin(angle) * distance
);
asteroid.userData = {
type: 'asteroid',
health: 50,
rotationSpeed: (Math.random() - 0.5) * 0.02
};
return asteroid;
}
// ==================== 敌人创建 ====================
function createEnemies() {
for (let i = 0; i < CONFIG.ENEMY_COUNT; i++) {
const enemy = createRandomEnemy();
enemies.push(enemy);
scene.add(enemy);
}
}
function createRandomEnemy() {
const group = new THREE.Group();
// 敌机主体
const geometry = new THREE.OctahedronGeometry(3, 0);
const material = new THREE.MeshStandardMaterial({
color: 0xF72585,
metalness: 0.7,
roughness: 0.3,
emissive: 0xF72585,
emissiveIntensity: 0.3
});
const body = new THREE.Mesh(geometry, material);
group.add(body);
// 敌机光源
const light = new THREE.PointLight(0xF72585, 1, 20);
light.position.y = 2;
group.add(light);
// 随机位置(在玩家周围)
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * 500 + 300;
group.position.set(
Math.cos(angle) * distance,
(Math.random() - 0.5) * 200,
Math.sin(angle) * distance
);
group.userData = {
type: 'enemy',
health: 100,
maxHealth: 100,
speed: 20 + Math.random() * 20,
rotationSpeed: 0.02,
lastShot: 0,
shootCooldown: 2 + Math.random() * 2
};
return group;
}
// ==================== 激光系统 ====================
function createLaser(from, to, isEnemy = false) {
const start = from.clone();
const end = to.clone();
const direction = new THREE.Vector3().subVectors(end, start).normalize();
const distance = start.distanceTo(end);
const geometry = new THREE.CylinderGeometry(0.2, 0.2, distance, 8);
const material = new THREE.MeshBasicMaterial({
color: isEnemy ? 0xFF0000 : 0x4CC9F0,
transparent: true,
opacity: 0.8
});
const laser = new THREE.Mesh(geometry, material);
laser.position.copy(start).add(direction.multiplyScalar(distance / 2));
laser.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), direction);
laser.userData = {
start: start,
end: end,
direction: direction,
speed: CONFIG.LASER_SPEED,
damage: isEnemy ? 10 : CONFIG.LASER_DAMAGE * gameState.player.upgrades.weapon,
isEnemy: isEnemy,
createdAt: gameState.lastTime
};
lasers.push(laser);
scene.add(laser);
// 创建激光粒子尾迹
createLaserTrail(start, isEnemy);
return laser;
}
function createLaserTrail(position, isEnemy) {
for (let i = 0; i < 5; i++) {
const particle = createParticle(
position.clone().add(new THREE.Vector3(
(Math.random() - 0.5) * 2,
(Math.random() - 0.5) * 2,
(Math.random() - 0.5) * 2
)),
isEnemy ? 0xFF0000 : 0x4CC9F0,
0.5
);
particle.userData.velocity = new THREE.Vector3(
(Math.random() - 0.5) * 10,
(Math.random() - 0.5) * 10,
(Math.random() - 0.5) * 10
);
}
}
// ==================== 粒子系统 ====================
function createParticle(position, color, life = 1) {
const geometry = new THREE.SphereGeometry(0.3, 4, 4);
const material = new THREE.MeshBasicMaterial({
color: color,
transparent: true,
opacity: 1
});
const particle = new THREE.Mesh(geometry, material);
particle.position.copy(position);
particle.userData = {
life: life,
maxLife: life,
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 5,
(Math.random() - 0.5) * 5,
(Math.random() - 0.5) * 5
)
};
particles.push(particle);
scene.add(particle);
return particle;
}
function createExplosion(position, color = 0xF72585, count = 20) {
for (let i = 0; i < count; i++) {
const particle = createParticle(position.clone(), color, 1.5);
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * 30 + 10;
particle.userData.velocity = new THREE.Vector3(
Math.cos(angle) * speed,
(Math.random() - 0.5) * speed,
Math.sin(angle) * speed
);
}
// 创建冲击波
createShockwave(position);
}
function createShockwave(position) {
const geometry = new THREE.RingGeometry(0.5, 1, 32);
const material = new THREE.MeshBasicMaterial({
color: 0x4CC9F0,
transparent: true,
opacity: 0.8,
side: THREE.DoubleSide
});
const shockwave = new THREE.Mesh(geometry, material);
shockwave.position.copy(position);
shockwave.lookAt(camera.position);
shockwave.userData = {
type: 'shockwave',
life: 0.5,
maxLife: 0.5
};
particles.push(shockwave);
scene.add(shockwave);
}
// ==================== 引擎尾焰 ====================
function createEngineTrail() {
const trailPos = playerShip.position.clone();
trailPos.z += 6;
trailPos.add(new THREE.Vector3(
(Math.random() - 0.5) * 2,
(Math.random() - 0.5) * 2,
0
));
const particle = createParticle(trailPos, 0xF72585, 0.3);
particle.userData.velocity = new THREE.Vector3(0, 0, -20);
}
// ==================== UI 更新 ====================
function updateUI() {
// 状态栏
const shieldPercent = (gameState.player.shield / gameState.player.maxShield) * 100;
const healthPercent = (gameState.player.health / gameState.player.maxHealth) * 100;
const energyPercent = (gameState.player.energy / gameState.player.maxEnergy) * 100;
document.getElementById('shield-bar').style.width = shieldPercent + '%';
document.getElementById('health-bar').style.width = healthPercent + '%';
document.getElementById('energy-bar').style.width = energyPercent + '%';
document.getElementById('shield-text').textContent = Math.round(shieldPercent) + '%';
document.getElementById('health-text').textContent = Math.round(healthPercent) + '%';
document.getElementById('energy-text').textContent = Math.round(energyPercent) + '%';
// 资源
document.getElementById('crystal-count').textContent = gameState.player.crystals;
document.getElementById('ore-count').textContent = gameState.player.ores;
document.getElementById('relic-count').textContent = gameState.player.relics;
// 经验
const expPercent = (gameState.player.exp / gameState.player.maxExp) * 100;
document.getElementById('exp-bar').style.width = expPercent + '%';
document.getElementById('level-text').textContent = gameState.player.level;
// 战斗统计
document.getElementById('kill-count').textContent = gameState.combat.kills;
document.getElementById('damage-count').textContent = Math.floor(gameState.combat.totalDamage);
// 警告
const warningOverlay = document.getElementById('warning-overlay');
if (healthPercent < 30) {
warningOverlay.classList.add('active');
} else {
warningOverlay.classList.remove('active');
}
// 技能冷却
if (gameState.combat.skillCooldown > 0) {
document.getElementById('energy-text').textContent = `CD: ${Math.ceil(gameState.combat.skillCooldown)}s`;
}
}
// ==================== 消息系统 ====================
function showMessage(text, type = 'info') {
const log = document.getElementById('message-log');
const message = document.createElement('div');
message.className = `log-message ${type}`;
message.textContent = text;
log.appendChild(message);
setTimeout(() => {
message.remove();
}, 4500);
}
// ==================== 交互系统 ====================
function checkInteractions(deltaTime) {
let nearestTarget = null;
let nearestDistance = Infinity;
let interactionType = null;
// 检查行星
for (const planet of planets) {
if (!planet.userData.hasResources) continue;
const distance = playerShip.position.distanceTo(planet.position);
if (distance < planet.userData.radius + 50 && distance < nearestDistance) {
nearestTarget = planet;
nearestDistance = distance;
interactionType = 'harvest';
}
}
// 更新交互状态
gameState.interaction.target = nearestTarget;
gameState.interaction.type = interactionType;
const promptEl = document.getElementById('interaction-prompt');
const promptText = document.getElementById('prompt-text');
if (nearestTarget && interactionType === 'harvest') {
const resourceName = {
'crystal': '高能晶体',
'ore': '稀有矿物',
'relic': '古老遗迹碎片'
};
promptText.textContent = `按 E 采集 ${resourceName[nearestTarget.userData.resourceType]}`;
promptEl.classList.add('visible');
} else {
promptEl.classList.remove('visible');
}
}
function performInteraction() {
const { target, type } = gameState.interaction;
if (!target || type !== 'harvest') return;
const data = target.userData;
if (!data.hasResources) return;
// 采集资源
const amount = Math.floor(Math.random() * 5) + 3;
const resourceType = data.resourceType;
if (resourceType === 'crystal') {
gameState.player.crystals += amount;
} else if (resourceType === 'ore') {
gameState.player.ores += amount;
} else {
gameState.player.relics += amount;
}
data.resourceAmount -= amount;
if (data.resourceAmount <= 0) {
data.hasResources = false;
// 改变星球外观表示已采集
target.children[0].material.emissiveIntensity = 0;
}
showMessage(`获得: ${resourceType} x${amount}`, 'success');
// 采集特效
createExplosion(playerShip.position.clone().add(new THREE.Vector3(0, 0, -10)), 0xFFD60A, 10);
// 获得经验
gainExp(amount * 2);
updateUI();
}
// ==================== 经验系统 ====================
function gainExp(amount) {
gameState.player.exp += amount;
if (gameState.player.exp >= gameState.player.maxExp) {
levelUp();
}
updateUI();
}
function levelUp() {
gameState.player.level++;
gameState.player.exp = gameState.player.exp - gameState.player.maxExp;
gameState.player.maxExp = Math.floor(gameState.player.maxExp * 1.5);
// 属性提升
gameState.player.maxHealth += 20;
gameState.player.maxShield += 20;
gameState.player.health = gameState.player.maxHealth;
gameState.player.shield = gameState.player.maxShield;
showMessage(`等级提升!当前等级: ${gameState.player.level}`, 'success');
// 升级特效
createExplosion(playerShip.position, 0x4CC9F0, 50);
}
// ==================== 战斗系统 ====================
function updateCombat(deltaTime) {
// 激光冷却
if (gameState.combat.laserCooldown > 0) {
gameState.combat.laserCooldown -= deltaTime;
}
// 技能冷却
if (gameState.combat.skillCooldown > 0) {
gameState.combat.skillCooldown -= deltaTime;
}
// 能量恢复
if (gameState.player.energy < gameState.player.maxEnergy) {
gameState.player.energy += deltaTime * 5;
if (gameState.player.energy > gameState.player.maxEnergy) {
gameState.player.energy = gameState.player.maxEnergy;
}
}
// 护盾恢复
if (gameState.player.shield < gameState.player.maxShield && gameState.player.energy > 10) {
gameState.player.shield += deltaTime * 2;
}
// 更新激光
for (let i = lasers.length - 1; i >= 0; i--) {
const laser = lasers[i];
const data = laser.userData;
// 激光移动
const moveDistance = data.speed * deltaTime;
laser.position.add(data.direction.clone().multiplyScalar(moveDistance));
// 激光生命周期
if (gameState.lastTime - data.createdAt > 3) {
removeLaser(i);
continue;
}
// 碰撞检测
if (!data.isEnemy) {
// 检测敌机
for (let j = enemies.length - 1; j >= 0; j--) {
const enemy = enemies[j];
if (laser.position.distanceTo(enemy.position) < 5) {
damageEnemy(enemy, data.damage);
removeLaser(i);
break;
}
}
// 检测小行星
for (let j = asteroids.length - 1; j >= 0; j--) {
const asteroid = asteroids[j];
if (laser.position.distanceTo(asteroid.position) < 3) {
damageAsteroid(asteroid, data.damage);
removeLaser(i);
break;
}
}
} else {
// 检测玩家
if (laser.position.distanceTo(playerShip.position) < 3) {
damagePlayer(data.damage);
removeLaser(i);
}
}
}
// 更新敌人AI
updateEnemyAI(deltaTime);
}
function updateEnemyAI(deltaTime) {
const now = gameState.lastTime;
for (const enemy of enemies) {
const data = enemy.userData;
// 追踪玩家
const toPlayer = new THREE.Vector3().subVectors(playerShip.position, enemy.position);
const distance = toPlayer.length();
if (distance > 100) {
toPlayer.normalize();
enemy.position.add(toPlayer.multiplyScalar(data.speed * deltaTime));
}
// 转向玩家
enemy.lookAt(playerShip.position);
// 射击
if (distance < 300 && now - data.lastShot > data.shootCooldown) {
data.lastShot = now;
const direction = toPlayer.normalize();
const target = enemy.position.clone().add(direction.multiplyScalar(100));
createLaser(enemy.position, target, true);
}
// 自转动画
enemy.rotation.x += data.rotationSpeed;
enemy.rotation.y += data.rotationSpeed;
}
}
function damageEnemy(enemy, damage) {
enemy.userData.health -= damage;
createExplosion(enemy.position, 0xF72585, 10);
gameState.combat.totalDamage += damage;
if (enemy.userData.health <= 0) {
destroyEnemy(enemy);
}
updateUI();
}
function destroyEnemy(enemy) {
createExplosion(enemy.position, 0xF72585, 30);
// 掉落资源
const dropType = Math.random();
if (dropType < 0.6) {
gameState.player.crystals += Math.floor(Math.random() * 10) + 5;
showMessage('获得: 高能晶体 x' + (Math.floor(Math.random() * 10) + 5), 'success');
} else if (dropType < 0.9) {
gameState.player.ores += Math.floor(Math.random() * 5) + 3;
showMessage('获得: 稀有矿物 x' + (Math.floor(Math.random() * 5) + 3), 'success');
} else {
gameState.player.relics += 1;
showMessage('获得: 古老遗迹碎片 x1', 'success');
}
// 经验奖励
gainExp(50);
// 移除敌人
const index = enemies.indexOf(enemy);
if (index > -1) {
enemies.splice(index, 1);
}
scene.remove(enemy);
gameState.combat.kills++;
updateUI();
}
function damageAsteroid(asteroid, damage) {
asteroid.userData.health -= damage;
createExplosion(asteroid.position, 0x888888, 5);
if (asteroid.userData.health <= 0) {
destroyAsteroid(asteroid);
}
}
function destroyAsteroid(asteroid) {
createExplosion(asteroid.position, 0x666666, 15);
// 获得少量矿石
gameState.player.ores += Math.floor(Math.random() * 3) + 1;
const index = asteroids.indexOf(asteroid);
if (index > -1) {
asteroids.splice(index, 1);
}
scene.remove(asteroid);
updateUI();
}
function damagePlayer(damage) {
// 先扣除护盾
if (gameState.player.shield > 0) {
gameState.player.shield -= damage;
if (gameState.player.shield < 0) {
gameState.player.health += gameState.player.shield;
gameState.player.shield = 0;
}
} else {
gameState.player.health -= damage;
}
createExplosion(playerShip.position.clone().add(new THREE.Vector3(0, 0, -5)), 0xFF0000, 10);
// 屏幕震动效果
gsap.to(camera.position, {
x: camera.position.x + (Math.random() - 0.5) * 2,
y: camera.position.y + (Math.random() - 0.5) * 2,
duration: 0.05,
onComplete: () => {
gsap.to(camera.position, {
x: playerShip.position.x,
y: playerShip.position.y + 50,
duration: 0.2
});
}
});
if (gameState.player.health <= 0) {
gameOver();
}
updateUI();
}
function removeLaser(index) {
const laser = lasers[index];
scene.remove(laser);
lasers.splice(index, 1);
}
// ==================== 飞船控制 ====================
function updateShip(deltaTime) {
const data = playerShip.userData;
const moveSpeed = CONFIG.SHIP_SPEED * gameState.player.upgrades.engine * 0.5;
// 计算移动方向
const moveDirection = new THREE.Vector3();
if (input.keys['KeyW'] || input.keys['ArrowUp']) {
moveDirection.z -= 1;
}
if (input.keys['KeyS'] || input.keys['ArrowDown']) {
moveDirection.z += 1;
}
if (input.keys['KeyA'] || input.keys['ArrowLeft']) {
moveDirection.x -= 1;
}
if (input.keys['KeyD'] || input.keys['ArrowRight']) {
moveDirection.x += 1;
}
if (input.keys['Space']) {
moveDirection.y += 1;
}
if (input.keys['ShiftLeft'] || input.keys['ShiftRight']) {
moveDirection.y -= 1;
}
// 应用加速度
if (moveDirection.length() > 0) {
moveDirection.normalize();
data.velocity.add(moveDirection.multiplyScalar(moveSpeed * deltaTime));
// 创建引擎尾焰
if (Math.random() > 0.5) {
createEngineTrail();
}
}
// 应用摩擦力
data.velocity.multiplyScalar(CONFIG.SHIP_FRICTION);
// 更新位置
playerShip.position.add(data.velocity.clone().multiplyScalar(deltaTime));
// 飞船倾斜效果
playerShip.rotation.z = -data.velocity.x * CONFIG.SHIP_TILT_FACTOR;
playerShip.rotation.x = data.velocity.z * CONFIG.SHIP_TILT_FACTOR * 0.5;
// 根据鼠标位置旋转飞船
const targetRotation = Math.atan2(
input.mouseWorld.x - playerShip.position.x,
input.mouseWorld.z - playerShip.position.z
);
playerShip.rotation.y = targetRotation + Math.PI / 2;
// 限制边界
const limit = CONFIG.UNIVERSE_SIZE * 0.8;
playerShip.position.x = Math.max(-limit, Math.min(limit, playerShip.position.x));
playerShip.position.y = Math.max(-limit, Math.min(limit, playerShip.position.y));
playerShip.position.z = Math.max(-limit, Math.min(limit, playerShip.position.z));
// 相机跟随
const targetCameraPos = new THREE.Vector3(
playerShip.position.x,
playerShip.position.y + 50,
playerShip.position.z + 80
);
camera.position.lerp(targetCameraPos, 0.05);
camera.lookAt(playerShip.position);
}
// ==================== 射击控制 ====================
function shoot() {
if (gameState.combat.laserCooldown > 0) return;
gameState.combat.laserCooldown = CONFIG.LASER_COOLDOWN;
const direction = new THREE.Vector3(0, 0, -1);
direction.applyQuaternion(playerShip.quaternion);
const start = playerShip.position.clone();
const end = start.clone().add(direction.multiplyScalar(200));
createLaser(start, end, false);
// 后坐力
gsap.to(playerShip.position, {
z: playerShip.position.z + 0.5,
duration: 0.05,
yoyo: true,
repeat: 1
});
}
// ==================== 技能系统 ====================
function activateSkill() {
if (gameState.combat.skillCooldown > 0) {
showMessage('技能冷却中...', 'warning');
return;
}
if (gameState.player.energy < 50) {
showMessage('能量不足!', 'warning');
return;
}
gameState.player.energy -= 50;
gameState.combat.skillCooldown = CONFIG.SKILL_COOLDOWN;
gameState.combat.skillActive = true;
// 全屏攻击特效
createExplosion(playerShip.position, 0x4CC9F0, 100);
// 伤害范围内所有敌人
for (let i = enemies.length - 1; i >= 0; i--) {
const enemy = enemies[i];
if (playerShip.position.distanceTo(enemy.position) < 200) {
damageEnemy(enemy, 100);
}
}
showMessage('技能激活: 超新星爆发!', 'success');
updateUI();
}
// ==================== 粒子更新 ====================
function updateParticles(deltaTime) {
for (let i = particles.length - 1; i >= 0; i--) {
const particle = particles[i];
const data = particle.userData;
// 更新生命周期
data.life -= deltaTime;
if (data.life <= 0) {
scene.remove(particle);
particles.splice(i, 1);
continue;
}
// 更新位置
if (data.velocity) {
particle.position.add(data.velocity.clone().multiplyScalar(deltaTime));
data.velocity.multiplyScalar(0.95);
}
// 更新透明度
if (particle.material) {
particle.material.opacity = data.life / data.maxLife;
}
// 冲击波放大
if (data.type === 'shockwave') {
const scale = 1 + (1 - data.life / data.maxLife) * 10;
particle.scale.set(scale, scale, scale);
}
}
}
// ==================== 天体更新 ====================
function updateCelestialBodies(deltaTime) {
// 更新行星
for (const planet of planets) {
planet.rotation.y += planet.userData.rotationSpeed;
}
// 更新小行星
for (const asteroid of asteroids) {
asteroid.rotation.x += asteroid.userData.rotationSpeed;
asteroid.rotation.y += asteroid.userData.rotationSpeed;
}
// 星空视差滚动
if (stars) {
stars.position.x = playerShip.position.x * 0.1;
stars.position.y = playerShip.position.y * 0.1;
stars.position.z = playerShip.position.z * 0.1;
}
}
// ==================== 小地图更新 ====================
function updateMinimap() {
const canvas = document.getElementById('minimap-canvas');
const ctx = canvas.getContext('2d');
const size = 180;
const scale = size / CONFIG.UNIVERSE_SIZE;
canvas.width = size;
canvas.height = size;
// 清空
ctx.fillStyle = 'rgba(5, 5, 16, 0.9)';
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 2, 0, Math.PI * 2);
ctx.fill();
// 绘制边框
ctx.strokeStyle = 'rgba(76, 201, 240, 0.5)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2 - 2, 0, Math.PI * 2);
ctx.stroke();
// 绘制玩家
const playerX = size / 2 + playerShip.position.x * scale;
const playerY = size / 2 + playerShip.position.z * scale;
ctx.fillStyle = '#4CC9F0';
ctx.beginPath();
ctx.arc(playerX, playerY, 4, 0, Math.PI * 2);
ctx.fill();
// 绘制敌人
ctx.fillStyle = '#F72585';
for (const enemy of enemies) {
const x = size / 2 + enemy.position.x * scale;
const y = size / 2 + enemy.position.z * scale;
ctx.beginPath();
ctx.arc(x, y, 2, 0, Math.PI * 2);
ctx.fill();
}
// 绘制行星
ctx.fillStyle = '#7B2CBF';
for (const planet of planets) {
const x = size / 2 + planet.position.x * scale;
const y = size / 2 + planet.position.z * scale;
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2);
ctx.fill();
}
}
// ==================== 游戏结束 ====================
function gameOver() {
gameState.isPlaying = false;
showMessage('飞船已损毁!', 'danger');
setTimeout(() => {
document.getElementById('pause-menu').classList.add('visible');
document.querySelector('.pause-title').textContent = '💀 游戏结束';
document.getElementById('resume-btn').style.display = 'none';
}, 1000);
}
// ==================== 游戏循环 ====================
function animate(currentTime = 0) {
requestAnimationFrame(animate);
const deltaTime = Math.min((currentTime - gameState.lastTime) / 1000, 0.1);
gameState.lastTime = currentTime;
if (!gameState.isPlaying || gameState.isPaused || gameState.isUpgrading) {
renderer.render(scene, camera);
return;
}
// 更新飞船
updateShip(deltaTime);
// 更新战斗
updateCombat(deltaTime);
// 检查交互
checkInteractions(deltaTime);
// 更新粒子
updateParticles(deltaTime);
// 更新天体
updateCelestialBodies(deltaTime);
// 更新小地图
updateMinimap();
// 渲染场景
renderer.render(scene, camera);
}
// ==================== 升级系统 ====================
function updateUpgradePanel() {
const upgrades = gameState.player.upgrades;
// 更新每个升级卡片
for (const [key, level] of Object.entries(upgrades)) {
const cost = Math.floor(CONFIG.BASE_UPGRADE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER, level - 1));
document.getElementById(`${key}-level`).textContent = `等级 ${level}`;
document.getElementById(`${key}-cost`).textContent = `消耗: ${cost} 晶体`;
}
}
function purchaseUpgrade(type) {
const level = gameState.player.upgrades[type];
const cost = Math.floor(CONFIG.BASE_UPGRADE_COST * Math.pow(CONFIG.UPGRADE_COST_MULTIPLIER, level - 1));
if (gameState.player.crystals < cost) {
showMessage('晶体不足!', 'warning');
return;
}
gameState.player.crystals -= cost;
gameState.player.upgrades[type]++;
// 应用升级效果
applyUpgrade(type);
updateUpgradePanel();
updateUI();
showMessage(`${type} 升级成功!`, 'success');
}
function applyUpgrade(type) {
const level = gameState.player.upgrades[type];
switch (type) {
case 'engine':
CONFIG.SHIP_SPEED = 50 + (level - 1) * 10;
break;
case 'shield':
gameState.player.maxShield = 100 + (level - 1) * 20;
gameState.player.shield = gameState.player.maxShield;
break;
case 'weapon':
CONFIG.LASER_DAMAGE = 25 + (level - 1) * 10;
break;
case 'cargo':
CONFIG.RESOURCE_MAX_CARGO = 100 + (level - 1) * 50;
break;
}
}
// ==================== 窗口调整 ====================
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// ==================== 输入处理 ====================
function setupInputHandlers() {
// 键盘按下
window.addEventListener('keydown', (e) => {
input.keys[e.code] = true;
// E 键交互
if (e.code === 'KeyE' && gameState.isPlaying && !gameState.isPaused) {
performInteraction();
}
// U 键升级面板
if (e.code === 'KeyU' && gameState.isPlaying) {
toggleUpgradePanel();
}
// 空格键技能
if (e.code === 'Space' && gameState.isPlaying && !gameState.isPaused) {
activateSkill();
}
// ESC 暂停
if (e.code === 'Escape') {
togglePause();
}
});
// 键盘释放
window.addEventListener('keyup', (e) => {
input.keys[e.code] = false;
});
// 鼠标移动
window.addEventListener('mousemove', (e) => {
input.mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
input.mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
// 计算鼠标在3D世界中的位置
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(input.mouse, camera);
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
const target = new THREE.Vector3();
raycaster.ray.intersectPlane(plane, target);
if (target) {
input.mouseWorld.copy(target);
}
});
// 鼠标点击
window.addEventListener('mousedown', (e) => {
if (e.button === 0 && gameState.isPlaying && !gameState.isPaused) {
input.mouse.down = true;
shoot();
}
});
window.addEventListener('mouseup', (e) => {
if (e.button === 0) {
input.mouse.down = false;
}
});
// UI 按钮事件
document.getElementById('start-btn').addEventListener('click', startGame);
document.getElementById('resume-btn').addEventListener('click', togglePause);
document.getElementById('restart-btn').addEventListener('click', restartGame);
document.getElementById('quit-btn').addEventListener('click', quitGame);
document.getElementById('close-upgrade').addEventListener('click', toggleUpgradePanel);
// 升级卡片点击
document.querySelectorAll('.upgrade-card').forEach(card => {
card.addEventListener('click', () => {
const upgradeType = card.dataset.upgrade;
purchaseUpgrade(upgradeType);
});
});
}
// ==================== 游戏控制 ====================
function startGame() {
document.getElementById('start-screen').classList.add('hidden');
document.getElementById('status-bar').style.display = 'flex';
document.getElementById('resource-panel').style.display = 'block';
document.getElementById('crosshair').style.display = 'block';
document.getElementById('combat-stats').style.display = 'block';
document.getElementById('exp-display').style.display = 'block';
document.getElementById('minimap').style.display = 'block';
document.getElementById('controls-info').style.display = 'block';
gameState.isPlaying = true;
gameState.isPaused = false;
showMessage('欢迎来到星际文明探索者!', 'success');
showMessage('使用 WASD 移动,鼠标瞄准,左键射击', 'info');
}
function togglePause() {
gameState.isPaused = !gameState.isPaused;
document.getElementById('pause-menu').classList.toggle('visible', gameState.isPaused);
}
function restartGame() {
// 重置游戏状态
gameState.player.health = 100;
gameState.player.maxHealth = 100;
gameState.player.shield = 100;
gameState.player.maxShield = 100;
gameState.player.energy = 100;
gameState.player.maxEnergy = 100;
gameState.player.exp = 0;
gameState.player.maxExp = 100;
gameState.player.level = 1;
gameState.player.crystals = 0;
gameState.player.ores = 0;
gameState.player.relics = 0;
gameState.player.upgrades = {
engine: 1,
shield: 1,
weapon: 1,
scanner: 1,
cargo: 1,
skill: 1
};
gameState.combat.kills = 0;
gameState.combat.totalDamage = 0;
gameState.combat.laserCooldown = 0;
gameState.combat.skillCooldown = 0;
// 重置飞船位置
playerShip.position.set(0, 0, 0);
playerShip.userData.velocity.set(0, 0, 0);
// 重置敌人
for (const enemy of enemies) {
scene.remove(enemy);
}
enemies = [];
createEnemies();
// 重置小行星
for (const asteroid of asteroids) {
scene.remove(asteroid);
}
asteroids = [];
createAsteroids();
// 重置行星资源
for (const planet of planets) {
planet.userData.hasResources = Math.random() > 0.3;
planet.userData.resourceAmount = Math.floor(Math.random() * 50) + 20;
planet.children[0].material.emissiveIntensity = 0.1;
}
// 清除激光和粒子
for (const laser of lasers) {
scene.remove(laser);
}
lasers = [];
for (const particle of particles) {
scene.remove(particle);
}
particles = [];
// 隐藏暂停菜单
document.getElementById('pause-menu').classList.remove('visible');
document.querySelector('.pause-title').textContent = '⏸️ 暂停';
document.getElementById('resume-btn').style.display = 'block';
updateUI();
updateUpgradePanel();
gameState.isPlaying = true;
gameState.isPaused = false;
showMessage('游戏重新开始!', 'success');
}
function quitGame() {
if (confirm('确定要退出游戏吗?')) {
window.close();
}
}
function toggleUpgradePanel() {
gameState.isUpgrading = !gameState.isUpgrading;
const panel = document.getElementById('upgrade-panel');
panel.classList.toggle('visible', gameState.isUpgrading);
if (gameState.isUpgrading) {
updateUpgradePanel();
}
}
// ==================== 初始化 ====================
function init() {
initThree();
setupInputHandlers();
// 控制台输出操作指南
console.log('%c🚀 星际文明探索者 - 操作指南', 'color: #4CC9F0; font-size: 20px; font-weight: bold;');
console.log('%c移动: W/A/S/D 或 方向键', 'color: #7B2CBF; font-size: 14px;');
console.log('%c升降: 空格(上升) / Shift(下降)', 'color: #7B2CBF; font-size: 14px;');
console.log('%c瞄准: 鼠标移动', 'color: #7B2CBF; font-size: 14px;');
console.log('%c射击: 左键点击', 'color: #7B2CBF; font-size: 14px;');
console.log('%c采集: E 键(靠近星球时)', 'color: #7B2CBF; font-size: 14px;');
console.log('%c技能: 空格键(需要能量)', 'color: #7B2CBF; font-size: 14px;');
console.log('%c升级: U 键打开升级面板', 'color: #7B2CBF; font-size: 14px;');
console.log('%c暂停: ESC 键', 'color: #7B2CBF; font-size: 14px;');
console.log('%c\n收集晶体升级飞船探索宇宙消灭敌人', 'color: #F72585; font-size: 16px;');
}
// 启动游戏
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>