fix: 清理AI遗留代码,修复场景配置
- 删除三套旧菜单系统 (MainMenu.cs, MainMenuUI.cs, ModeSelectionUI.cs) - Ground 添加 BoxCollider 并设置 tag 为 Ground - UIManager.OnReturnClicked 改为通过 PageController 返回首页 - PageController 增加 ReturnToHome 方法,管理 BtnFixationBack 可见性 - 清理废弃场景 Experiment.unity / ModeSelection.unity 及历史截图
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
const express = require('express');
|
||||
const path = require('path');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
const ROOT = __dirname;
|
||||
|
||||
// 首页 —— 全屏启动页面
|
||||
// 必须在静态文件中间件之前注册,否则 express.static 会优先返回 index.html
|
||||
app.get('/', (req, res) => {
|
||||
res.send(`<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>运动伤害现场急救虚拟仿真实验</title>
|
||||
<link rel="shortcut icon" href="TemplateData/favicon.ico">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Microsoft YaHei", "PingFang SC", sans-serif;
|
||||
background: #231F20;
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
/* ========== 启动封面 ========== */
|
||||
#landing {
|
||||
position: fixed; inset: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: radial-gradient(ellipse at center, #2a2526 0%, #1a1516 70%, #0d0a0b 100%);
|
||||
z-index: 100;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
#landing.hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#landing .logo-area {
|
||||
margin-bottom: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#landing .logo-area .icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin: 0 auto 30px;
|
||||
background: url('TemplateData/unity-logo-light.png') no-repeat center;
|
||||
background-size: contain;
|
||||
filter: drop-shadow(0 0 30px rgba(255,255,255,0.15));
|
||||
}
|
||||
|
||||
#landing h1 {
|
||||
font-size: clamp(24px, 4vw, 42px);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 20px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
#landing .subtitle {
|
||||
margin-top: 12px;
|
||||
font-size: clamp(14px, 1.8vw, 18px);
|
||||
color: rgba(255,255,255,0.45);
|
||||
letter-spacing: 0.15em;
|
||||
}
|
||||
|
||||
#btn-start {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px 56px;
|
||||
font-size: clamp(16px, 2vw, 20px);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.1em;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #4a90d9 0%, #357abd 100%);
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
box-shadow: 0 8px 32px rgba(74, 144, 217, 0.35);
|
||||
}
|
||||
|
||||
#btn-start:hover {
|
||||
transform: translateY(-2px) scale(1.03);
|
||||
box-shadow: 0 12px 40px rgba(74, 144, 217, 0.5);
|
||||
}
|
||||
|
||||
#btn-start:active {
|
||||
transform: translateY(0) scale(0.98);
|
||||
}
|
||||
|
||||
#btn-start .arrow {
|
||||
display: inline-block;
|
||||
font-size: 1.2em;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
#btn-start:hover .arrow {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
#landing .hint {
|
||||
margin-top: 40px;
|
||||
font-size: 13px;
|
||||
color: rgba(255,255,255,0.25);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* ========== Unity 容器 (默认隐藏) ========== */
|
||||
#unity-container {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
display: none;
|
||||
background: #231F20;
|
||||
}
|
||||
|
||||
#unity-container.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#unity-canvas {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
background: #231F20;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ========== 加载进度条 ========== */
|
||||
#unity-loading-bar {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: none;
|
||||
text-align: center;
|
||||
z-index: 10;
|
||||
}
|
||||
#unity-loading-bar.show { display: block; }
|
||||
|
||||
#unity-logo {
|
||||
width: 154px; height: 130px;
|
||||
margin: 0 auto;
|
||||
background: url('TemplateData/unity-logo-dark.png') no-repeat center;
|
||||
}
|
||||
#unity-progress-bar-empty {
|
||||
width: 141px; height: 18px;
|
||||
margin: 10px auto 0;
|
||||
background: url('TemplateData/progress-bar-empty-dark.png') no-repeat center;
|
||||
}
|
||||
#unity-progress-bar-full {
|
||||
width: 0%; height: 18px;
|
||||
background: url('TemplateData/progress-bar-full-dark.png') no-repeat center;
|
||||
}
|
||||
|
||||
#unity-footer {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
z-index: 10;
|
||||
}
|
||||
#unity-webgl-logo {
|
||||
width: 204px; height: 38px;
|
||||
background: url('TemplateData/webgl-logo.png') no-repeat center;
|
||||
}
|
||||
#unity-build-title {
|
||||
color: rgba(255,255,255,0.5);
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
#unity-fullscreen-button {
|
||||
cursor: pointer;
|
||||
width: 38px; height: 38px;
|
||||
background: url('TemplateData/fullscreen-button.png') no-repeat center;
|
||||
}
|
||||
#unity-warning {
|
||||
position: absolute; left: 50%; top: 5%;
|
||||
transform: translate(-50%);
|
||||
background: white; color: #333;
|
||||
padding: 10px; display: none; z-index: 20;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ===== 启动封面 ===== -->
|
||||
<div id="landing">
|
||||
<div class="logo-area">
|
||||
<div class="icon"></div>
|
||||
<h1>运动伤害现场急救虚拟仿真实验</h1>
|
||||
<p class="subtitle">VIRTUAL SIMULATION EXPERIMENT</p>
|
||||
</div>
|
||||
<button id="btn-start" onclick="enterFullscreen()">
|
||||
进入全屏实验
|
||||
<span class="arrow">→</span>
|
||||
</button>
|
||||
<p class="hint">点击按钮进入全屏沉浸式实验环境</p>
|
||||
</div>
|
||||
|
||||
<!-- ===== Unity 容器 ===== -->
|
||||
<div id="unity-container">
|
||||
<canvas id="unity-canvas" tabindex="-1"></canvas>
|
||||
<div id="unity-loading-bar">
|
||||
<div id="unity-logo"></div>
|
||||
<div id="unity-progress-bar-empty">
|
||||
<div id="unity-progress-bar-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="unity-warning"></div>
|
||||
<div id="unity-footer">
|
||||
<div id="unity-webgl-logo"></div>
|
||||
<div id="unity-fullscreen-button"></div>
|
||||
<div id="unity-build-title">运动伤害现场急救虚拟仿真实验</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var container = document.querySelector("#unity-container");
|
||||
var canvas = document.querySelector("#unity-canvas");
|
||||
var loadingBar = document.querySelector("#unity-loading-bar");
|
||||
var progressBarFull = document.querySelector("#unity-progress-bar-full");
|
||||
var fullscreenButton = document.querySelector("#unity-fullscreen-button");
|
||||
var warningBanner = document.querySelector("#unity-warning");
|
||||
var landing = document.querySelector("#landing");
|
||||
|
||||
function unityShowBanner(msg, type) {
|
||||
function updateBannerVisibility() {
|
||||
warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
|
||||
}
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = msg;
|
||||
warningBanner.appendChild(div);
|
||||
if (type == 'error') div.style = 'background: red; padding: 10px;';
|
||||
else {
|
||||
if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
|
||||
setTimeout(function() {
|
||||
warningBanner.removeChild(div);
|
||||
updateBannerVisibility();
|
||||
}, 5000);
|
||||
}
|
||||
updateBannerVisibility();
|
||||
}
|
||||
|
||||
var buildUrl = "Build";
|
||||
var loaderUrl = buildUrl + "/Build.loader.js";
|
||||
var config = {
|
||||
dataUrl: buildUrl + "/Build.data",
|
||||
frameworkUrl: buildUrl + "/Build.framework.js",
|
||||
codeUrl: buildUrl + "/Build.wasm",
|
||||
streamingAssetsUrl: "StreamingAssets",
|
||||
companyName: "DefaultCompany",
|
||||
productName: "运动伤害现场急救虚拟仿真实验",
|
||||
productVersion: "0.1.0",
|
||||
showBanner: unityShowBanner,
|
||||
};
|
||||
|
||||
var unityInstance = null;
|
||||
|
||||
// ========== 进入全屏 ==========
|
||||
function enterFullscreen() {
|
||||
var el = document.documentElement;
|
||||
|
||||
var requestFS = el.requestFullscreen || el.webkitRequestFullscreen
|
||||
|| el.msRequestFullscreen || el.mozRequestFullScreen;
|
||||
|
||||
if (requestFS) {
|
||||
requestFS.call(el).then(function() {
|
||||
startUnity();
|
||||
}).catch(function(err) {
|
||||
// 全屏被拒绝(例如用户取消),仍然启动 Unity
|
||||
console.warn('全屏请求失败,以普通模式启动:', err);
|
||||
startUnity();
|
||||
});
|
||||
} else {
|
||||
// 不支持全屏 API 的浏览器
|
||||
startUnity();
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 启动 Unity ==========
|
||||
function startUnity() {
|
||||
// 隐藏封面
|
||||
landing.classList.add('hidden');
|
||||
|
||||
// 显示 Unity 容器
|
||||
container.classList.add('active');
|
||||
loadingBar.classList.add('show');
|
||||
|
||||
// 加载 Unity
|
||||
var script = document.createElement("script");
|
||||
script.src = loaderUrl;
|
||||
script.onload = function() {
|
||||
createUnityInstance(canvas, config, function(progress) {
|
||||
progressBarFull.style.width = 100 * progress + "%";
|
||||
}).then(function(instance) {
|
||||
unityInstance = instance;
|
||||
loadingBar.classList.remove('show');
|
||||
|
||||
// 全屏按钮
|
||||
fullscreenButton.onclick = function() {
|
||||
unityInstance.SetFullscreen(1);
|
||||
};
|
||||
}).catch(function(message) {
|
||||
alert('加载失败: ' + message);
|
||||
});
|
||||
};
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
// ========== 监听全屏退出 ==========
|
||||
document.addEventListener('fullscreenchange', function() {
|
||||
if (!document.fullscreenElement && unityInstance) {
|
||||
canvas.style.width = '100%';
|
||||
canvas.style.height = '100%';
|
||||
}
|
||||
});
|
||||
|
||||
// ========== 防止意外滚动 ==========
|
||||
document.addEventListener('gesturestart', function(e) { e.preventDefault(); });
|
||||
</script>
|
||||
</body>
|
||||
</html>`);
|
||||
});
|
||||
|
||||
// 静态文件服务
|
||||
app.use(express.static(ROOT, {
|
||||
setHeaders: (res, filePath) => {
|
||||
// 确保 .wasm 有正确的 MIME type(Chrome 需要)
|
||||
if (filePath.endsWith('.wasm')) {
|
||||
res.setHeader('Content-Type', 'application/wasm');
|
||||
}
|
||||
if (filePath.endsWith('.js')) {
|
||||
res.setHeader('Content-Type', 'application/javascript');
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// 启动服务
|
||||
app.listen(PORT, () => {
|
||||
console.log('');
|
||||
console.log(' ╔══════════════════════════════════════════════════╗');
|
||||
console.log(' ║ 运动伤害现场急救虚拟仿真实验 - WebGL Server ║');
|
||||
console.log(' ║ ║');
|
||||
console.log(' ║ Server running at: http://localhost:' + PORT + ' ║');
|
||||
console.log(' ║ Press Ctrl+C to stop ║');
|
||||
console.log(' ╚══════════════════════════════════════════════════╝');
|
||||
console.log('');
|
||||
});
|
||||
Reference in New Issue
Block a user