饥荒改名年糕生存,优化动画
This commit is contained in:
@@ -28,6 +28,9 @@ const detail = ref(null) // {game, owned, best_score}
|
||||
const phase = ref('loading') // loading / locked / ready / playing / over
|
||||
const liveScore = ref(0) // 实时得分
|
||||
const finalScore = ref(0) // 结束得分
|
||||
const displayName = computed(() => (code === 'starve' ? '年糕求生' : detail.value?.game?.name || '游戏'))
|
||||
const showManual = ref(false)
|
||||
const showSettings = ref(false)
|
||||
const result = ref(null) // 结算响应
|
||||
const useDouble = ref(false) // 是否使用双倍积分卡
|
||||
const bag = ref([]) // 我的道具背包
|
||||
@@ -61,6 +64,31 @@ function onHeadMouseMove(e) {
|
||||
if (!floatHead.value) return
|
||||
headShow.value = e.clientY <= 130
|
||||
}
|
||||
const touchMode = ref(localStorage.getItem('starve_touch_mode') || 'both')
|
||||
function saveTouchMode(mode) {
|
||||
touchMode.value = mode
|
||||
localStorage.setItem('starve_touch_mode', mode)
|
||||
window.dispatchEvent(new CustomEvent('starve-touch-mode', { detail: mode }))
|
||||
}
|
||||
function openManual() {
|
||||
showManual.value = true
|
||||
if (phase.value === 'playing') gameRef.value?.setPaused?.(true)
|
||||
}
|
||||
function closeManual() {
|
||||
showManual.value = false
|
||||
if (phase.value === 'playing') gameRef.value?.setPaused?.(false)
|
||||
}
|
||||
function openSettings() {
|
||||
showSettings.value = true
|
||||
if (phase.value === 'playing') gameRef.value?.setPaused?.(true)
|
||||
}
|
||||
function closeSettings() {
|
||||
showSettings.value = false
|
||||
if (phase.value === 'playing') gameRef.value?.setPaused?.(false)
|
||||
}
|
||||
function togglePause() {
|
||||
gameRef.value?.togglePause?.()
|
||||
}
|
||||
const playHeadClasses = computed(() => ({
|
||||
'play-head-float': floatHead.value,
|
||||
'play-head-hidden': floatHead.value && !headShow.value,
|
||||
@@ -549,10 +577,11 @@ watch(() => coopStore.roomState?.code, (code) => {
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('mousemove', onHeadMouseMove)
|
||||
// play-head 通过吸顶按钮手动展开/收起,不再跟随鼠标自动弹出
|
||||
// 宽屏游戏(如饥荒):给 body 打标解除全局 1200px 限宽
|
||||
if (meta?.wide) document.body.classList.add('wide-page')
|
||||
load()
|
||||
window.addEventListener('nlg:open-manual', openManual)
|
||||
if (coopable) {
|
||||
window.addEventListener('nlg:pending-join', tryPendingJoin)
|
||||
tryPendingJoin()
|
||||
@@ -560,8 +589,9 @@ onMounted(() => {
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
document.body.classList.remove('wide-page')
|
||||
window.removeEventListener('nlg:open-manual', openManual)
|
||||
window.removeEventListener('nlg:pending-join', tryPendingJoin)
|
||||
window.removeEventListener('mousemove', onHeadMouseMove)
|
||||
// play-head 展开状态由组件自行管理
|
||||
clearInterval(inviteTickTimer)
|
||||
gameRef.value?.stop()
|
||||
// 离开游玩页断开联机连接(房间自动退出)
|
||||
@@ -571,18 +601,24 @@ onBeforeUnmount(() => {
|
||||
|
||||
<template>
|
||||
<div v-if="detail" class="play-wrap" :class="{ 'play-fill': meta?.wide }">
|
||||
<button v-if="floatHead" class="head-toggle" @click="headShow = !headShow">
|
||||
{{ headShow ? '▲ 收起' : '☰ 年糕求生' }}
|
||||
</button>
|
||||
<!-- 顶部信息条 -->
|
||||
<div class="play-head panel" :class="playHeadClasses">
|
||||
<button class="btn btn-ghost btn-sm" @click="router.back()">← 返回</button>
|
||||
<GameIcon class="g-icon" :code="code" :icon="detail.game.icon" :size="34" />
|
||||
<div class="g-info">
|
||||
<b>{{ detail.game.name }}</b>
|
||||
<b>{{ displayName }}</b>
|
||||
<span class="text-dim" style="font-size: 12px">{{ meta.controls }}</span>
|
||||
</div>
|
||||
<div class="g-stats">
|
||||
<span class="stat-chip">本局 <b class="text-accent">{{ liveScore }}</b></span>
|
||||
<span class="stat-chip">最高 <b class="text-primary">{{ detail.best_score }}</b></span>
|
||||
<span class="stat-chip">💰 {{ userStore.user?.points ?? 0 }}</span>
|
||||
<button class="btn btn-ghost btn-sm" @click="openManual">📖 手册</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="openSettings">⚙️ 设置</button>
|
||||
<button v-if="phase === 'playing'" class="btn btn-ghost btn-sm" @click="togglePause">⏸ 暂停</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 游戏区域 -->
|
||||
@@ -595,7 +631,7 @@ onBeforeUnmount(() => {
|
||||
<!-- 1. 模式选择 -->
|
||||
<template v-if="coopStage === 'mode'">
|
||||
<div class="ov-icon"><GameIcon :code="code" :icon="detail.game.icon" :size="56" /></div>
|
||||
<h3>{{ detail.game.name }}</h3>
|
||||
<h3>{{ displayName }}</h3>
|
||||
<p class="text-dim ov-desc">{{ detail.game.description }}</p>
|
||||
<div class="mode-cards">
|
||||
<button class="mode-card" @click="coopStage = 'solo'">
|
||||
@@ -617,6 +653,10 @@ onBeforeUnmount(() => {
|
||||
<i>2~4 人共享同一世界</i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="ov-btns">
|
||||
<button class="btn btn-ghost btn-sm" @click="openManual">📖 操作手册</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="openSettings">⚙️ 设置</button>
|
||||
</div>
|
||||
<button class="btn btn-ghost" @click="coopStage = 'skins'">
|
||||
更衣室 · 30 款人物皮肤
|
||||
</button>
|
||||
@@ -783,9 +823,13 @@ onBeforeUnmount(() => {
|
||||
<!-- ============ 普通游戏:原有开始面板 ============ -->
|
||||
<template v-else>
|
||||
<div class="ov-icon"><GameIcon :code="code" :icon="detail.game.icon" :size="levelsMeta ? 40 : 56" /></div>
|
||||
<h3>{{ detail.game.name }}</h3>
|
||||
<h3>{{ displayName }}</h3>
|
||||
<p v-if="!levelsMeta" class="text-dim ov-desc">{{ detail.game.description }}</p>
|
||||
<p class="text-dim" style="font-size: 12px">🎮 {{ meta.controls }}</p>
|
||||
<div class="ov-btns">
|
||||
<button class="btn btn-ghost btn-sm" @click="openManual">📖 操作手册</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="openSettings">⚙️ 设置</button>
|
||||
</div>
|
||||
<label v-if="meta.supports.includes('double_points') && propCount('double_points') > 0" class="double-check">
|
||||
<input v-model="useDouble" type="checkbox" />
|
||||
使用 ✨双倍积分卡(剩 {{ propCount('double_points') }} 张),本局积分翻倍
|
||||
@@ -893,6 +937,54 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作手册 -->
|
||||
<div v-if="showManual" class="modal-mask" @click.self="closeManual">
|
||||
<div class="mod-modal panel manual-modal">
|
||||
<button class="bm-close" @click="closeManual">✕</button>
|
||||
<h3>操作手册</h3>
|
||||
<p class="text-dim" style="font-size: 12px; line-height: 1.6; text-align: left">
|
||||
{{ meta.controls }}<br />
|
||||
移动端:点击地面移动{{ touchMode === 'both' || touchMode === 'joystick' ? ',也可使用左下角摇杆' : '' }};点击目标会自动攻击/采集。<br />
|
||||
快捷键:WASD 移动 · 空格采集 · F 攻击 · C 合成 · M 地图 · P/Esc 暂停。
|
||||
</p>
|
||||
<div class="ov-btns">
|
||||
<button class="btn" @click="closeManual">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设置 -->
|
||||
<div v-if="showSettings" class="modal-mask" @click.self="closeSettings">
|
||||
<div class="mod-modal panel settings-modal">
|
||||
<button class="bm-close" @click="closeSettings">✕</button>
|
||||
<h3>设置</h3>
|
||||
<div class="setting-block">
|
||||
<b>移动端移动方式</b>
|
||||
<div class="setting-options">
|
||||
<button class="chip" :class="{ on: touchMode === 'both' }" @click="saveTouchMode('both')">点击 + 摇杆</button>
|
||||
<button class="chip" :class="{ on: touchMode === 'tap' }" @click="saveTouchMode('tap')">仅点击</button>
|
||||
<button class="chip" :class="{ on: touchMode === 'joystick' }" @click="saveTouchMode('joystick')">仅摇杆</button>
|
||||
</div>
|
||||
<p class="text-dim" style="font-size: 12px">默认都支持;摇杆未选中时自动隐藏。</p>
|
||||
</div>
|
||||
<div class="setting-block">
|
||||
<b>PC 快捷键</b>
|
||||
<ul class="shortcut-list">
|
||||
<li><span>WASD / 方向键</span>移动</li>
|
||||
<li><span>空格</span>采集 / 交互</li>
|
||||
<li><span>F</span>攻击</li>
|
||||
<li><span>1~9</span>使用物品栏</li>
|
||||
<li><span>C</span>合成</li>
|
||||
<li><span>M</span>地图</li>
|
||||
<li><span>P / Esc</span>暂停 / 继续</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="ov-btns">
|
||||
<button class="btn" @click="closeSettings">完成</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 未拥有提示 -->
|
||||
@@ -1657,4 +1749,55 @@ onBeforeUnmount(() => {
|
||||
.overlay.room-entry {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 二级导航:吸顶小按钮手动展开/收起,不随鼠标弹出 */
|
||||
.head-toggle {
|
||||
position: fixed;
|
||||
top: 2px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 160;
|
||||
padding: 4px 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-panel);
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
/* 手册/设置弹窗 */
|
||||
.manual-modal,
|
||||
.settings-modal {
|
||||
width: min(560px, 100%);
|
||||
text-align: left;
|
||||
}
|
||||
.setting-block {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 12px 14px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.setting-options {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.shortcut-list {
|
||||
margin: 8px 0 0;
|
||||
padding-left: 18px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.shortcut-list span {
|
||||
display: inline-block;
|
||||
min-width: 96px;
|
||||
color: var(--primary-2);
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user