独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TRIZ最终理想解:电池包弹射阻力锚定制系统</title>
<style>
:root {
--bg-color: #050914;
--grid-color: rgba(0, 255, 255, 0.08);
--neon-cyan: #00f3ff;
--neon-blue: #0088ff;
--neon-orange: #ffaa00;
--neon-red: #ff2a2a;
--neon-green: #00ffaa;
--glass-bg: rgba(5, 12, 26, 0.6);
--glass-border: rgba(0, 243, 255, 0.3);
--font-main: 'Segoe UI', system-ui, -apple-system, sans-serif;
--font-mono: 'Consolas', 'Courier New', monospace;
}
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background-color: var(--bg-color);
background-image:
radial-gradient(circle at 50% 50%, #0a1128 0%, #03050a 100%);
color: #fff;
font-family: var(--font-main);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
#app-container {
position: relative;
width: 100%;
height: 100%;
max-width: 1600px;
max-height: 900px;
display: flex;
flex-direction: column;
box-shadow: inset 0 0 100px rgba(0,0,0,0.8);
}
/* 顶部控制台 HUD */
.hud-panel {
position: absolute;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 8px;
padding: 20px;
backdrop-filter: blur(10px);
box-shadow: 0 8px 32px rgba(0,0,0,0.5), inset 0 0 20px rgba(0, 243, 255, 0.05);
z-index: 10;
}
.hud-top-left {
top: 30px;
left: 30px;
border-left: 4px solid var(--neon-cyan);
}
.hud-top-right {
top: 30px;
right: 30px;
border-right: 4px solid var(--neon-orange);
display: flex;
flex-direction: column;
gap: 15px;
}
.hud-bottom-center {
bottom: 30px;
left: 50%;
transform: translateX(-50%);
border-bottom: 4px solid var(--neon-green);
text-align: center;
width: 600px;
opacity: 0;
transition: opacity 0.5s ease;
}
h1, h2, h3 {
margin: 0;
font-weight: 600;
letter-spacing: 1px;
}
.title {
font-size: 1.2rem;
color: var(--neon-cyan);
text-transform: uppercase;
margin-bottom: 5px;
display: flex;
align-items: center;
gap: 10px;
}
.title::before {
content: '';
display: inline-block;
width: 12px;
height: 12px;
background: var(--neon-cyan);
box-shadow: 0 0 10px var(--neon-cyan);
}
.subtitle {
font-size: 0.85rem;
color: #8892b0;
font-family: var(--font-mono);
}
.data-row {
display: flex;
justify-content: space-between;
align-items: center;
font-family: var(--font-mono);
font-size: 1.1rem;
gap: 20px;
margin-top: 8px;
}
.data-label {
color: #a8b2d1;
font-size: 0.9rem;
}
.data-value {
color: var(--neon-orange);
font-weight: bold;
text-shadow: 0 0 8px rgba(255, 170, 0, 0.5);
}
.data-value.cyan {
color: var(--neon-cyan);
text-shadow: 0 0 8px rgba(0, 243, 255, 0.5);
}
/* 控制按钮 */
.control-group {
display: flex;
gap: 10px;
margin-top: 10px;
}
button {
background: rgba(0, 243, 255, 0.1);
border: 1px solid var(--neon-cyan);
color: var(--neon-cyan);
padding: 8px 16px;
font-family: var(--font-main);
font-size: 0.9rem;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 1px;
}
button:hover {
background: var(--neon-cyan);
color: #000;
box-shadow: 0 0 15px var(--neon-cyan);
}
button.active {
background: var(--neon-cyan);
color: #000;
font-weight: bold;
box-shadow: 0 0 15px var(--neon-cyan);
}
button.btn-ice {
border-color: #a0c4ff;
color: #a0c4ff;
}
button.btn-ice.active, button.btn-ice:hover {
background: #a0c4ff;
color: #000;
box-shadow: 0 0 15px #a0c4ff;
}
/* SVG 容器 */
#svg-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
svg {
width: 100%;
height: 100%;
}
/* 状态指示器 */
.status-indicator {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.8rem;
font-weight: bold;
font-family: var(--font-mono);
margin-top: 10px;
}
.status-cruise { background: rgba(0, 255, 170, 0.2); border: 1px solid var(--neon-green); color: var(--neon-green); }
.status-eject { background: rgba(255, 42, 42, 0.2); border: 1px solid var(--neon-red); color: var(--neon-red); }
.status-brake { background: rgba(255, 170, 0, 0.2); border: 1px solid var(--neon-orange); color: var(--neon-orange); }
.status-stop { background: rgba(0, 243, 255, 0.2); border: 1px solid var(--neon-cyan); color: var(--neon-cyan); }
/* 扫描线叠层 */
.scanlines {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
to bottom,
rgba(255,255,255,0),
rgba(255,255,255,0) 50%,
rgba(0,0,0,0.2) 50%,
rgba(0,0,0,0.2)
);
background-size: 100% 4px;
pointer-events: none;
z-index: 20;
opacity: 0.3;
}
.ifr-highlight {
font-size: 1.4rem;
color: var(--neon-green);
text-shadow: 0 0 10px var(--neon-green);
margin-bottom: 10px;
}
.ifr-desc {
color: #e2e8f0;
font-size: 1rem;
line-height: 1.5;
}
</style>
</head>
<body>
<div id="app-container">
<div class="scanlines"></div>
<!-- 左上角:系统状态 -->
<div class="hud-panel hud-top-left">
<div class="title">安全脱离系统监控台</div>
<div class="subtitle">SYS.VER 4.2.0 | TRIZ 理想解演示</div>
<div style="margin-top: 20px;">
<div class="data-label">当前执行阶段</div>
<div id="phase-indicator" class="status-indicator status-cruise">01 - 正常巡航</div>
</div>
<div style="margin-top: 20px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 15px;">
<div class="data-label">环境模拟设置</div>
<div class="control-group">
<button id="btn-dry" class="active" onclick="setRoadCondition('dry')">标准柏油路面 (μ>0.8)</button>
<button id="btn-ice" class="btn-ice" onclick="setRoadCondition('ice')">冰雪低附路面 (μ<0.3)</button>
</div>
</div>
</div>
<!-- 右上角:实时遥测数据 -->
<div class="hud-panel hud-top-right">
<div class="title">实时运动学遥测</div>
<div class="subtitle">参考系:追踪脱离电池包</div>
<div class="data-row">
<span class="data-label">对地相对速度:</span>
<span class="data-value cyan" id="data-speed">120.0 km/h</span>
</div>
<div class="data-row">
<span class="data-label">实时摩擦系数:</span>
<span class="data-value" id="data-friction">0.00 μ</span>
</div>
<div class="data-row">
<span class="data-label">制动滑行距离:</span>
<span class="data-value" id="data-distance">0.00 m</span>
</div>
<div class="data-row">
<span class="data-label">气囊内部压力:</span>
<span class="data-value" id="data-pressure">0 kPa</span>
</div>
</div>
<!-- 底部居中:TRIZ 理想解说明 (动画最后阶段显示) -->
<div class="hud-panel hud-bottom-center" id="ifr-panel">
<div class="ifr-highlight">最终理想解 (IFR) 达成</div>
<div class="ifr-desc">
巧妙利用脱离瞬间的压缩空气与自身重力,将“翻滚的危险源”直接转化为<b>高阻力制动锚</b>。<br>
芳纶气囊消除硬着陆冲击,并在 <span id="ifr-dist-text" style="color:var(--neon-orange); font-weight:bold;">2.0</span> 米内强行终止滑行,杜绝次生灾害。
</div>
</div>
<!-- 核心 SVG 动画区 -->
<div id="svg-container">
<svg viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid slice">
<defs>
<!-- 发光滤镜 -->
<filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="8" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-orange" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="15" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-red" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="10" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<!-- 芳纶纤维纹理 -->
<pattern id="aramid-texture" width="10" height="10" patternUnits="userSpaceOnUse">
<path d="M0 0L10 10ZM10 0L0 10Z" stroke="rgba(0,0,0,0.3)" stroke-width="1" />
<rect width="10" height="10" fill="url(#airbag-grad)" fill-opacity="0.8" />
</pattern>
<linearGradient id="airbag-grad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#ffcc00" />
<stop offset="100%" stop-color="#ff6600" />
</linearGradient>
<!-- 背景网格 -->
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="var(--grid-color)" stroke-width="1"/>
</pattern>
<!-- 运动模糊线条滤镜 -->
<filter id="motion-blur" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur stdDeviation="20 0" result="blur" />
</filter>
</defs>
<!-- 背景与网格 -->
<rect width="100%" height="100%" fill="url(#grid)" />
<g id="world-transform">
<!-- 动态路面线 -->
<g id="road-lines" stroke="rgba(255,255,255,0.4)" stroke-width="4" stroke-dasharray="80 120">
<line x1="-1000" y1="700" x2="3000" y2="700" />
<line x1="-1000" y1="730" x2="3000" y2="730" opacity="0.5" stroke-dasharray="40 60" />
<line x1="-1000" y1="760" x2="3000" y2="760" opacity="0.2" stroke-dasharray="20 40" />
</g>
<!-- 路面高亮摩擦区 -->
<ellipse id="friction-glow" cx="800" cy="700" rx="200" ry="20" fill="rgba(255, 60, 0, 0)" filter="url(#glow-orange)" />
<!-- 汽车底盘 (虚影) -->
<g id="car-chassis" filter="url(#glow-cyan)" opacity="0.8">
<!-- 轮廓线框风格的底盘 -->
<path d="M 400 550 L 450 500 L 1150 500 L 1200 550 L 1180 620 L 420 620 Z" fill="rgba(0, 243, 255, 0.05)" stroke="var(--neon-cyan)" stroke-width="2"/>
<!-- 轮子 -->
<circle cx="500" cy="620" r="40" fill="none" stroke="var(--neon-cyan)" stroke-width="2" stroke-dasharray="10 5" />
<circle cx="1100" cy="620" r="40" fill="none" stroke="var(--neon-cyan)" stroke-width="2" stroke-dasharray="10 5" />
<circle cx="500" cy="620" r="25" fill="none" stroke="var(--neon-cyan)" stroke-width="1" />
<circle cx="1100" cy="620" r="25" fill="none" stroke="var(--neon-cyan)" stroke-width="1" />
<!-- 车体科技线条 -->
<line x1="450" y1="520" x2="1150" y2="520" stroke="rgba(0, 243, 255, 0.5)" stroke-width="1" />
<text x="750" y="480" fill="var(--neon-cyan)" font-family="var(--font-mono)" font-size="14" letter-spacing="2">EV CHASSIS // PLATFORM 9</text>
</g>
<!-- 弹射指示箭头 -->
<g id="eject-arrow" opacity="0" filter="url(#glow-red)">
<path d="M 800 420 L 820 380 L 780 380 Z" fill="var(--neon-red)"/>
<line x1="800" y1="380" x2="800" y2="480" stroke="var(--neon-red)" stroke-width="4" stroke-dasharray="10 5"/>
<text x="820" y="440" fill="var(--neon-red)" font-family="var(--font-main)" font-size="16" font-weight="bold">侧推爆破激活</text>
</g>
<!-- 电池包系统 -->
<g id="battery-system">
<!-- 芳纶气囊 (初始隐藏/压缩在电池底部) -->
<g id="airbag" transform="scale(1, 0)" transform-origin="800 590">
<path d="M 620 590 Q 600 680 650 695 L 950 695 Q 1000 680 980 590 Z" fill="url(#aramid-texture)" stroke="var(--neon-orange)" stroke-width="3" filter="url(#glow-orange)"/>
<!-- 气囊上的纹理线条 -->
<path d="M 640 620 Q 800 660 960 620" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
<path d="M 630 650 Q 800 680 970 650" fill="none" stroke="rgba(255,255,255,0.4)" stroke-width="2"/>
<text x="800" y="660" fill="#fff" font-family="var(--font-mono)" font-size="14" text-anchor="middle" font-weight="bold" text-shadow="0 0 5px #000">陶瓷基耐高温芳纶材质</text>
</g>
<!-- 电池本体 -->
<g id="battery-pack">
<rect x="650" y="550" width="300" height="40" rx="5" fill="#1a1e29" stroke="var(--neon-orange)" stroke-width="2" />
<!-- 内部电芯结构 -->
<rect x="660" y="555" width="40" height="30" fill="rgba(255, 170, 0, 0.2)" stroke="var(--neon-orange)" stroke-width="1"/>
<rect x="710" y="555" width="40" height="30" fill="rgba(255, 170, 0, 0.2)" stroke="var(--neon-orange)" stroke-width="1"/>
<rect x="760" y="555" width="40" height="30" fill="rgba(255, 170, 0, 0.2)" stroke="var(--neon-orange)" stroke-width="1"/>
<rect x="810" y="555" width="40" height="30" fill="rgba(255, 170, 0, 0.2)" stroke="var(--neon-orange)" stroke-width="1"/>
<rect x="860" y="555" width="40" height="30" fill="rgba(255, 170, 0, 0.2)" stroke="var(--neon-orange)" stroke-width="1"/>
<rect x="910" y="555" width="30" height="30" fill="rgba(255, 170, 0, 0.2)" stroke="var(--neon-orange)" stroke-width="1"/>
<!-- 警示标志 -->
<path d="M 800 560 L 810 580 L 790 580 Z" fill="var(--neon-orange)" />
<text x="800" y="585" fill="#1a1e29" font-family="var(--font-main)" font-size="10" font-weight="bold" text-anchor="middle">!</text>
</g>
</g>
<!-- 制动火花粒子效果 -->
<g id="sparks" opacity="0" filter="url(#motion-blur)"></g>
<!-- 信息标注连线 (动态显示) -->
<g id="annotations" opacity="0">
<!-- 摩擦力指示 -->
<line x1="800" y1="700" x2="800" y2="760" stroke="var(--neon-green)" stroke-width="2" />
<circle cx="800" cy="700" r="4" fill="var(--neon-green)" />
<text x="810" y="750" fill="var(--neon-green)" font-family="var(--font-main)" font-size="16" font-weight="bold" filter="url(#glow-cyan)">超高地面摩擦阻力 (μ > 0.8)</text>
<!-- 气囊作用指示 -->
<line x1="900" y1="650" x2="1050" y2="600" stroke="var(--neon-orange)" stroke-width="2" />
<circle cx="900" cy="650" r="4" fill="var(--neon-orange)" />
<text x="1060" y="605" fill="var(--neon-orange)" font-family="var(--font-main)" font-size="16" font-weight="bold">柔性减震,防止外壳破裂起火</text>
</g>
</g>
</svg>
</div>
</div>
<script>
/**
* 物理引擎与动画调度器
* 采用“相机锁定脱离电池包”的参考系
*/
// --- 配置与状态变量 ---
const v0 = 33.33; // 初始速度 m/s (约120km/h)
const pixelsPerMeter = 40; // 视觉缩放比例
let simConfig = {
frictionCoeff: 0.85, // 默认高摩擦
roadType: 'dry'
};
let state = {
phase: 0, // 0:巡航, 1:弹射脱离, 2:气囊充气, 3:触地制动, 4:完全停止
time: 0,
batterySpeed: v0, // 电池相对地面的速度 m/s
carX: 0, // 汽车相对电池的距离 (m)
batteryY: 0, // 电池下落距离 (m)
slideDistance: 0, // 滑行距离 (m)
roadPos: 0, // 路面纹理偏移 (px)
airbagScale: 0, // 0 to 1
pressure: 0,
sparkIntensity: 0
};
let animationFrameId;
let lastTime = performance.now();
// --- DOM 元素引用 ---
const dom = {
roadLines: document.getElementById('road-lines'),
carChassis: document.getElementById('car-chassis'),
batterySystem: document.getElementById('battery-system'),
airbag: document.getElementById('airbag'),
sparks: document.getElementById('sparks'),
ejectArrow: document.getElementById('eject-arrow'),
annotations: document.getElementById('annotations'),
frictionGlow: document.getElementById('friction-glow'),
// HUD
phaseIndicator: document.getElementById('phase-indicator'),
dataSpeed: document.getElementById('data-speed'),
dataFriction: document.getElementById('data-friction'),
dataDistance: document.getElementById('data-distance'),
dataPressure: document.getElementById('data-pressure'),
ifrPanel: document.getElementById('ifr-panel'),
ifrDistText: document.getElementById('ifr-dist-text'),
// 按钮
btnDry: document.getElementById('btn-dry'),
btnIce: document.getElementById('btn-ice')
};
// --- 初始化火花粒子 ---
const sparkCount = 30;
for(let i=0; i<sparkCount; i++) {
let line = document.createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute("stroke", "#ffaa00");
line.setAttribute("stroke-width", Math.random() * 3 + 1);
dom.sparks.appendChild(line);
}
// --- 交互控制 ---
window.setRoadCondition = function(type) {
simConfig.roadType = type;
if(type === 'dry') {
simConfig.frictionCoeff = 0.85;
dom.btnDry.classList.add('active');
dom.btnIce.classList.remove('active');
} else {
simConfig.frictionCoeff = 0.25; // 冰雪路面摩擦小
dom.btnIce.classList.add('active');
dom.btnDry.classList.remove('active');
}
// 重置动画
resetSimulation();
};
function resetSimulation() {
state = {
phase: 0,
time: 0,
batterySpeed: v0,
carX: 0,
batteryY: 0,
slideDistance: 0,
roadPos: 0,
airbagScale: 0,
pressure: 0,
sparkIntensity: 0
};
dom.ifrPanel.style.opacity = '0';
dom.annotations.setAttribute('opacity', '0');
dom.frictionGlow.setAttribute('fill', 'rgba(255, 60, 0, 0)');
updateHUD();
}
// --- 主循环 ---
function loop(currentTime) {
let dt = (currentTime - lastTime) / 1000; // 秒
if (dt > 0.1) dt = 0.1; // 防止标签页休眠导致步长过大
lastTime = currentTime;
updatePhysics(dt);
renderVisuals();
updateHUD();
animationFrameId = requestAnimationFrame(loop);
}
// --- 物理状态更新 ---
function updatePhysics(dt) {
state.time += dt;
// 时间轴编排
// 0s - 1.5s: 正常巡航
// 1.5s - 1.8s: 触发弹射
// 1.8s - 2.2s: 下落与气囊爆开
// 2.2s - ... : 触地制动直到停止
// 停止后停留4秒,然后重置
if (state.time < 1.5) {
state.phase = 0;
}
else if (state.time >= 1.5 && state.time < 1.8) {
state.phase = 1;
state.batteryY += 2 * dt; // 开始下落
}
else if (state.time >= 1.8 && state.time < 2.2) {
state.phase = 2;
state.batteryY += 10 * dt; // 加速下落
if(state.batteryY > 1.8) state.batteryY = 1.8; // 落地最大高度
// 气囊充气 0->1
state.airbagScale = Math.min(1, (state.time - 1.8) / 0.3);
state.pressure = state.airbagScale * 350; // kPa
}
else if (state.time >= 2.2 && state.batterySpeed > 0) {
state.phase = 3;
// 核心 IFR 机制:强力摩擦制动
let deceleration = simConfig.frictionCoeff * 9.8; // a = μg
state.batterySpeed -= deceleration * dt;
if (state.batterySpeed < 0) state.batterySpeed = 0;
// 记录滑行距离
let ds = state.batterySpeed * dt;
state.slideDistance += ds;
state.sparkIntensity = (state.batterySpeed / v0); // 速度越快火花越亮
}
else if (state.batterySpeed === 0) {
if(state.phase !== 4) {
state.phase = 4;
state.stopTime = state.time; // 记录停止时刻
}
state.sparkIntensity = 0;
// 循环重置机制
if(state.time > state.stopTime + 5.0) {
resetSimulation();
}
}
// 运动学积分 (基于“相机跟随电池”的坐标系)
// 电池保持在中心。路面相对向左移动。
state.roadPos -= state.batterySpeed * pixelsPerMeter * dt;
// 汽车以 v0 的恒定速度前进,相对电池的速度是 (v0 - batterySpeed)
state.carX += (v0 - state.batterySpeed) * pixelsPerMeter * dt;
}
// --- 渲染更新 ---
function renderVisuals() {
// 1. 路面滚动
dom.roadLines.setAttribute('transform', `translate(${state.roadPos % 200}, 0)`);
// 2. 汽车远离
dom.carChassis.setAttribute('transform', `translate(${state.carX}, ${-state.carX * 0.05})`); // 伴随轻微上升感
dom.carChassis.setAttribute('opacity', Math.max(0, 0.8 - state.carX / 1000)); // 渐隐
// 3. 电池包弹射下落与气囊
dom.batterySystem.setAttribute('transform', `translate(0, ${state.batteryY * pixelsPerMeter})`);
// 气囊缩放与弹性动画
let currentScale = state.airbagScale;
if(state.phase === 3) {
// 制动时的挤压变形抖动
let jitter = Math.sin(state.time * 50) * 0.05 * state.sparkIntensity;
currentScale = 1 - jitter;
dom.frictionGlow.setAttribute('fill', `rgba(255, 60, 0, ${0.4 * state.sparkIntensity})`);
}
dom.airbag.setAttribute('transform', `scale(1, ${currentScale})`);
// 4. 弹射箭头
if(state.phase === 1) {
dom.ejectArrow.setAttribute('opacity', 1);
let arrowY = Math.sin(state.time * 20) * 10; // 闪烁抖动
dom.ejectArrow.setAttribute('transform', `translate(0, ${arrowY})`);
} else {
dom.ejectArrow.setAttribute('opacity', 0);
}
// 5. 制动火花粒子
if(state.phase === 3 && state.sparkIntensity > 0) {
dom.sparks.setAttribute('opacity', state.sparkIntensity);
let lines = dom.sparks.children;
for(let i=0; i<lines.length; i++) {
// 火花从气囊底部的接触面产生并向后飞(向左,因为电池相对路面向右滑行)
// 实际上路面向左走,火花应该留在路面上向左飞
let startX = 700 + Math.random() * 200;
let startY = 695 + Math.random() * 5;
let length = (Math.random() * 100 + 50) * state.sparkIntensity;
// 偶尔重置火花位置
if(Math.random() < 0.2) {
lines[i].setAttribute('x1', startX);
lines[i].setAttribute('y1', startY);
lines[i].setAttribute('x2', startX - length);
lines[i].setAttribute('y2', startY - (Math.random()*10 - 5));
} else {
// 让火花随路面后退
let x1 = parseFloat(lines[i].getAttribute('x1')) - state.batterySpeed * pixelsPerMeter * 0.016;
let x2 = parseFloat(lines[i].getAttribute('x2')) - state.batterySpeed * pixelsPerMeter * 0.016;
lines[i].setAttribute('x1', x1);
lines[i].setAttribute('x2', x2);
}
}
} else {
dom.sparks.setAttribute('opacity', 0);
}
// 6. 后期标注与理想解展示
if(state.phase >= 3) {
dom.annotations.setAttribute('opacity', Math.min(1, (state.time - 2.2) * 2));
if(simConfig.roadType === 'ice') {
dom.annotations.querySelector('text').textContent = "低摩擦冰雪路面 (μ < 0.3)";
dom.annotations.querySelector('text').setAttribute('fill', '#a0c4ff');
dom.annotations.querySelector('line').setAttribute('stroke', '#a0c4ff');
dom.annotations.querySelector('circle').setAttribute('fill', '#a0c4ff');
} else {
dom.annotations.querySelector('text').textContent = "超高地面摩擦阻力 (μ > 0.8)";
dom.annotations.querySelector('text').setAttribute('fill', 'var(--neon-green)');
dom.annotations.querySelector('line').setAttribute('stroke', 'var(--neon-green)');
dom.annotations.querySelector('circle').setAttribute('fill', 'var(--neon-green)');
}
}
if(state.phase === 4 && state.time - state.stopTime > 0.5) {
dom.ifrPanel.style.opacity = '1';
dom.ifrDistText.textContent = state.slideDistance.toFixed(1);
if(simConfig.roadType === 'ice') {
dom.ifrDistText.style.color = '#a0c4ff';
} else {
dom.ifrDistText.style.color = 'var(--neon-green)';
}
}
}
// --- HUD 数据更新 ---
function updateHUD() {
// 状态指示器
let phaseText, phaseClass;
switch(state.phase) {
case 0: phaseText = "01 - 正常巡航阶段"; phaseClass = "status-cruise"; break;
case 1: phaseText = "02 - 侧向推力爆破脱离"; phaseClass = "status-eject"; break;
case 2: phaseText = "03 - 底部耐高温气囊充气"; phaseClass = "status-brake"; break;
case 3: phaseText = "04 - 触地强力摩擦制动"; phaseClass = "status-brake"; break;
case 4: phaseText = "05 - 锚定停滞 (完全消除隐患)"; phaseClass = "status-stop"; break;
}
dom.phaseIndicator.textContent = phaseText;
dom.phaseIndicator.className = `status-indicator ${phaseClass}`;
// 遥测数据
dom.dataSpeed.textContent = (state.batterySpeed * 3.6).toFixed(1) + " km/h";
let displayFriction = state.phase >= 3 ? simConfig.frictionCoeff.toFixed(2) : "0.00";
dom.dataFriction.textContent = displayFriction + " μ";
dom.dataDistance.textContent = state.slideDistance.toFixed(2) + " m";
dom.dataPressure.textContent = Math.floor(state.pressure) + " kPa";
// 颜色反馈
if(state.batterySpeed < 5) dom.dataSpeed.classList.remove('cyan');
else dom.dataSpeed.classList.add('cyan');
}
// --- 启动动画 ---
window.addEventListener('DOMContentLoaded', () => {
resetSimulation();
lastTime = performance.now();
animationFrameId = requestAnimationFrame(loop);
});
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
