game/index.html

250 lines
13 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, viewport-fit=cover" />
<title>宇森 · Yusen活的文明系统模拟</title>
<link rel="stylesheet" href="assets/fonts/yusen-fonts.css" />
<link rel="icon" type="image/png" sizes="48x48" href="assets/ui/logo_planet_48.png?v=20260723">
<link rel="icon" type="image/png" sizes="256x256" href="assets/ui/logo_planet_256.png?v=20260723">
<link rel="apple-touch-icon" href="assets/ui/logo_planet_256.png?v=20260723">
<link rel="stylesheet" href="assets/common.css" />
<!-- 首屏 hero 图预加载,提升 LCP -->
<link rel="preload" as="image" href="assets/slides/01_starry_sky.webp" fetchpriority="high">
<style>
/* ===== 首页:全屏 hero 轮播 ===== */
html,body{height:100%;width:100%;overflow:hidden;}
.home-main{flex:1;display:flex;flex-direction:column;position:relative;overflow:hidden;}
.hero{position:relative;flex:1;border-radius:0;overflow:hidden;min-height:0;}
.hero .slideshow{position:absolute;inset:0;overflow:hidden;}
.hero .slide-track{position:absolute;inset:0;display:flex;flex-direction:column;transition:transform 1.25s cubic-bezier(0.4,0,0.2,1);will-change:transform;}
.hero .slide{flex:0 0 100%;width:100%;height:100%;background-size:cover;background-position:center;position:relative;}
.hero .slide::before{content:"";position:absolute;inset:0;
background:linear-gradient(90deg, rgba(8,12,26,.92) 0%, rgba(8,12,26,.70) 22%, rgba(8,12,26,.40) 40%, transparent 58%),
linear-gradient(180deg, rgba(8,12,26,.55) 0%, transparent 35%);}
.hero .copy{position:absolute;left:56px;top:56px;z-index:3;pointer-events:none;}
.hero .copy h1{font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:56px;letter-spacing:10px;color:#fff;text-shadow:0 2px 24px rgba(0,0,0,.9),0 0 32px rgba(139,92,246,.7);line-height:1.2;}
.hero .copy .sub2{font-family:"Press Start 2P",monospace;font-size:11px;color:var(--gold);margin:6px 0 0;letter-spacing:2px;text-shadow:0 1px 8px rgba(0,0,0,.9);}
.hero .copy .tag{font-size:20px;font-weight:500;color:#e8ecf6;margin-top:4px;text-shadow:0 1px 10px rgba(0,0,0,.85);}
/* 轮播文字(左下) */
.slide-label{position:absolute;left:56px;bottom:72px;z-index:4;pointer-events:none;opacity:0;transform:translateY(16px);transition:opacity .8s ease, transform .8s ease;}
.slide.active .slide-label{opacity:1;transform:translateY(0);}
.slide-label .sl-en{font-family:"Press Start 2P",monospace;font-size:13px;color:var(--cyan);letter-spacing:3px;margin-bottom:10px;display:block;text-shadow:0 1px 8px rgba(0,0,0,.9);}
.slide-label .sl-cn{font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:46px;letter-spacing:7px;color:#fff;text-shadow:0 2px 22px rgba(0,0,0,.95),0 0 30px rgba(139,92,246,.65);line-height:1.25;}
.slide-label .sl-desc{font-size:16px;color:#c8d2ec;margin-top:12px;max-width:500px;line-height:1.85;text-shadow:0 1px 8px rgba(0,0,0,.88);}
/* 右下指示器 */
.sl-dots{position:absolute;right:40px;bottom:96px;z-index:5;display:flex;flex-direction:column;gap:14px;pointer-events:auto;}
.sl-dot{width:12px;height:12px;border-radius:50%;background:rgba(255,255,255,.22);border:1px solid rgba(255,255,255,.4);cursor:pointer;transition:.3s;flex:0 0 auto;}
.sl-dot:hover{background:rgba(255,255,255,.5);}
.sl-dot.active{background:var(--gold);border-color:var(--gold);box-shadow:0 0 12px rgba(231,184,92,.6);transform:scale(1.15);}
/* 左右箭头 */
.sl-arrow{position:absolute;top:50%;z-index:6;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;border:1px solid rgba(255,255,255,.15);background:rgba(8,12,26,.55);backdrop-filter:blur(8px);color:#e8ecf6;font-size:22px;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;}
.sl-arrow:hover{background:rgba(139,92,246,.25);border-color:rgba(139,92,246,.4);transform:translateY(-50%) scale(1.08);}
.sl-arrow.prev{left:16px;}
.sl-arrow.next{right:16px;}
/* 起源历史(右上竖排) */
.slide-origin{position:absolute;right:72px;top:48px;z-index:4;pointer-events:none;writing-mode:vertical-rl;text-orientation:upright;
font-family:"Noto Sans SC",sans-serif;font-size:16px;font-weight:500;letter-spacing:3px;line-height:1.55;color:rgba(240,244,252,.94);
text-shadow:0 1px 3px rgba(0,0,0,.92);max-height:34vh;overflow:hidden;
opacity:0;transform:translateY(-12px);transition:opacity .9s ease .25s, transform .9s ease .25s;}
.slide.active .slide-origin{opacity:1;transform:translateY(0);}
.slide-origin .so-tag{color:var(--gold);font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:19px;letter-spacing:5px;margin-bottom:7px;text-shadow:0 1px 4px rgba(0,0,0,.92),0 0 10px rgba(231,184,92,.45);}
/* 进入游戏按钮(底部) */
.hero .enter-wrap{position:absolute;left:0;right:0;bottom:32px;display:flex;justify-content:center;z-index:5;}
.hero .enter-btn{
font-family:"Noto Sans SC",sans-serif;font-size:17px;font-weight:600;color:#0b1020;
background:linear-gradient(135deg, #f0d49a, #e7b85c, #f0d49a);
padding:14px 48px;border-radius:30px;cursor:pointer;border:1px solid rgba(255,255,255,.3);
box-shadow:0 4px 14px rgba(231,184,92,.35), inset 0 1px 0 rgba(255,255,255,.4);
letter-spacing:2px;transition:.2s;
}
.hero .enter-btn:hover{
filter:brightness(1.08);transform:translateY(-2px);
box-shadow:0 6px 20px rgba(231,184,92,.5), inset 0 1px 0 rgba(255,255,255,.5);
}
.hero .enter-btn:active{transform:translateY(0);}
/* ===== 响应式 ===== */
@media (max-width:900px){
.hero .copy h1{font-size:42px;}
}
@media (max-width:768px){
.hero .copy{left:18px;top:28px;}
.hero .copy h1{font-size:30px;letter-spacing:5px;}
.hero .copy .tag{font-size:15px;}
.slide-label{left:18px;bottom:78px;}
.slide-label .sl-cn{font-size:24px;letter-spacing:3px;}
.slide-label .sl-desc{font-size:13px;max-width:100%;}
.sl-dots{right:16px;gap:10px;}
.hero .enter-btn{font-size:15px;padding:11px 30px;}
}
</style>
</head>
<body>
<div class="app">
<header class="topbar">
<a href="index.html" class="logo"><span class="cn">宇森</span></a>
<nav class="nav">
<a href="announce.html">公告</a>
<a href="background.html">背景</a>
<a href="rules.html">规则</a>
<a href="codex.html">图鉴</a>
<a href="story.html">剧情</a>
<a href="forum.html" class="auth-only">论坛</a>
<a href="worlddata.html" class="auth-only">世界数据</a>
</nav>
<div class="spacer"></div>
<div class="user-box" id="userBox"></div>
</header>
<main class="home-main">
<section class="hero">
<div class="slideshow" id="slideshow"></div>
<div class="copy">
<h1>宇森 &#183; Yusen</h1>
<div class="sub2">LIVING CIVILIZATION SIMULATOR</div>
<div class="tag">活的文明系统模拟</div>
</div>
<button class="sl-arrow prev" id="slPrev" aria-label="上一张"></button>
<button class="sl-arrow next" id="slNext" aria-label="下一张"></button>
<div class="enter-wrap">
<button class="enter-btn" id="enterGame">⚔ 进入游戏</button>
</div>
</section>
</main>
</div>
<script src="assets/game-api.js"></script>
<script src="assets/common.js"></script>
<script>
// ============ 五层世界图片轮播 ============
(function(){
const slides = [
{ img:'assets/slides/01_starry_sky.webp', en:'STARRY SKY', cn:'星空', desc:'陨石星空带悬浮于世界最外层,是文明触及维度的起点。星轨连通各浮空岛,穹鎏晶体自星尘中凝结。',
origin:'世界未形,星尘先于万物浮游于虚无。首缕维度自星隙坍缩成形,穹鎏晶体由尘凝就,文明自此仰望苍穹之始。' },
{ img:'assets/slides/02_sky.webp', en:'SKY', cn:'天空', desc:'云朵地基块托起浮空岛群,灵气复苏的第一缕风拂过。各族初代聚落,在此仰望也更在此扎根。',
origin:'云基初结,浮空岛群自苍穹垂落凡尘。灵气复苏,初民循风而居,于云上筑城,仰望亦扎根,道统由此萌发。' },
{ img:'assets/slides/03_earth.webp', en:'EARTH', cn:'大地', desc:'平原与森林铺展成万物生灵的摇篮,玄荒文明于斯鼎盛。城邦林立,征伐与道统在沃土上并行。',
origin:'沃野铺展为万灵摇篮,玄荒先族自林泉走出。城邦并起,征伐与道统并驰沃土之上,文明于此鼎盛绵延。' },
{ img:'assets/slides/04_underground.webp',en:'UNDERGROUND',cn:'地下', desc:'溶洞晶矿与暗河在深处低语,冥玉生于幽暗玉石之中。地心工坊调度浅层资源,灯火不熄。',
origin:'溶洞深开,晶矿与暗河在幽处低语。冥玉生于幽玉深心,地心工坊取浅层之资,灯火长明,匠魂不熄。' },
{ img:'assets/slides/05_core.webp', en:'CORE', cn:'地心', desc:'熔岩奔流的地心,是世界诞生的本源。元玺在此凝聚,追溯天地初开的那一瞬永恒。',
origin:'熔岩奔流处,乃世界本源所钟。元玺于亿载炽火中凝聚成形,溯天地初开一瞬,万物归处,亦是起始。' }
];
const container = document.getElementById('slideshow');
if (!container) return;
let current = 0, timer = null;
const INTERVAL = 5500;
// 预加载所有图(消除切换空白)
slides.forEach(s => { const img = new Image(); img.src = s.img; });
// 缩略图(保留兼容)
const track = document.createElement('div');
track.className = 'slide-track';
container.appendChild(track);
slides.forEach((s,i)=>{
const el = document.createElement('div');
el.className = 'slide' + (i===0 ? ' active' : '');
el.style.backgroundImage = "url('" + s.img + "')";
el.innerHTML =
'<div class="slide-label"><span class="sl-en">' + s.en + '</span><div class="sl-cn">' + s.cn + '</div><div class="sl-desc">' + s.desc + '</div></div>' +
'<div class="slide-origin"><span class="so-tag">起源</span>' + s.origin + '</div>';
track.appendChild(el);
});
const all = track.querySelectorAll('.slide');
// 指示器
const dotsWrap = document.createElement('div');
dotsWrap.className = 'sl-dots';
slides.forEach((_,i)=>{
const d = document.createElement('div');
d.className = 'sl-dot' + (i===0 ? ' active' : '');
d.addEventListener('click', ()=> go(i));
dotsWrap.appendChild(d);
});
document.querySelector('.hero').appendChild(dotsWrap);
const dots = dotsWrap.querySelectorAll('.sl-dot');
// 箭头按钮
const prevBtn = document.getElementById('slPrev');
const nextBtn = document.getElementById('slNext');
if (prevBtn) prevBtn.addEventListener('click', ()=> { prev(); resetTimer(); });
if (nextBtn) nextBtn.addEventListener('click', ()=> { next(); resetTimer(); });
function go(idx){
if (idx<0) idx = slides.length-1;
if (idx>=slides.length) idx = 0;
if (idx === current) return;
all[current].classList.remove('active');
dots[current].classList.remove('active');
current = idx;
track.style.transform = 'translateY(' + (-current*100) + '%)';
all[current].classList.add('active');
dots[current].classList.add('active');
resetTimer();
}
function next(){ go((current+1) % slides.length); }
function prev(){ go((current-1+slides.length) % slides.length); }
function resetTimer(){ clearInterval(timer); timer = setInterval(next, INTERVAL); }
// 滚轮切换
let lock = false, wAccum = 0;
document.querySelector('.hero').addEventListener('wheel', (e)=>{
wAccum += e.deltaY;
if (lock) return;
if (Math.abs(wAccum) > 50){
lock = true;
wAccum > 0 ? next() : prev();
wAccum = 0;
setTimeout(()=> { lock=false; }, 1250);
}
}, {passive:true});
// 键盘
document.addEventListener('keydown', (e)=>{
if (e.key === 'ArrowLeft') prev();
if (e.key === 'ArrowRight') next();
});
// 触屏
const hero = document.querySelector('.hero');
let tx=0, ty=0;
hero.addEventListener('touchstart', (e)=>{
const t = e.touches[0];
tx = t.clientX; ty = t.clientY;
}, {passive:true});
hero.addEventListener('touchend', (e)=>{
const t = e.changedTouches[0];
const dx = t.clientX - tx, dy = t.clientY - ty;
if (Math.abs(dy) > Math.abs(dx) && Math.abs(dy) > 50){
dy > 0 ? prev() : next();
}
}, {passive:true});
resetTimer();
})();
// ============ 进入游戏 ============
document.getElementById('enterGame').addEventListener('click', async ()=>{
try {
const me = await API.me();
if (me && me.uid) location.href = 'world.html';
else location.href = 'login.html?next=world.html';
} catch(e) {
location.href = 'login.html?next=world.html';
}
});
</script>
</body>
</html>