年糕生存游戏

This commit is contained in:
李琦
2026-08-15 16:46:17 +08:00
parent e70b7aa3d7
commit eca29aecc8
6 changed files with 854 additions and 25 deletions

View File

@@ -70,10 +70,30 @@ function saveTouchMode(mode) {
localStorage.setItem('starve_touch_mode', mode)
window.dispatchEvent(new CustomEvent('starve-touch-mode', { detail: mode }))
}
const isMobile = computed(() => typeof window !== 'undefined' && ('ontouchstart' in window || navigator.maxTouchPoints > 0))
const isPortrait = ref(false)
let portraitMq = null
function updateOrientation() {
isPortrait.value = isMobile.value && !!portraitMq?.matches
}
async function enterLandscape() {
try {
if (document.fullscreenElement) await document.exitFullscreen()
await document.documentElement.requestFullscreen?.()
} catch (e) {}
try {
await screen.orientation?.lock?.('landscape')
} catch (e) {}
updateOrientation()
}
function openManual() {
showManual.value = true
if (phase.value === 'playing') gameRef.value?.setPaused?.(true)
}
function toggleHeadNav() {
headShow.value = !headShow.value
window.dispatchEvent(new CustomEvent('nlg:starve-nav-toggle'))
}
function closeManual() {
showManual.value = false
if (phase.value === 'playing') gameRef.value?.setPaused?.(false)
@@ -581,11 +601,17 @@ onMounted(() => {
// 宽屏游戏(如饥荒):给 body 打标解除全局 1200px 限宽
if (meta?.wide) document.body.classList.add('wide-page')
load()
portraitMq = window.matchMedia('(orientation: portrait)')
window.addEventListener('nlg:open-settings', openSettings)
portraitMq.addEventListener('change', updateOrientation)
updateOrientation()
window.addEventListener('nlg:open-manual', openManual)
if (coopable) {
window.addEventListener('nlg:pending-join', tryPendingJoin)
tryPendingJoin()
}
portraitMq?.removeEventListener('change', updateOrientation)
window.removeEventListener('nlg:open-settings', openSettings)
})
onBeforeUnmount(() => {
document.body.classList.remove('wide-page')
@@ -600,8 +626,8 @@ onBeforeUnmount(() => {
</script>
<template>
<div v-if="detail" class="play-wrap" :class="{ 'play-fill': meta?.wide }">
<button v-if="floatHead" class="head-toggle" @click="headShow = !headShow">
<div v-if="detail" class="play-wrap" :class="{ 'play-fill': meta?.wide, 'starve-ui': code === 'starve' }">
<button v-if="floatHead" class="head-toggle" @click="toggleHeadNav">
{{ headShow ? ' 收起' : ' 年糕求生' }}
</button>
<!-- 顶部信息条 -->
@@ -985,6 +1011,16 @@ onBeforeUnmount(() => {
</div>
</div>
</div>
<div v-if="floatHead && isPortrait" class="landscape-tip">
<div class="landscape-card">
<div class="landscape-icon">📱</div>
<h3>请横屏游玩</h3>
<p class="text-dim">年糕求生建议横屏操作点击按钮自动进入横屏</p>
<button class="btn" @click="enterLandscape">进入横屏</button>
<button class="btn btn-ghost" @click="isPortrait = false">暂不</button>
</div>
</div>
</div>
<!-- 未拥有提示 -->
@@ -1800,4 +1836,172 @@ onBeforeUnmount(() => {
color: var(--primary-2);
font-weight: 700;
}
/* ---- 移动端横屏提示 ---- */
.landscape-tip {
position: fixed;
inset: 0;
z-index: 400;
background: rgba(8, 5, 4, 0.82);
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.landscape-card {
background: linear-gradient(180deg, #2b2115, #17120b);
border: 2px solid #b89a5c;
border-radius: 18px;
padding: 26px 30px;
text-align: center;
display: flex;
flex-direction: column;
gap: 12px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
}
.landscape-icon {
font-size: 54px;
}
/* ---- 年糕求生 UI游戏内弹窗/面板统一手绘木纸风格 ---- */
.play-wrap.starve-ui .modal-mask {
background: rgba(10, 7, 4, 0.62);
}
.play-wrap.starve-ui .mod-modal,
.play-wrap.starve-ui .modal-mask .mod-modal {
background: linear-gradient(180deg, #2b2115, #17120b);
border: 2px solid #b89a5c;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
color: #f4ead2;
}
.play-wrap.starve-ui .btn-ghost {
background: rgba(42, 32, 18, 0.9);
border-color: #6f5b38;
color: #f4ead2;
}
.play-wrap.starve-ui .play-head {
background: linear-gradient(180deg, #2b2115, #17120b);
border: 2px solid #b89a5c;
}
.play-wrap.starve-ui .stat-chip {
background: rgba(42, 32, 18, 0.9);
border-color: #6f5b38;
}
.play-wrap.starve-ui .head-toggle {
background: #2b2115;
border-color: #b89a5c;
color: #f4ead2;
}
.play-wrap.starve-ui .mod-card {
background: rgba(42, 32, 18, 0.9);
border-color: #6f5b38;
}
.play-wrap.starve-ui .mod-card:hover {
border-color: #e8bc5a;
}
.play-wrap.starve-ui .btn {
border-radius: 10px;
border-color: #b89a5c;
background: linear-gradient(180deg, #5a4327, #3a2b17);
color: #f4ead2;
}
.play-wrap.starve-ui .mode-card {
background: rgba(42, 32, 18, 0.92);
border-color: #6f5b38;
border-radius: 14px;
}
.play-wrap.starve-ui .mode-card:hover {
border-color: #e8bc5a;
}
.play-wrap.starve-ui .join-row,
.play-wrap.starve-ui .overlay.room-entry .ov-btns {
background: rgba(42, 32, 18, 0.9);
border-color: #6f5b38;
}
.play-wrap.starve-ui .join-input {
background: #17120b;
border-color: #b89a5c;
color: #f4ead2;
}
.play-wrap.starve-ui .mod-modal h3 {
color: #f4ead2;
}
/* 更强的饥荒主题:羊皮纸/木箱/铜扣 */
.play-wrap.starve-ui .mod-modal,
.play-wrap.starve-ui .manual-modal,
.play-wrap.starve-ui .settings-modal {
background:
radial-gradient(circle at 12% 10%, rgba(232, 188, 90, 0.16), transparent 32%),
repeating-linear-gradient(90deg, rgba(0,0,0,0.06) 0 2px, transparent 2px 14px),
linear-gradient(180deg, #33261a, #17120b);
border: 2px solid #b89a5c;
box-shadow:
inset 0 0 0 4px #241a10,
0 12px 40px rgba(0, 0, 0, 0.6);
color: #f4ead2;
}
.play-wrap.starve-ui .mod-modal h3,
.play-wrap.starve-ui .manual-modal h3,
.play-wrap.starve-ui .settings-modal h3 {
font-family: "Ma Shan Zheng", "KaiTi", serif;
letter-spacing: 2px;
color: #f4d68a;
text-shadow: 2px 2px 0 #17120b;
}
.play-wrap.starve-ui .btn,
.play-wrap.starve-ui .btn-ghost {
position: relative;
font-family: "Ma Shan Zheng", "KaiTi", serif;
letter-spacing: 1px;
border: 1.6px solid #b89a5c;
background:
linear-gradient(180deg, rgba(255,255,255,0.08), transparent 45%),
linear-gradient(180deg, #5a4327, #2b1d10);
box-shadow: inset 0 0 0 2px #1d1409, 0 3px 0 #0d0906;
text-shadow: 1px 1px 0 #0d0906;
}
.play-wrap.starve-ui .btn:hover,
.play-wrap.starve-ui .btn-ghost:hover {
border-color: #f0c04a;
color: #fff2c0;
}
.play-wrap.starve-ui .mode-card {
background:
radial-gradient(circle at 50% 0%, rgba(232, 188, 90, 0.18), transparent 45%),
linear-gradient(180deg, #302213, #17120b);
box-shadow: inset 0 0 0 3px #1d1409, 0 6px 16px rgba(0,0,0,0.35);
font-family: "Ma Shan Zheng", "KaiTi", serif;
}
.play-wrap.starve-ui .overlay.room-entry .ov-btns,
.play-wrap.starve-ui .join-row {
background:
linear-gradient(180deg, rgba(232,188,90,0.08), transparent),
linear-gradient(180deg, #302213, #17120b);
box-shadow: inset 0 0 0 2px #1d1409;
}
.play-wrap.starve-ui .mod-modal,
.play-wrap.starve-ui .manual-modal,
.play-wrap.starve-ui .settings-modal,
.play-wrap.starve-ui .mode-card,
.play-wrap.starve-ui .mod-card,
.play-wrap.starve-ui .join-row,
.play-wrap.starve-ui .join-input {
border-radius: 0;
image-rendering: pixelated;
}
.play-wrap.starve-ui .bm-close {
width: 30px;
height: 30px;
padding: 0;
border: 2px solid #b89a5c;
background: #2b2115;
color: #f4ead2;
font-size: 14px;
line-height: 1;
}
.play-wrap.starve-ui .mod-card-check {
border-radius: 0;
}
</style>