更新
This commit is contained in:
@@ -5,7 +5,7 @@
|
|||||||
v-if="src && !imageFailed"
|
v-if="src && !imageFailed"
|
||||||
class="food-tile-icon__img"
|
class="food-tile-icon__img"
|
||||||
:src="src"
|
:src="src"
|
||||||
:mode="size === 'tile' ? 'aspectFill' : 'aspectFit'"
|
mode="aspectFit"
|
||||||
@error="onImageError"
|
@error="onImageError"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
@@ -71,6 +71,11 @@ function onImageError() {
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 玻璃格上的食材图片:投影增强立体感(参考稿) */
|
||||||
|
.food-tile-icon--tile .food-tile-icon__img {
|
||||||
|
filter: drop-shadow(0 6rpx 10rpx rgba(0, 0, 0, 0.16));
|
||||||
|
}
|
||||||
|
|
||||||
.food-tile-icon--goal {
|
.food-tile-icon--goal {
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
|
|||||||
@@ -125,30 +125,28 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- Header HUD -->
|
<!-- Header HUD -->
|
||||||
<view class="gg-header gg-glass" :style="headerStyle">
|
<view class="gg-header" :style="headerStyle">
|
||||||
<!-- 顶部导航与全局状态 -->
|
<!-- 顶部导航与全局状态 -->
|
||||||
<view class="gg-hud-nav" :style="navStyle">
|
<view class="gg-hud-nav" :style="navStyle">
|
||||||
<!-- 左侧控制组 -->
|
<!-- 左:返回 -->
|
||||||
|
<view class="gg-hud-btn" hover-class="gg-hud-btn--pressed" @tap="goBack">
|
||||||
|
<TongjiIcon name="chevron-left" size="md" color="#006c4b" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 绝对居中的关卡 -->
|
||||||
|
<view class="gg-hud-level-center">
|
||||||
|
<text class="gg-hud-level-text">第 {{ levelConfig.id }} 关</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 右:声音 -->
|
||||||
<view class="gg-hud-control-group">
|
<view class="gg-hud-control-group">
|
||||||
<view class="gg-hud-btn" hover-class="gg-hud-btn--pressed" @tap="goBack">
|
|
||||||
<TongjiIcon name="chevron-left" size="md" color="#006c49" />
|
|
||||||
</view>
|
|
||||||
<view
|
<view
|
||||||
class="gg-hud-btn"
|
class="gg-hud-btn"
|
||||||
:class="{ 'is-muted': !sfxEnabled }"
|
:class="{ 'is-muted': !sfxEnabled }"
|
||||||
hover-class="gg-hud-btn--pressed"
|
hover-class="gg-hud-btn--pressed"
|
||||||
@tap="onSoundToggle"
|
@tap="onSoundToggle"
|
||||||
>
|
>
|
||||||
<TongjiIcon name="volume" size="md" :color="sfxEnabled ? '#006c49' : '#94a3b8'" />
|
<TongjiIcon name="volume" size="md" :color="sfxEnabled ? '#006c4b' : '#94a3b8'" />
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 绝对居中的关卡与得分 -->
|
|
||||||
<view class="gg-hud-level-center">
|
|
||||||
<text class="gg-hud-level-text">第 {{ levelConfig.id }} 组</text>
|
|
||||||
<view class="gg-hud-score" :class="{ 'is-pop': scoreAnimating }">
|
|
||||||
<text class="gg-hud-score-val">{{ scoreText }}</text>
|
|
||||||
<text class="gg-hud-score-unit">分</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -156,49 +154,40 @@
|
|||||||
|
|
||||||
<!-- 主区:棋盘为主,辅助信息弱化 -->
|
<!-- 主区:棋盘为主,辅助信息弱化 -->
|
||||||
<view class="gg-main" :style="mainStyle">
|
<view class="gg-main" :style="mainStyle">
|
||||||
<!-- 次:仅展示上次消除的食物与含糖量 -->
|
<!-- 信息横幅:默认为玩法提示;消除后展示该食物的含糖与建议 -->
|
||||||
<view v-if="gamePhase === 'playing'" class="gg-hud-last-food">
|
<view
|
||||||
<view class="gg-hud-last-food-head">
|
v-if="gamePhase === 'playing'"
|
||||||
<text class="gg-hud-last-food-kicker">上次消除</text>
|
class="gg-info-banner"
|
||||||
<view
|
:class="lastClearedFood ? 'is-food is-' + lastClearedFood.gi : ''"
|
||||||
v-if="lastClearedFood"
|
>
|
||||||
class="gg-hud-last-food-chip"
|
<!-- 已消除:食物含糖 + 建议 -->
|
||||||
:class="'is-' + lastClearedFood.gi"
|
<template v-if="lastClearedFood">
|
||||||
>
|
<view class="gg-info-banner-icon is-food" :class="'is-' + lastClearedFood.gi">
|
||||||
<text class="gg-hud-last-food-chip-dot"></text>
|
|
||||||
<text class="gg-hud-last-food-chip-text">{{ lastClearedFood.giShort }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
v-if="lastClearedFood"
|
|
||||||
class="gg-hud-last-food-card"
|
|
||||||
:class="'is-' + lastClearedFood.gi"
|
|
||||||
>
|
|
||||||
<view class="gg-hud-last-food-icon" :class="'is-' + lastClearedFood.gi">
|
|
||||||
<FoodTileIcon :food="lastClearedFood.food" size="goal" />
|
<FoodTileIcon :food="lastClearedFood.food" size="goal" />
|
||||||
</view>
|
</view>
|
||||||
<view class="gg-hud-last-food-body">
|
<view class="gg-info-banner-body">
|
||||||
<text class="gg-hud-last-food-name">{{ lastClearedFood.name }}</text>
|
<view class="gg-info-food-head">
|
||||||
<view class="gg-hud-last-food-sugar-row">
|
<text class="gg-info-food-name">{{ lastClearedFood.name }}</text>
|
||||||
<view class="gg-hud-last-food-gi" :class="'is-' + lastClearedFood.gi">
|
<view class="gg-info-food-gi" :class="'is-' + lastClearedFood.gi">
|
||||||
<text class="gg-hud-last-food-gi-text">含糖 {{ lastClearedFood.giShort }}</text>
|
<text class="gg-info-food-gi-text">含糖{{ lastClearedFood.giShort }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="gg-hud-last-food-sugar-hint">{{ lastClearedFood.eatHint }}</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
<text class="gg-info-food-tip" :class="'is-' + lastClearedFood.gi">{{ lastClearedFood.tip }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</template>
|
||||||
<view v-else class="gg-hud-last-food-placeholder">
|
<!-- 默认:玩法提示 -->
|
||||||
<view class="gg-hud-last-food-placeholder-dot" aria-hidden="true"></view>
|
<template v-else>
|
||||||
<text>三连消除后,这里显示食物名称与含糖量</text>
|
<view class="gg-info-banner-icon">
|
||||||
</view>
|
<TongjiIcon name="info" size="md" color="#ffffff" />
|
||||||
|
</view>
|
||||||
|
<view class="gg-info-banner-body">
|
||||||
|
<text class="gg-info-banner-text"><text class="gg-info-banner-kw">认糖:</text>点击食物看含糖量 · 消除红色「高」即过关</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 主:棋盘 -->
|
<!-- 主:棋盘 -->
|
||||||
<view class="gg-board-hero">
|
<view class="gg-board-hero">
|
||||||
<view v-if="gamePhase === 'playing'" class="gg-board-hint-inline">
|
|
||||||
<text class="gg-hint-tag">认糖</text>
|
|
||||||
<text class="gg-board-hint-text">点食物看含糖 · 消掉红色「高」即过关</text>
|
|
||||||
</view>
|
|
||||||
<view class="gg-board-stack" :style="boardStackStyle">
|
<view class="gg-board-stack" :style="boardStackStyle">
|
||||||
<view class="gg-board-zone">
|
<view class="gg-board-zone">
|
||||||
<view v-if="hintTipVisible" class="gg-no-move-tip">
|
<view v-if="hintTipVisible" class="gg-no-move-tip">
|
||||||
@@ -265,8 +254,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 辅:道具栏(弱化) -->
|
<!-- 辅:底部道具栏 -->
|
||||||
<view class="gg-footer gg-glass gg-footer--sub" :style="footerStyle">
|
<view class="gg-footer" :style="footerStyle">
|
||||||
<view class="gg-boosters">
|
<view class="gg-boosters">
|
||||||
<view
|
<view
|
||||||
v-for="booster in boosters"
|
v-for="booster in boosters"
|
||||||
@@ -276,9 +265,11 @@
|
|||||||
:class="{ 'is-disabled': booster.count <= 0 }"
|
:class="{ 'is-disabled': booster.count <= 0 }"
|
||||||
@tap="onBooster(booster)"
|
@tap="onBooster(booster)"
|
||||||
>
|
>
|
||||||
<view class="gg-booster-count" :class="booster.countClass">{{ booster.count }}</view>
|
<view class="gg-booster-tile">
|
||||||
<view class="gg-booster-icon">
|
<view class="gg-booster-icon">
|
||||||
<TongjiIcon :name="booster.icon" size="xl" :color="booster.color" />
|
<TongjiIcon :name="booster.icon" size="xl" :color="booster.color" />
|
||||||
|
</view>
|
||||||
|
<view class="gg-booster-count" :class="booster.countClass">{{ booster.count }}</view>
|
||||||
</view>
|
</view>
|
||||||
<text class="gg-booster-label">{{ booster.label }}</text>
|
<text class="gg-booster-label">{{ booster.label }}</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -336,8 +327,8 @@ const COL_AXES = Array.from({ length: COLS }, (_, i) => i)
|
|||||||
const BOARD_INSET_RPX = 4
|
const BOARD_INSET_RPX = 4
|
||||||
/** 棋盘与底部道具栏之间的安全间隙,避免最后一行被遮挡 */
|
/** 棋盘与底部道具栏之间的安全间隙,避免最后一行被遮挡 */
|
||||||
const BOARD_FOOTER_GAP_RPX = 28
|
const BOARD_FOOTER_GAP_RPX = 28
|
||||||
const GRID_PAD_RPX = 8
|
const GRID_PAD_RPX = 18
|
||||||
const GRID_GAP_RPX = 8
|
const GRID_GAP_RPX = 14
|
||||||
const SWAP_MS = 280
|
const SWAP_MS = 280
|
||||||
const MATCH_MS = 400
|
const MATCH_MS = 400
|
||||||
const GRAVITY_MS = 300
|
const GRAVITY_MS = 300
|
||||||
@@ -360,6 +351,21 @@ const activeFoods = ref([])
|
|||||||
const sessionHighFood = ref(null)
|
const sessionHighFood = ref(null)
|
||||||
const goalDefs = ref([])
|
const goalDefs = ref([])
|
||||||
|
|
||||||
|
/** 解锁高糖三连所需的有效操作次数(约 8 步内才有机会消除红色) */
|
||||||
|
const HIGH_UNLOCK_MOVES = 7
|
||||||
|
/** 解锁前棋盘固定保留的高糖数量(<3 无法三连,故无法消除) */
|
||||||
|
const HIGH_COUNT_LOCKED = 2
|
||||||
|
/** 解锁后棋盘至少保留的高糖数量(够凑三连) */
|
||||||
|
const HIGH_COUNT_UNLOCKED = 3
|
||||||
|
/** 解锁后高糖数量上限,避免刷屏 */
|
||||||
|
const HIGH_COUNT_MAX = 6
|
||||||
|
/** 解锁后每次补格生成高糖的概率 */
|
||||||
|
const HIGH_SPAWN_P = 0.16
|
||||||
|
/** 非高糖棋子的最小种类数,保证棋盘有足够变化 */
|
||||||
|
const MIN_NON_HIGH_TYPES = 4
|
||||||
|
/** 本局玩家有效操作次数(成功消除的交换计为一次) */
|
||||||
|
const playerMoves = ref(0)
|
||||||
|
|
||||||
function pickRandom(pool, n) {
|
function pickRandom(pool, n) {
|
||||||
const arr = [...pool]
|
const arr = [...pool]
|
||||||
for (let i = arr.length - 1; i > 0; i--) {
|
for (let i = arr.length - 1; i > 0; i--) {
|
||||||
@@ -379,13 +385,26 @@ function selectSessionFoods() {
|
|||||||
if (Array.isArray(fixedKeys) && fixedKeys.length) {
|
if (Array.isArray(fixedKeys) && fixedKeys.length) {
|
||||||
const fixed = fixedKeys.map((k) => getFoodByKey(k)).filter(Boolean)
|
const fixed = fixedKeys.map((k) => getFoodByKey(k)).filter(Boolean)
|
||||||
const fixedHighs = fixed.filter((f) => f.gi === 'high')
|
const fixedHighs = fixed.filter((f) => f.gi === 'high')
|
||||||
|
const fixedNonHighs = fixed.filter((f) => f.gi !== 'high')
|
||||||
|
// 每关只允许一种高糖:从固定高糖里随机取 1 种
|
||||||
const fixedHighPick = pickRandom(fixedHighs, 1)
|
const fixedHighPick = pickRandom(fixedHighs, 1)
|
||||||
sessionHighFood.value = fixedHighPick[0] ? cloneFoodType(fixedHighPick[0]) : null
|
sessionHighFood.value = fixedHighPick[0] ? cloneFoodType(fixedHighPick[0]) : null
|
||||||
|
|
||||||
activeFoods.value = fixed
|
// 非高糖种类不足时,用随机低糖补足,保证棋盘有变化
|
||||||
warmUpFoodImgs(fixed)
|
const nonHigh = [...fixedNonHighs]
|
||||||
|
if (nonHigh.length < MIN_NON_HIGH_TYPES) {
|
||||||
|
const used = new Set([...nonHigh, ...fixedHighPick].map((f) => f.key))
|
||||||
|
const extraLows = FOOD_LIBRARY.filter((f) => f.gi === 'low' && !used.has(f.key))
|
||||||
|
nonHigh.push(...pickRandom(extraLows, MIN_NON_HIGH_TYPES - nonHigh.length))
|
||||||
|
}
|
||||||
|
|
||||||
const goalFoods = pickRandom(fixed, 2)
|
const active = [...nonHigh, ...fixedHighPick]
|
||||||
|
activeFoods.value = active
|
||||||
|
warmUpFoodImgs(active)
|
||||||
|
|
||||||
|
// 收集目标从非高糖里挑(高糖以“消除即过关”驱动)
|
||||||
|
const goalPool = nonHigh.length ? nonHigh : active
|
||||||
|
const goalFoods = pickRandom(goalPool, Math.min(2, goalPool.length))
|
||||||
const fixedTargets = levelConfig.value.goalTargets || [10, 12]
|
const fixedTargets = levelConfig.value.goalTargets || [10, 12]
|
||||||
goalDefs.value = goalFoods.map((f, i) => ({ key: f.key, food: cloneFoodType(f), target: fixedTargets[i] ?? 10 }))
|
goalDefs.value = goalFoods.map((f, i) => ({ key: f.key, food: cloneFoodType(f), target: fixedTargets[i] ?? 10 }))
|
||||||
|
|
||||||
@@ -659,10 +678,6 @@ const goalList = computed(() =>
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
const allGoalsDone = computed(() =>
|
|
||||||
goalList.value.length > 0 && goalList.value.every((g) => g.done)
|
|
||||||
)
|
|
||||||
|
|
||||||
const glucoseStatusText = computed(() => {
|
const glucoseStatusText = computed(() => {
|
||||||
if (glucoseLevel.value < 30) return '血糖偏低'
|
if (glucoseLevel.value < 30) return '血糖偏低'
|
||||||
if (glucoseLevel.value > 70) return '血糖过高'
|
if (glucoseLevel.value > 70) return '血糖过高'
|
||||||
@@ -744,7 +759,15 @@ function updateGridMetrics() {
|
|||||||
|
|
||||||
function randomFood() {
|
function randomFood() {
|
||||||
const pool = activeFoods.value.length ? activeFoods.value : FOOD_LIBRARY
|
const pool = activeFoods.value.length ? activeFoods.value : FOOD_LIBRARY
|
||||||
const pick = pool[Math.floor(Math.random() * pool.length)]
|
const highFood = sessionHighFood.value
|
||||||
|
// 解锁后高糖才会随补格生成;解锁前一律生成非高糖,由 ensureHighPresence 控制高糖数量
|
||||||
|
const afterUnlock = highFood && playerMoves.value >= HIGH_UNLOCK_MOVES
|
||||||
|
if (afterUnlock && Math.random() < HIGH_SPAWN_P) {
|
||||||
|
return cloneFoodType(highFood)
|
||||||
|
}
|
||||||
|
const nonHigh = pool.filter((f) => f.gi !== 'high')
|
||||||
|
const src = nonHigh.length ? nonHigh : pool
|
||||||
|
const pick = src[Math.floor(Math.random() * src.length)]
|
||||||
return cloneFoodType(pick)
|
return cloneFoodType(pick)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,6 +782,91 @@ function boardHasHighGiFood() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 该位置若变为高糖,是否会与现有高糖形成三连(注入时尽量避免,让玩家自己凑) */
|
||||||
|
function wouldFormHighRun(r, c) {
|
||||||
|
const isHigh = (rr, cc) => {
|
||||||
|
const t = board.value[rr]?.[cc]
|
||||||
|
return t && !t.isRemoved && t.type.gi === 'high'
|
||||||
|
}
|
||||||
|
let h = 1
|
||||||
|
for (let cc = c - 1; cc >= 0 && isHigh(r, cc); cc--) h++
|
||||||
|
for (let cc = c + 1; cc < COLS && isHigh(r, cc); cc++) h++
|
||||||
|
if (h >= 3) return true
|
||||||
|
let v = 1
|
||||||
|
for (let rr = r - 1; rr >= 0 && isHigh(rr, c); rr--) v++
|
||||||
|
for (let rr = r + 1; rr < ROWS && isHigh(rr, c); rr++) v++
|
||||||
|
return v >= 3
|
||||||
|
}
|
||||||
|
|
||||||
|
function shuffleInPlace(arr) {
|
||||||
|
for (let i = arr.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[arr[i], arr[j]] = [arr[j], arr[i]]
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 维持棋盘上高糖(红色)食物的数量,是“约 8 步才能消除红色”的核心:
|
||||||
|
* - 解锁前(playerMoves < HIGH_UNLOCK_MOVES)固定保留 2 个,永远无法三连 → 无法消除;
|
||||||
|
* - 解锁后至少保留 3 个(散开、避免直接成行),玩家凑三连即可消除过关;上限 HIGH_COUNT_MAX。
|
||||||
|
* 高糖只在此注入/回收,randomFood 解锁前不生成高糖。
|
||||||
|
*/
|
||||||
|
function ensureHighPresence() {
|
||||||
|
const highFood = sessionHighFood.value
|
||||||
|
if (!highFood) return
|
||||||
|
const before = playerMoves.value < HIGH_UNLOCK_MOVES
|
||||||
|
const minTarget = before ? HIGH_COUNT_LOCKED : HIGH_COUNT_UNLOCKED
|
||||||
|
const maxCap = before ? HIGH_COUNT_LOCKED : HIGH_COUNT_MAX
|
||||||
|
|
||||||
|
const highTiles = []
|
||||||
|
const nonHighTiles = []
|
||||||
|
for (let r = 0; r < ROWS; r++) {
|
||||||
|
for (let c = 0; c < COLS; c++) {
|
||||||
|
const t = board.value[r]?.[c]
|
||||||
|
if (!t || t.isRemoved) continue
|
||||||
|
if (t.type.gi === 'high') highTiles.push(t)
|
||||||
|
else nonHighTiles.push(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highTiles.length < minTarget) {
|
||||||
|
let need = minTarget - highTiles.length
|
||||||
|
const candidates = shuffleInPlace([...nonHighTiles])
|
||||||
|
// 优先选不会立即成三连的位置
|
||||||
|
for (const t of candidates) {
|
||||||
|
if (need <= 0) break
|
||||||
|
if (t.type.gi === 'high') continue
|
||||||
|
if (wouldFormHighRun(t.r, t.c)) continue
|
||||||
|
t.type = cloneFoodType(highFood)
|
||||||
|
need--
|
||||||
|
}
|
||||||
|
// 仍不够再放宽限制
|
||||||
|
for (const t of candidates) {
|
||||||
|
if (need <= 0) break
|
||||||
|
if (t.type.gi === 'high') continue
|
||||||
|
t.type = cloneFoodType(highFood)
|
||||||
|
need--
|
||||||
|
}
|
||||||
|
bumpLayout()
|
||||||
|
} else if (highTiles.length > maxCap) {
|
||||||
|
const lowMidPool = activeFoods.value.filter((f) => f.gi !== 'high')
|
||||||
|
let remove = highTiles.length - maxCap
|
||||||
|
const shuffled = shuffleInPlace([...highTiles])
|
||||||
|
for (const t of shuffled) {
|
||||||
|
if (remove <= 0) break
|
||||||
|
const repl = lowMidPool.length
|
||||||
|
? lowMidPool[Math.floor(Math.random() * lowMidPool.length)]
|
||||||
|
: null
|
||||||
|
if (repl) {
|
||||||
|
t.type = cloneFoodType(repl)
|
||||||
|
remove--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bumpLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function wouldCreateInitialMatch(r, c, type, currentBoard, currentRow) {
|
function wouldCreateInitialMatch(r, c, type, currentBoard, currentRow) {
|
||||||
const key = type.key
|
const key = type.key
|
||||||
if (r >= 2 && currentBoard[r - 1][c]?.type.key === key && currentBoard[r - 2][c]?.type.key === key) {
|
if (r >= 2 && currentBoard[r - 1][c]?.type.key === key && currentBoard[r - 2][c]?.type.key === key) {
|
||||||
@@ -813,6 +921,8 @@ function initBoard() {
|
|||||||
}
|
}
|
||||||
ensureBoardFull(next)
|
ensureBoardFull(next)
|
||||||
commitBoard(next)
|
commitBoard(next)
|
||||||
|
// 注入本关唯一高糖(解锁前固定 2 个,无法三连)
|
||||||
|
ensureHighPresence()
|
||||||
startHintTimer()
|
startHintTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,6 +984,7 @@ function setupLevel(levelId) {
|
|||||||
highClearAlertVisible.value = false
|
highClearAlertVisible.value = false
|
||||||
clearedHighFoodName.value = ''
|
clearedHighFoodName.value = ''
|
||||||
lastClearedFood.value = null
|
lastClearedFood.value = null
|
||||||
|
playerMoves.value = 0
|
||||||
tileTouchStart = null
|
tileTouchStart = null
|
||||||
clearDragPreview()
|
clearDragPreview()
|
||||||
selectSessionFoods()
|
selectSessionFoods()
|
||||||
@@ -1467,6 +1578,7 @@ function recordLastClearedFood(groups) {
|
|||||||
gi,
|
gi,
|
||||||
giShort: GI_SHORT[gi] || '低糖',
|
giShort: GI_SHORT[gi] || '低糖',
|
||||||
eatHint: formatEatLabel(t),
|
eatHint: formatEatLabel(t),
|
||||||
|
tip: getFoodTip(t),
|
||||||
color: GI_COLOR[gi] || '#64748b',
|
color: GI_COLOR[gi] || '#64748b',
|
||||||
food: cloneFoodType(t)
|
food: cloneFoodType(t)
|
||||||
}
|
}
|
||||||
@@ -1513,11 +1625,7 @@ function showLearnFx(groups) {
|
|||||||
|
|
||||||
function checkGameEnd() {
|
function checkGameEnd() {
|
||||||
if (gamePhase.value !== 'playing') return
|
if (gamePhase.value !== 'playing') return
|
||||||
// 无失败惩罚:认全目标或已消除场上全部高糖食物即通关
|
// 唯一通关条件:消除本关唯一的高糖(红色)食物
|
||||||
if (allGoalsDone.value) {
|
|
||||||
endGame('won', { reason: 'goals' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (sessionHighFood.value && !boardHasHighGiFood()) {
|
if (sessionHighFood.value && !boardHasHighGiFood()) {
|
||||||
endGame('won', {
|
endGame('won', {
|
||||||
reason: 'high_cleared',
|
reason: 'high_cleared',
|
||||||
@@ -1640,11 +1748,14 @@ async function processSwap(t1, t2, opts = {}) {
|
|||||||
const matches = findMatches()
|
const matches = findMatches()
|
||||||
if (matches.length > 0) {
|
if (matches.length > 0) {
|
||||||
movesLeft.value = Math.max(0, movesLeft.value - 1)
|
movesLeft.value = Math.max(0, movesLeft.value - 1)
|
||||||
|
playerMoves.value += 1
|
||||||
const endedByHigh = await clearAndRefill()
|
const endedByHigh = await clearAndRefill()
|
||||||
if (endedByHigh) {
|
if (endedByHigh) {
|
||||||
isProcessing.value = false
|
isProcessing.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 按解锁进度维持高糖数量(到第 7 步起补到可消除的 3 个)
|
||||||
|
ensureHighPresence()
|
||||||
// 所有连消结束后,检查棋盘是否死锁并自动重排
|
// 所有连消结束后,检查棋盘是否死锁并自动重排
|
||||||
await reshuffleIfStuck()
|
await reshuffleIfStuck()
|
||||||
} else {
|
} else {
|
||||||
@@ -1887,6 +1998,8 @@ async function onBooster(booster) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 恢复本关高糖数量,避免纤维清空高糖直接跳过“8 步”门槛
|
||||||
|
ensureHighPresence()
|
||||||
// fiber 改变了棋盘,保险检查是否死锁
|
// fiber 改变了棋盘,保险检查是否死锁
|
||||||
await reshuffleIfStuck()
|
await reshuffleIfStuck()
|
||||||
|
|
||||||
@@ -2003,6 +2116,8 @@ async function onBooster(booster) {
|
|||||||
await delay(GRAVITY_MS)
|
await delay(GRAVITY_MS)
|
||||||
clearDropFlags()
|
clearDropFlags()
|
||||||
|
|
||||||
|
// 维持本关高糖数量
|
||||||
|
ensureHighPresence()
|
||||||
// meal 自带洗牌已保证有解,但再做一次轻量检查保险
|
// meal 自带洗牌已保证有解,但再做一次轻量检查保险
|
||||||
await reshuffleIfStuck()
|
await reshuffleIfStuck()
|
||||||
|
|
||||||
@@ -2051,7 +2166,7 @@ function initLayout() {
|
|||||||
paddingTop: `${paddingTop}px`,
|
paddingTop: `${paddingTop}px`,
|
||||||
paddingLeft: '32rpx',
|
paddingLeft: '32rpx',
|
||||||
paddingRight: '32rpx',
|
paddingRight: '32rpx',
|
||||||
paddingBottom: '10rpx'
|
paddingBottom: '18rpx'
|
||||||
}
|
}
|
||||||
navStyle.value = {
|
navStyle.value = {
|
||||||
paddingRight: `${Math.max(0, headerPaddingRight - uni.upx2px(32))}px`
|
paddingRight: `${Math.max(0, headerPaddingRight - uni.upx2px(32))}px`
|
||||||
@@ -2071,19 +2186,25 @@ function recalcBoardSize() {
|
|||||||
const query = uni.createSelectorQuery().in(instance?.proxy)
|
const query = uni.createSelectorQuery().in(instance?.proxy)
|
||||||
query.select('.gg-header').boundingClientRect()
|
query.select('.gg-header').boundingClientRect()
|
||||||
query.select('.gg-footer').boundingClientRect()
|
query.select('.gg-footer').boundingClientRect()
|
||||||
|
query.select('.gg-board-hero').boundingClientRect()
|
||||||
query.exec((res) => {
|
query.exec((res) => {
|
||||||
try {
|
try {
|
||||||
const sys = uni.getSystemInfoSync()
|
const sys = uni.getSystemInfoSync()
|
||||||
const header = res?.[0]
|
const header = res?.[0]
|
||||||
const footer = res?.[1]
|
const footer = res?.[1]
|
||||||
|
const hero = res?.[2]
|
||||||
const headerBottom = Math.ceil(header?.bottom ?? header?.height ?? uni.upx2px(360))
|
const headerBottom = Math.ceil(header?.bottom ?? header?.height ?? uni.upx2px(360))
|
||||||
|
// 棋盘真正可用区从进度条/信息横幅之下(board-hero 顶部)算起
|
||||||
|
const boardAreaTop = Math.ceil(hero?.top ?? headerBottom)
|
||||||
// 底部道具栏较高,测量失败时用更保守的兜底高度,避免最后一行被遮挡
|
// 底部道具栏较高,测量失败时用更保守的兜底高度,避免最后一行被遮挡
|
||||||
const footerTop = Math.floor(footer?.top ?? (sys.windowHeight - uni.upx2px(300)))
|
const footerTop = Math.floor(footer?.top ?? (sys.windowHeight - uni.upx2px(300)))
|
||||||
const inset = uni.upx2px(BOARD_INSET_RPX)
|
const inset = uni.upx2px(BOARD_INSET_RPX)
|
||||||
const footerGap = uni.upx2px(BOARD_FOOTER_GAP_RPX)
|
const footerGap = uni.upx2px(BOARD_FOOTER_GAP_RPX)
|
||||||
const zoneW = sys.windowWidth
|
// gg-main 左右内边距各 20rpx,棋盘可用宽度需相应收窄
|
||||||
|
const sidePad = uni.upx2px(20)
|
||||||
|
const zoneW = sys.windowWidth - sidePad * 2
|
||||||
// 预留底部安全间隙,棋盘不贴到道具栏
|
// 预留底部安全间隙,棋盘不贴到道具栏
|
||||||
const zoneH = Math.max(0, footerTop - headerBottom - footerGap)
|
const zoneH = Math.max(0, footerTop - boardAreaTop - footerGap)
|
||||||
|
|
||||||
// 5 行 × 4 列:宽高分别约束,取较小单格像素
|
// 5 行 × 4 列:宽高分别约束,取较小单格像素
|
||||||
cellSizePx.value = calcMaxCellSize(zoneW - inset * 2, zoneH - inset * 2)
|
cellSizePx.value = calcMaxCellSize(zoneW - inset * 2, zoneH - inset * 2)
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
.game-page {
|
.game-page {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
background: #f4fbf4; /* VitalMint background */
|
/* 参考稿:顶部高光的薄荷渐变背景 */
|
||||||
color: #161d19; /* VitalMint text color */
|
background: #e9f0e9;
|
||||||
|
background-image: radial-gradient(circle at 50% -20%, #ffffff 0%, #e9f0e9 60%, #d5dcd5 100%);
|
||||||
|
color: #171d19;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -24,68 +26,72 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-glass {
|
.game-page .gg-glass {
|
||||||
background: rgba(255, 255, 255, 0.75);
|
background: rgba(255, 255, 255, 0.6);
|
||||||
backdrop-filter: blur(16px);
|
backdrop-filter: blur(20px);
|
||||||
-webkit-backdrop-filter: blur(16px);
|
-webkit-backdrop-filter: blur(20px);
|
||||||
border: 1.5rpx solid rgba(255, 255, 255, 0.6);
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== Header HUD ===== */
|
/* ===== Header / TopAppBar(参考稿玻璃顶栏) ===== */
|
||||||
.game-page .gg-header {
|
.game-page .gg-header {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 50;
|
z-index: 50;
|
||||||
border-radius: 0 0 24rpx 24rpx;
|
background: rgba(255, 255, 255, 0.4);
|
||||||
box-shadow: 0 4rpx 20rpx rgba(0, 108, 73, 0.04);
|
backdrop-filter: blur(24px);
|
||||||
background: rgba(255, 255, 255, 0.88);
|
-webkit-backdrop-filter: blur(24px);
|
||||||
backdrop-filter: blur(16px);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
-webkit-backdrop-filter: blur(16px);
|
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.02);
|
||||||
border-bottom: 1rpx solid rgba(0, 108, 73, 0.06);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-nav {
|
.game-page .gg-hud-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: var(--menu-height, 64rpx);
|
min-height: var(--menu-height, 64rpx);
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-control-group {
|
.game-page .gg-hud-control-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10rpx;
|
gap: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 玻璃圆形图标按钮 */
|
||||||
.game-page .gg-hud-btn {
|
.game-page .gg-hud-btn {
|
||||||
width: var(--menu-height, 64rpx);
|
width: 84rpx;
|
||||||
height: var(--menu-height, 64rpx);
|
height: 84rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: rgba(255, 255, 255, 0.85);
|
background: rgba(255, 255, 255, 0.7);
|
||||||
border: 1rpx solid rgba(0, 108, 73, 0.08);
|
border: 1px solid rgba(255, 255, 255, 0.9);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
box-shadow: 0 4rpx 12rpx rgba(0, 108, 73, 0.03);
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.04), inset 0 1px 2px rgba(255, 255, 255, 0.8);
|
||||||
transition: all 0.2s ease;
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
transition: all 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-btn--pressed {
|
.game-page .gg-hud-btn--pressed {
|
||||||
opacity: 0.75;
|
|
||||||
transform: scale(0.94);
|
transform: scale(0.94);
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-btn.is-muted {
|
.game-page .gg-hud-btn.is-muted {
|
||||||
opacity: 0.45;
|
opacity: 0.55;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-level-center {
|
.game-page .gg-hud-level-center {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -93,25 +99,29 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-level-text {
|
.game-page .gg-hud-level-text {
|
||||||
font-size: 30rpx;
|
font-size: 44rpx;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
color: #475569;
|
color: #006c4b;
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
letter-spacing: 1rpx;
|
letter-spacing: 2rpx;
|
||||||
|
text-shadow: 0 2rpx 6rpx rgba(0, 108, 75, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-score {
|
.game-page .gg-hud-score {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
gap: 4rpx;
|
gap: 6rpx;
|
||||||
|
margin-top: 2rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-score-val {
|
.game-page .gg-hud-score-val {
|
||||||
font-size: 44rpx;
|
font-size: 68rpx;
|
||||||
font-weight: 900;
|
font-weight: 800;
|
||||||
color: #006c49;
|
color: #006c4b;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
line-height: 1.2;
|
line-height: 1;
|
||||||
|
letter-spacing: -2rpx;
|
||||||
|
text-shadow: 0 2rpx 6rpx rgba(0, 108, 75, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-score.is-pop .gg-hud-score-val {
|
.game-page .gg-hud-score.is-pop .gg-hud-score-val {
|
||||||
@@ -119,9 +129,136 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-hud-score-unit {
|
.game-page .gg-hud-score-unit {
|
||||||
font-size: 26rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #64748b;
|
color: #3d4a42;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 信息横幅(参考稿玻璃卡 + 绿色 info 图标) ===== */
|
||||||
|
.game-page .gg-info-banner {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 750rpx;
|
||||||
|
margin: 0 auto 20rpx;
|
||||||
|
padding: 20rpx 24rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20rpx;
|
||||||
|
border-radius: 28rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.6);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
-webkit-backdrop-filter: blur(20px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
|
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.06), inset 0 1px 2px rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-banner-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 22rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(135deg, #00a676, #006c4b);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0 8rpx 18rpx rgba(0, 108, 75, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-banner-body {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-banner-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #171d19;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-banner-kw {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #006c4b;
|
||||||
|
letter-spacing: 1rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* —— 消除后:该食物的含糖 + 建议 —— */
|
||||||
|
.game-page .gg-info-banner.is-food {
|
||||||
|
gap: 18rpx;
|
||||||
|
animation: gg-info-food-in 0.28s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
.game-page .gg-info-banner.is-food.is-low { border-color: rgba(22, 163, 74, 0.28); }
|
||||||
|
.game-page .gg-info-banner.is-food.is-mid { border-color: rgba(234, 88, 12, 0.28); }
|
||||||
|
.game-page .gg-info-banner.is-food.is-high { border-color: rgba(220, 38, 38, 0.3); }
|
||||||
|
|
||||||
|
/* 食物图标:白底 + GI 彩色描边(覆盖默认绿色渐变) */
|
||||||
|
.game-page .gg-info-banner-icon.is-food {
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(15, 23, 42, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.9);
|
||||||
|
border-width: 2rpx;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
.game-page .gg-info-banner-icon.is-food.is-low { border-color: rgba(22, 163, 74, 0.4); }
|
||||||
|
.game-page .gg-info-banner-icon.is-food.is-mid { border-color: rgba(234, 88, 12, 0.4); }
|
||||||
|
.game-page .gg-info-banner-icon.is-food.is-high { border-color: rgba(220, 38, 38, 0.45); }
|
||||||
|
|
||||||
|
.game-page .gg-info-banner-icon.is-food .food-tile-icon--goal {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-food-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14rpx;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-food-name {
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
color: #171d19;
|
||||||
|
line-height: 1.2;
|
||||||
|
max-width: 320rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-info-food-gi {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4rpx 16rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
}
|
||||||
|
.game-page .gg-info-food-gi-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #ffffff;
|
||||||
|
letter-spacing: 1rpx;
|
||||||
|
}
|
||||||
|
.game-page .gg-info-food-gi.is-low { background: linear-gradient(135deg, #5bdda8, #00a676); box-shadow: 0 2rpx 8rpx rgba(0, 166, 118, 0.32); }
|
||||||
|
.game-page .gg-info-food-gi.is-mid { background: linear-gradient(135deg, #fbbf24, #d97706); box-shadow: 0 2rpx 8rpx rgba(217, 119, 6, 0.32); }
|
||||||
|
.game-page .gg-info-food-gi.is-high { background: linear-gradient(135deg, #f87171, #ba1a1a); box-shadow: 0 2rpx 8rpx rgba(186, 26, 26, 0.34); }
|
||||||
|
|
||||||
|
.game-page .gg-info-food-tip {
|
||||||
|
display: block;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #3d4a42;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.game-page .gg-info-food-tip.is-low { color: #15803d; }
|
||||||
|
.game-page .gg-info-food-tip.is-mid { color: #c2410c; }
|
||||||
|
.game-page .gg-info-food-tip.is-high { color: #b91c1c; }
|
||||||
|
|
||||||
|
@keyframes gg-info-food-in {
|
||||||
|
from { opacity: 0.35; transform: translateY(-6rpx); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 次:上次消除(名称 + 含糖量),GI 三色编码学习卡 ===== */
|
/* ===== 次:上次消除(名称 + 含糖量),GI 三色编码学习卡 ===== */
|
||||||
@@ -545,8 +682,8 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
padding: 8rpx 1rpx 0;
|
padding: 14rpx 20rpx 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gg-hint-banner 已移除,提示直接显示在棋盘食物上 */
|
/* gg-hint-banner 已移除,提示直接显示在棋盘食物上 */
|
||||||
@@ -580,17 +717,16 @@
|
|||||||
.game-page .game-grid {
|
.game-page .game-grid {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-radius: 36rpx;
|
border-radius: 48rpx;
|
||||||
background: rgba(255, 255, 255, 0.92);
|
background: rgba(255, 255, 255, 0.6);
|
||||||
backdrop-filter: blur(24px);
|
backdrop-filter: blur(20px);
|
||||||
-webkit-backdrop-filter: blur(24px);
|
-webkit-backdrop-filter: blur(20px);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 20rpx 56rpx rgba(0, 108, 73, 0.14),
|
0 12rpx 32rpx rgba(0, 0, 0, 0.06),
|
||||||
0 4rpx 16rpx rgba(15, 23, 42, 0.06),
|
inset 0 1px 2px rgba(255, 255, 255, 0.9);
|
||||||
inset 0 2rpx 12rpx rgba(255, 255, 255, 0.85);
|
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
border: 2rpx solid rgba(0, 108, 73, 0.12);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,14 +750,17 @@
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 0;
|
border-radius: 28rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
justify-content: stretch;
|
justify-content: stretch;
|
||||||
background: transparent;
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(244, 251, 245, 0.6));
|
||||||
box-shadow: none;
|
box-shadow:
|
||||||
border: none;
|
0 10rpx 20rpx rgba(0, 108, 75, 0.08),
|
||||||
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s;
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 0 -2rpx 6rpx rgba(0, 0, 0, 0.02);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.9);
|
||||||
|
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease, opacity 0.2s;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
@@ -654,13 +793,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.game-page .game-tile.is-selected {
|
.game-page .game-tile.is-selected {
|
||||||
transform: scale(1.12);
|
transform: scale(1.08);
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
border: none;
|
border: 2px solid #00a676;
|
||||||
box-shadow: none;
|
border-radius: 28rpx;
|
||||||
outline: 4rpx solid #006c49;
|
box-shadow:
|
||||||
outline-offset: -2rpx;
|
0 0 20rpx rgba(0, 166, 118, 0.35),
|
||||||
border-radius: 8rpx;
|
inset 0 0 10rpx rgba(0, 166, 118, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .game-tile--pressed {
|
.game-page .game-tile--pressed {
|
||||||
@@ -863,31 +1002,39 @@
|
|||||||
/* ===== 棋子含糖等级常驻角标(认知核心:一眼看出高/中/低糖) ===== */
|
/* ===== 棋子含糖等级常驻角标(认知核心:一眼看出高/中/低糖) ===== */
|
||||||
.game-page .gg-tile-gi {
|
.game-page .gg-tile-gi {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2rpx;
|
top: -12rpx;
|
||||||
left: 2rpx;
|
left: 50%;
|
||||||
z-index: 3;
|
transform: translateX(-50%);
|
||||||
min-width: 30rpx;
|
z-index: 5;
|
||||||
height: 30rpx;
|
min-width: 40rpx;
|
||||||
padding: 0 6rpx;
|
padding: 6rpx 16rpx;
|
||||||
border-radius: 999rpx;
|
border-radius: 999rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
font-weight: 900;
|
font-weight: 800;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
letter-spacing: 1rpx;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.25);
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
border: 2rpx solid rgba(255, 255, 255, 0.9);
|
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.2);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-tile-gi.is-low { background: #16a34a; }
|
.game-page .gg-tile-gi.is-low {
|
||||||
.game-page .gg-tile-gi.is-mid { background: #e67e22; }
|
background: linear-gradient(135deg, rgba(91, 221, 168, 0.95), rgba(0, 166, 118, 0.95));
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 166, 118, 0.4), inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
.game-page .gg-tile-gi.is-mid {
|
||||||
|
background: linear-gradient(135deg, rgba(251, 191, 36, 0.95), rgba(217, 119, 6, 0.95));
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(217, 119, 6, 0.4), inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
.game-page .gg-tile-gi.is-high {
|
.game-page .gg-tile-gi.is-high {
|
||||||
background: #dc2626;
|
background: linear-gradient(135deg, rgba(248, 113, 113, 0.95), rgba(186, 26, 26, 0.95));
|
||||||
box-shadow: 0 2rpx 10rpx rgba(220, 38, 38, 0.45);
|
box-shadow: 0 4rpx 12rpx rgba(186, 26, 26, 0.4), inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
|
||||||
font-size: 22rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 点击食物的大字科普卡 ===== */
|
/* ===== 点击食物的大字科普卡 ===== */
|
||||||
@@ -980,97 +1127,96 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
border-radius: 48rpx 48rpx 0 0;
|
border-radius: 64rpx 64rpx 0 0;
|
||||||
border-top: 1rpx solid rgba(0, 108, 73, 0.06);
|
border-top: 1px solid #ffffff;
|
||||||
box-shadow: 0 -4rpx 24rpx rgba(0, 108, 73, 0.04);
|
box-shadow: 0 -12rpx 40rpx rgba(0, 0, 0, 0.08);
|
||||||
padding-top: 12rpx;
|
padding-top: 24rpx;
|
||||||
padding-left: 24rpx;
|
padding-left: 24rpx;
|
||||||
padding-right: 24rpx;
|
padding-right: 24rpx;
|
||||||
background: rgba(255, 255, 255, 0.78);
|
background: rgba(255, 255, 255, 0.7);
|
||||||
}
|
backdrop-filter: blur(28px);
|
||||||
|
-webkit-backdrop-filter: blur(28px);
|
||||||
.game-page .gg-footer--sub .gg-booster-btn {
|
|
||||||
padding: 16rpx 0;
|
|
||||||
width: 152rpx;
|
|
||||||
border-radius: 32rpx;
|
|
||||||
background: rgba(255, 255, 255, 0.75);
|
|
||||||
border-color: rgba(0, 108, 73, 0.08);
|
|
||||||
box-shadow: 0 4rpx 12rpx rgba(0, 108, 73, 0.04);
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-page .gg-footer--sub .gg-booster-label {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #64748b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-boosters {
|
.game-page .gg-boosters {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
max-width: 750rpx;
|
max-width: 750rpx;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 单个道具:图标卡 + 角标 + 文字 */
|
||||||
.game-page .gg-booster-btn {
|
.game-page .gg-booster-btn {
|
||||||
position: relative;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 22rpx 0;
|
padding: 8rpx 0;
|
||||||
width: 176rpx;
|
width: 184rpx;
|
||||||
background: rgba(255, 255, 255, 0.85);
|
background: transparent;
|
||||||
border: 1.5rpx solid rgba(0, 108, 73, 0.12);
|
border: none;
|
||||||
border-radius: 40rpx;
|
transition: transform 0.2s ease;
|
||||||
box-shadow: 0 8rpx 20rpx rgba(0, 108, 73, 0.03), inset 0 2rpx 4rpx rgba(255, 255, 255, 0.8);
|
|
||||||
transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-booster-btn--pressed {
|
.game-page .gg-booster-tile {
|
||||||
|
position: relative;
|
||||||
|
width: 112rpx;
|
||||||
|
height: 112rpx;
|
||||||
|
border-radius: 36rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(255, 255, 255, 0.85);
|
||||||
|
border: 1px solid #ffffff;
|
||||||
|
box-shadow: 0 8rpx 18rpx rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.9);
|
||||||
|
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.game-page .gg-booster-btn--pressed .gg-booster-tile {
|
||||||
transform: scale(0.92);
|
transform: scale(0.92);
|
||||||
background: rgba(255, 255, 255, 0.65);
|
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-booster-btn.is-disabled {
|
.game-page .gg-booster-btn.is-disabled {
|
||||||
opacity: 0.35;
|
opacity: 0.4;
|
||||||
filter: grayscale(100%);
|
filter: grayscale(100%);
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-booster-count {
|
.game-page .gg-booster-count {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10rpx;
|
top: -12rpx;
|
||||||
right: -10rpx;
|
right: -12rpx;
|
||||||
width: 52rpx;
|
min-width: 50rpx;
|
||||||
height: 52rpx;
|
height: 50rpx;
|
||||||
border-radius: 50%;
|
padding: 0 10rpx;
|
||||||
|
border-radius: 26rpx;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 30rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 900;
|
font-weight: 800;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 4rpx solid #fff;
|
border: 3rpx solid #ffffff;
|
||||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.12);
|
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.18);
|
||||||
|
text-shadow: 0 1rpx 1rpx rgba(0, 0, 0, 0.2);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-booster-count.is-green { background: #10b981; }
|
.game-page .gg-booster-count.is-green { background: linear-gradient(135deg, #00a676, #006c4b); box-shadow: 0 4rpx 10rpx rgba(0, 166, 118, 0.3); }
|
||||||
.game-page .gg-booster-count.is-orange { background: #f97316; }
|
.game-page .gg-booster-count.is-orange { background: linear-gradient(135deg, #f59e0b, #d97706); box-shadow: 0 4rpx 10rpx rgba(217, 119, 6, 0.3); }
|
||||||
.game-page .gg-booster-count.is-rose { background: #f43f5e; }
|
.game-page .gg-booster-count.is-rose { background: linear-gradient(135deg, #ef4444, #ba1a1a); box-shadow: 0 4rpx 10rpx rgba(186, 26, 26, 0.3); }
|
||||||
|
|
||||||
.game-page .gg-booster-icon {
|
.game-page .gg-booster-icon {
|
||||||
margin-bottom: 8rpx;
|
transition: transform 0.2s ease;
|
||||||
transition: transform 0.25s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-page .gg-booster-btn--pressed .gg-booster-icon {
|
|
||||||
transform: scale(0.85);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-page .gg-booster-label {
|
.game-page .gg-booster-label {
|
||||||
|
margin-top: 14rpx;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: #2b3a32;
|
color: #3d4a42;
|
||||||
|
letter-spacing: 1rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 高糖消除红色警示弹窗 ===== */
|
/* ===== 高糖消除红色警示弹窗 ===== */
|
||||||
|
|||||||
Reference in New Issue
Block a user