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

2314 lines
80 KiB
HTML
Raw Normal View History

<!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>