更新
This commit is contained in:
@@ -67,11 +67,31 @@
|
||||
<text class="gg-food-card-tip">{{ foodCard.tip }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 消除高糖:红色警示弹窗(短暂强调后进入结算) -->
|
||||
<view v-if="highClearAlertVisible" class="gg-high-alert-overlay" @tap.stop>
|
||||
<view class="gg-high-alert-card">
|
||||
<view class="gg-high-alert-icon-wrap" aria-hidden="true">
|
||||
<TongjiIcon name="alert-triangle" size="lg" color="#ffffff" />
|
||||
</view>
|
||||
<view class="gg-high-alert-badge-row">
|
||||
<text class="gg-high-alert-badge">高糖</text>
|
||||
<text class="gg-high-alert-badge-sub">红色标识 · 升糖快</text>
|
||||
</view>
|
||||
<text class="gg-high-alert-title">已消除高糖食物</text>
|
||||
<text class="gg-high-alert-name">{{ clearedHighFoodName }}</text>
|
||||
<text class="gg-high-alert-tip">请记住:这类食物要少吃</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学习结果 -->
|
||||
<view v-if="gamePhase !== 'playing'" class="gg-result-overlay" @tap.stop>
|
||||
<view class="gg-result-card">
|
||||
<text class="gg-result-title">{{ gamePhase === 'won' ? '学会啦!' : '再认一认' }}</text>
|
||||
<view v-if="gamePhase === 'won'" class="gg-result-stars">
|
||||
<view class="gg-result-card" :class="{ 'is-high-clear': winReason === 'high_cleared' }">
|
||||
<view v-if="winReason === 'high_cleared'" class="gg-result-high-head">
|
||||
<text class="gg-result-high-badge">高糖</text>
|
||||
<text class="gg-result-high-tag">已消除</text>
|
||||
</view>
|
||||
<text class="gg-result-title">{{ resultTitle }}</text>
|
||||
<view v-if="gamePhase === 'won' && winReason !== 'high_cleared'" class="gg-result-stars">
|
||||
<text
|
||||
v-for="i in 3"
|
||||
:key="'star-' + i"
|
||||
@@ -80,16 +100,20 @@
|
||||
>★</text>
|
||||
</view>
|
||||
<text class="gg-result-sub">{{ resultMessage }}</text>
|
||||
<view v-if="resultStats.length" class="gg-result-stats">
|
||||
<view v-if="resultStats.length" class="gg-result-stats" :class="{ 'is-high-clear': winReason === 'high_cleared' }">
|
||||
<view v-for="(row, idx) in resultStats" :key="'rs-' + idx" class="gg-result-stat">
|
||||
<text class="gg-result-stat-label">{{ row.label }}</text>
|
||||
<text class="gg-result-stat-val">{{ row.value }}</text>
|
||||
<text class="gg-result-stat-val" :class="{ 'is-high-val': winReason === 'high_cleared' && idx === 0 }">
|
||||
<text v-if="winReason === 'high_cleared' && idx === 0" class="gg-result-inline-badge">高糖</text>
|
||||
{{ row.value }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="gg-result-actions">
|
||||
<view
|
||||
v-if="gamePhase === 'won'"
|
||||
class="gg-result-btn is-primary"
|
||||
:class="{ 'is-high-primary': winReason === 'high_cleared' }"
|
||||
@tap="goNextLevel"
|
||||
>认下一组</view>
|
||||
<view class="gg-result-btn" :class="{ 'is-primary': gamePhase !== 'won' }" @tap="restartLevel">
|
||||
@@ -128,104 +152,49 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心数据面板:三栏网格布局 -->
|
||||
<view class="gg-hud-dashboard">
|
||||
<!-- 左侧:血糖监控指示器 -->
|
||||
<view class="gg-dash-glucose">
|
||||
<view class="gg-glucose-ring" :class="meterFillClass" :style="glucoseRingStyle">
|
||||
<view class="gg-glucose-ring-inner">
|
||||
<TongjiIcon name="glucose" size="sm" :color="glucoseAccentColor" />
|
||||
<text class="gg-glucose-value">{{ glucoseLevel }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="gg-glucose-detail">
|
||||
<view class="gg-glucose-detail-head">
|
||||
<text class="gg-glucose-title">血糖</text>
|
||||
<text class="gg-glucose-status" :class="statusLabelClass">{{ glucoseShortStatus }}</text>
|
||||
</view>
|
||||
<view class="gg-meter-bar">
|
||||
<view class="gg-meter-track">
|
||||
<view class="gg-meter-zone is-low" />
|
||||
<view class="gg-meter-zone is-ok" />
|
||||
<view class="gg-meter-zone is-high" />
|
||||
</view>
|
||||
<view class="gg-meter-fill" :class="meterFillClass" :style="{ width: glucoseLevel + '%' }" />
|
||||
<view class="gg-meter-pointer" :class="meterFillClass" :style="{ left: glucoseLevel + '%' }" />
|
||||
</view>
|
||||
<view class="gg-meter-legend">
|
||||
<text class="is-low-text">偏低</text>
|
||||
<text class="is-ok-text">稳定</text>
|
||||
<text class="is-high-text">偏高</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 垂直分割线 1 -->
|
||||
<view class="gg-dash-divider" />
|
||||
|
||||
<!-- 中间:步数看板(仅展示,无失败惩罚) -->
|
||||
<view class="gg-dash-moves">
|
||||
<text class="gg-moves-label">步数</text>
|
||||
<text class="gg-moves-val">{{ movesLeft }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 垂直分割线 2 -->
|
||||
<view class="gg-dash-divider" />
|
||||
|
||||
<!-- 右侧:关卡任务目标 -->
|
||||
<view class="gg-dash-mission">
|
||||
<view class="gg-mission-head">
|
||||
<view class="gg-mission-title-wrap">
|
||||
<text class="gg-mission-title">认识这些食物</text>
|
||||
<text class="gg-mission-pct">{{ goalProgressPct }}%</text>
|
||||
</view>
|
||||
<view v-if="dailyStreak >= 2" class="gg-mission-streak">
|
||||
<TongjiIcon name="flame" size="sm" color="#059669" />
|
||||
<text>{{ dailyStreak }} 天</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="gg-mission-goals">
|
||||
<view
|
||||
v-for="g in goalList"
|
||||
:key="g.key"
|
||||
class="gg-goal-chip"
|
||||
:class="{ 'is-done': g.done }"
|
||||
>
|
||||
<view class="gg-goal-icon-wrap">
|
||||
<FoodTileIcon :food="g.food" size="goal" />
|
||||
</view>
|
||||
<view class="gg-goal-chip-body">
|
||||
<view class="gg-goal-chip-bar">
|
||||
<view
|
||||
class="gg-goal-chip-fill"
|
||||
:style="{ width: Math.min(100, Math.round((g.current / g.target) * 100)) + '%' }"
|
||||
/>
|
||||
</view>
|
||||
<text class="gg-goal-chip-text">{{ g.current }}/{{ g.target }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部棋盘说明(认知导向,无倒计时) -->
|
||||
<view v-if="gamePhase === 'playing'" class="gg-board-hint-bar">
|
||||
<view class="gg-board-hint-left">
|
||||
<view class="gg-hint-tag">认糖</view>
|
||||
<text class="gg-board-hint-text">点一下食物,看它含糖高不高</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 棋盘 -->
|
||||
<!-- 主区:棋盘为主,辅助信息弱化 -->
|
||||
<view class="gg-main" :style="mainStyle">
|
||||
<view class="gg-board-stack" :style="boardStackStyle">
|
||||
|
||||
<!-- 次:仅展示上次消除的食物与含糖量 -->
|
||||
<view v-if="gamePhase === 'playing'" class="gg-hud-last-food">
|
||||
<text class="gg-hud-last-food-kicker">上次消除</text>
|
||||
<view
|
||||
v-if="lastClearedFood"
|
||||
class="gg-hud-last-food-card"
|
||||
:class="'is-' + lastClearedFood.gi"
|
||||
>
|
||||
<view class="gg-hud-last-food-icon">
|
||||
<FoodTileIcon :food="lastClearedFood.food" size="goal" />
|
||||
</view>
|
||||
<view class="gg-hud-last-food-body">
|
||||
<text class="gg-hud-last-food-name">{{ lastClearedFood.name }}</text>
|
||||
<view class="gg-hud-last-food-sugar-row">
|
||||
<text class="gg-hud-last-food-sugar-label">含糖量</text>
|
||||
<text
|
||||
class="gg-hud-last-food-gi"
|
||||
:class="'is-' + lastClearedFood.gi"
|
||||
:style="{ backgroundColor: lastClearedFood.color }"
|
||||
>{{ lastClearedFood.giShort }}</text>
|
||||
<text class="gg-hud-last-food-sugar-hint">{{ lastClearedFood.eatHint }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="gg-hud-last-food-placeholder">
|
||||
<text>三连消除后,这里显示食物名称与含糖量</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主:棋盘 -->
|
||||
<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-zone">
|
||||
<view v-if="hintTipVisible" class="gg-no-move-tip">
|
||||
<TongjiIcon name="alert-circle" size="sm" color="#ea580c" />
|
||||
<TongjiIcon name="alert-triangle" size="sm" color="#ea580c" />
|
||||
<text class="gg-no-move-tip-text">{{ hintTipText }}</text>
|
||||
</view>
|
||||
<view class="gg-board-wrap" :style="boardWrapStyle">
|
||||
@@ -284,11 +253,12 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部道具 -->
|
||||
<view class="gg-footer gg-glass" :style="footerStyle">
|
||||
<!-- 辅:道具栏(弱化) -->
|
||||
<view class="gg-footer gg-glass gg-footer--sub" :style="footerStyle">
|
||||
<view class="gg-boosters">
|
||||
<view
|
||||
v-for="booster in boosters"
|
||||
@@ -314,7 +284,15 @@ import { computed, getCurrentInstance, nextTick, onMounted, onUnmounted, ref } f
|
||||
import { onLoad, onReady } from '@dcloudio/uni-app'
|
||||
import TongjiIcon from '../components/TongjiIcon.vue'
|
||||
import FoodTileIcon from '../components/FoodTileIcon.vue'
|
||||
import { FOOD_LIBRARY, cloneFoodType, getClearVal, getFoodTip, GI_SHORT, GI_COLOR } from '../data/gameFoodLibrary.js'
|
||||
import {
|
||||
FOOD_LIBRARY,
|
||||
cloneFoodType,
|
||||
getClearVal,
|
||||
getFoodTip,
|
||||
formatEatLabel,
|
||||
GI_SHORT,
|
||||
GI_COLOR
|
||||
} from '../data/gameFoodLibrary.js'
|
||||
import { warmUpFoodImgs } from '../data/gameFoodImg.js'
|
||||
import { useGameSfx } from '../composables/useGameSfx.js'
|
||||
import { useGameFx } from '../composables/useGameFx.js'
|
||||
@@ -341,11 +319,11 @@ const sessionMaxCombo = ref(0)
|
||||
const menuHeight = ref(32)
|
||||
const menuTop = ref(0)
|
||||
|
||||
const ROWS = 6
|
||||
const ROWS = 5
|
||||
const COLS = 4
|
||||
const ROW_AXES = Array.from({ length: ROWS }, (_, i) => i)
|
||||
const COL_AXES = Array.from({ length: COLS }, (_, i) => i)
|
||||
/** 6 行 × 4 列棋盘:单格像素由可用区域反算 */
|
||||
/** 5 行 × 4 列棋盘:单格像素由可用区域反算 */
|
||||
const BOARD_INSET_RPX = 4
|
||||
/** 棋盘与底部道具栏之间的安全间隙,避免最后一行被遮挡 */
|
||||
const BOARD_FOOTER_GAP_RPX = 28
|
||||
@@ -366,9 +344,11 @@ const dragPreview = ref(null)
|
||||
let tileTouchStart = null
|
||||
let touchHandledInteraction = false
|
||||
|
||||
// 每局选中的食材子集(保证消除可玩,并让每次进入素材不同)
|
||||
const SESSION_FOODS = { low: 3, mid: 2, high: 2 }
|
||||
// 每局选中的食材子集;高糖仅 1 种(消除该种即通关)
|
||||
const SESSION_FOODS = { low: 3, mid: 2, high: 1 }
|
||||
const activeFoods = ref([])
|
||||
/** 本局唯一的高糖食物类型 */
|
||||
const sessionHighFood = ref(null)
|
||||
const goalDefs = ref([])
|
||||
|
||||
function pickRandom(pool, n) {
|
||||
@@ -382,17 +362,20 @@ function pickRandom(pool, n) {
|
||||
|
||||
/**
|
||||
* 随机挑选本局食材与收集目标。每次调用结果不同:
|
||||
* 低/中/高 各取若干,组成 7 种棋子;再从中挑 2 种作为收集目标。
|
||||
* 低/中各若干 + 仅 1 种高糖;再从中挑 2 种作为收集目标。
|
||||
*/
|
||||
function selectSessionFoods() {
|
||||
const lows = FOOD_LIBRARY.filter((f) => f.gi === 'low')
|
||||
const mids = FOOD_LIBRARY.filter((f) => f.gi === 'mid')
|
||||
const highs = FOOD_LIBRARY.filter((f) => f.gi === 'high')
|
||||
|
||||
const highPick = pickRandom(highs, 1)
|
||||
sessionHighFood.value = highPick[0] ? cloneFoodType(highPick[0]) : null
|
||||
|
||||
const selected = [
|
||||
...pickRandom(lows, SESSION_FOODS.low),
|
||||
...pickRandom(mids, SESSION_FOODS.mid),
|
||||
...pickRandom(highs, SESSION_FOODS.high)
|
||||
...highPick
|
||||
]
|
||||
activeFoods.value = selected
|
||||
warmUpFoodImgs(selected)
|
||||
@@ -507,8 +490,21 @@ const selectedUid = ref(null)
|
||||
const matchChain = ref(0)
|
||||
const movesLeft = ref(25)
|
||||
const gamePhase = ref('playing')
|
||||
/** goals | high_cleared */
|
||||
const winReason = ref('')
|
||||
const loseReason = ref('')
|
||||
/** 消除高糖时的红色警示弹窗 */
|
||||
const highClearAlertVisible = ref(false)
|
||||
const clearedHighFoodName = ref('')
|
||||
|
||||
const resultTitle = computed(() => {
|
||||
if (gamePhase.value !== 'won') return '再认一认'
|
||||
if (winReason.value === 'high_cleared') return '高糖已消除!'
|
||||
return '学会啦!'
|
||||
})
|
||||
const resultMessage = ref('')
|
||||
/** 上一次三连消除的食物(摘要条展示) */
|
||||
const lastClearedFood = ref(null)
|
||||
const foodCard = ref(null)
|
||||
let foodCardTimer = null
|
||||
const floatingVals = ref([])
|
||||
@@ -666,14 +662,15 @@ const glucoseShortStatus = computed(() => {
|
||||
const glucoseAccentColor = computed(() => {
|
||||
if (glucoseLevel.value < 30) return '#3b82f6'
|
||||
if (glucoseLevel.value > 70) return '#dc2626'
|
||||
return '#006c49'
|
||||
return '#ea580c'
|
||||
})
|
||||
|
||||
const glucoseRingStyle = computed(() => {
|
||||
const pct = glucoseLevel.value
|
||||
const color = glucoseAccentColor.value
|
||||
const track = glucoseLevel.value < 30 || glucoseLevel.value > 70 ? '#e2ece6' : '#ffedd5'
|
||||
return {
|
||||
background: `conic-gradient(${color} 0 ${pct}%, #e2ece6 ${pct}% 100%)`
|
||||
background: `conic-gradient(${color} 0 ${pct}%, ${track} ${pct}% 100%)`
|
||||
}
|
||||
})
|
||||
|
||||
@@ -723,6 +720,17 @@ function randomFood() {
|
||||
return cloneFoodType(pick)
|
||||
}
|
||||
|
||||
/** 本局棋盘上是否还存在高糖食物 */
|
||||
function boardHasHighGiFood() {
|
||||
for (let r = 0; r < ROWS; r++) {
|
||||
for (let c = 0; c < COLS; c++) {
|
||||
const tile = board.value[r]?.[c]
|
||||
if (tile && !tile.isRemoved && tile.type.gi === 'high') return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function wouldCreateInitialMatch(r, c, type, currentBoard, currentRow) {
|
||||
const key = type.key
|
||||
if (r >= 2 && currentBoard[r - 1][c]?.type.key === key && currentBoard[r - 2][c]?.type.key === key) {
|
||||
@@ -833,7 +841,11 @@ function setupLevel(levelId) {
|
||||
const cfg = getLevelConfig(levelId)
|
||||
applyLevelConfig(cfg)
|
||||
sessionMaxCombo.value = 0
|
||||
winReason.value = ''
|
||||
loseReason.value = ''
|
||||
highClearAlertVisible.value = false
|
||||
clearedHighFoodName.value = ''
|
||||
lastClearedFood.value = null
|
||||
tileTouchStart = null
|
||||
clearDragPreview()
|
||||
selectSessionFoods()
|
||||
@@ -869,6 +881,10 @@ function recomputeGlucoseFromBoard() {
|
||||
|
||||
function restartLevel() {
|
||||
gamePhase.value = 'playing'
|
||||
winReason.value = ''
|
||||
highClearAlertVisible.value = false
|
||||
clearedHighFoodName.value = ''
|
||||
lastClearedFood.value = null
|
||||
resultMessage.value = ''
|
||||
resultStars.value = 0
|
||||
resultStats.value = []
|
||||
@@ -884,6 +900,9 @@ function restartLevel() {
|
||||
|
||||
function goNextLevel() {
|
||||
gamePhase.value = 'playing'
|
||||
winReason.value = ''
|
||||
highClearAlertVisible.value = false
|
||||
clearedHighFoodName.value = ''
|
||||
resultMessage.value = ''
|
||||
resultStars.value = 0
|
||||
resultStats.value = []
|
||||
@@ -1407,6 +1426,24 @@ function updateGoal(key) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 记录本批消除中代表性食物(取最大匹配组) */
|
||||
function recordLastClearedFood(groups) {
|
||||
if (!Array.isArray(groups) || !groups.length) return
|
||||
const main = groups.reduce((a, b) => ((b.size || 0) > (a.size || 0) ? b : a))
|
||||
const rep = main?.tiles?.[Math.floor((main.tiles.length || 1) / 2)]
|
||||
const t = rep?.type
|
||||
if (!t) return
|
||||
const gi = t.gi || 'low'
|
||||
lastClearedFood.value = {
|
||||
name: t.name || '食物',
|
||||
gi,
|
||||
giShort: GI_SHORT[gi] || '低糖',
|
||||
eatHint: formatEatLabel(t),
|
||||
color: GI_COLOR[gi] || '#64748b',
|
||||
food: cloneFoodType(t)
|
||||
}
|
||||
}
|
||||
|
||||
function updateScore(pts) {
|
||||
const bonus = Math.round(pts)
|
||||
score.value += bonus
|
||||
@@ -1448,10 +1485,28 @@ function showLearnFx(groups) {
|
||||
|
||||
function checkGameEnd() {
|
||||
if (gamePhase.value !== 'playing') return
|
||||
// 无失败惩罚:仅在认全目标食物时通关,步数耗尽不判负
|
||||
// 无失败惩罚:认全目标或已消除场上全部高糖食物即通关
|
||||
if (allGoalsDone.value) {
|
||||
endGame('won')
|
||||
endGame('won', { reason: 'goals' })
|
||||
return
|
||||
}
|
||||
if (sessionHighFood.value && !boardHasHighGiFood()) {
|
||||
endGame('won', {
|
||||
reason: 'high_cleared',
|
||||
foodName: sessionHighFood.value.name
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** 三连消除含高糖:先红色警示弹窗,再进入结算 */
|
||||
async function finishHighSugarClear(foodType) {
|
||||
const name = foodType?.name || sessionHighFood.value?.name || '高糖食物'
|
||||
clearedHighFoodName.value = name
|
||||
highClearAlertVisible.value = true
|
||||
triggerFlash('rgba(220, 38, 38, 0.22)', 0.35)
|
||||
await delay(2000)
|
||||
highClearAlertVisible.value = false
|
||||
endGame('won', { reason: 'high_cleared', foodName: name })
|
||||
}
|
||||
|
||||
function buildResultStats() {
|
||||
@@ -1463,11 +1518,12 @@ function buildResultStats() {
|
||||
]
|
||||
}
|
||||
|
||||
function endGame(phase) {
|
||||
function endGame(phase, opts = {}) {
|
||||
gamePhase.value = phase
|
||||
clearHints()
|
||||
|
||||
if (phase === 'won') {
|
||||
winReason.value = opts.reason || 'goals'
|
||||
const { stars, newBest } = recordWin({
|
||||
levelId: levelConfig.value.id,
|
||||
movesLeft: movesLeft.value,
|
||||
@@ -1477,14 +1533,25 @@ function endGame(phase) {
|
||||
maxCombo: sessionMaxCombo.value
|
||||
})
|
||||
resultStars.value = stars
|
||||
const learnedNames = goalList.value.map((g) => g.food?.name).filter(Boolean).join('、')
|
||||
resultMessage.value = learnedNames
|
||||
? `这一组您认识了:${learnedNames}。记住它们的含糖高低啦!`
|
||||
: '又认识了几种食物的含糖高低,真棒!'
|
||||
if (newBest && gameProgress.value.maxUnlocked > levelConfig.value.id) {
|
||||
resultMessage.value += ` 已解锁第 ${levelConfig.value.id + 1} 组。`
|
||||
if (winReason.value === 'high_cleared') {
|
||||
const name = opts.foodName || sessionHighFood.value?.name || '高糖食物'
|
||||
resultMessage.value =
|
||||
`您已消除高糖食物「${name}」!这类食物升糖快,日常要少吃。`
|
||||
resultStats.value = [
|
||||
{ label: '本局高糖食物', value: name },
|
||||
{ label: '消除练习', value: '达标' },
|
||||
{ label: '得分', value: scoreText.value }
|
||||
]
|
||||
} else {
|
||||
const learnedNames = goalList.value.map((g) => g.food?.name).filter(Boolean).join('、')
|
||||
resultMessage.value = learnedNames
|
||||
? `这一组您认识了:${learnedNames}。记住它们的含糖高低啦!`
|
||||
: '又认识了几种食物的含糖高低,真棒!'
|
||||
if (newBest && gameProgress.value.maxUnlocked > levelConfig.value.id) {
|
||||
resultMessage.value += ` 已解锁第 ${levelConfig.value.id + 1} 组。`
|
||||
}
|
||||
resultStats.value = buildResultStats()
|
||||
}
|
||||
resultStats.value = buildResultStats()
|
||||
playSfxLayer('win', 'winStinger', 120, 0.7)
|
||||
} else {
|
||||
recordLoss()
|
||||
@@ -1545,7 +1612,11 @@ async function processSwap(t1, t2, opts = {}) {
|
||||
const matches = findMatches()
|
||||
if (matches.length > 0) {
|
||||
movesLeft.value = Math.max(0, movesLeft.value - 1)
|
||||
await clearAndRefill()
|
||||
const endedByHigh = await clearAndRefill()
|
||||
if (endedByHigh) {
|
||||
isProcessing.value = false
|
||||
return
|
||||
}
|
||||
// 所有连消结束后,检查棋盘是否死锁并自动重排
|
||||
await reshuffleIfStuck()
|
||||
} else {
|
||||
@@ -1561,7 +1632,10 @@ async function processSwap(t1, t2, opts = {}) {
|
||||
|
||||
async function clearAndRefill() {
|
||||
const { groups, tiles } = findMatchGroups()
|
||||
if (!tiles.length) return
|
||||
if (!tiles.length) return false
|
||||
|
||||
const clearedHighTiles = tiles.filter((t) => t.type.gi === 'high')
|
||||
recordLastClearedFood(groups)
|
||||
|
||||
let totalVal = 0
|
||||
let maxSize = 3
|
||||
@@ -1600,14 +1674,22 @@ async function clearAndRefill() {
|
||||
await delay(MATCH_MS)
|
||||
|
||||
removeTilesFromBoard(tiles)
|
||||
|
||||
if (clearedHighTiles.length > 0) {
|
||||
await finishHighSugarClear(clearedHighTiles[0].type)
|
||||
return true
|
||||
}
|
||||
|
||||
await applyGravity()
|
||||
|
||||
const next = findMatchGroups()
|
||||
if (next.tiles.length > 0) {
|
||||
matchChain.value += 1
|
||||
await delay(200)
|
||||
await clearAndRefill()
|
||||
const ended = await clearAndRefill()
|
||||
if (ended) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async function applyGravity() {
|
||||
@@ -1771,7 +1853,11 @@ async function onBooster(booster) {
|
||||
|
||||
const matches = findMatches()
|
||||
if (matches.length > 0) {
|
||||
await clearAndRefill()
|
||||
const endedByHigh = await clearAndRefill()
|
||||
if (endedByHigh) {
|
||||
isProcessing.value = false
|
||||
return
|
||||
}
|
||||
}
|
||||
// fiber 改变了棋盘,保险检查是否死锁
|
||||
await reshuffleIfStuck()
|
||||
@@ -1937,7 +2023,7 @@ function initLayout() {
|
||||
paddingTop: `${paddingTop}px`,
|
||||
paddingLeft: '32rpx',
|
||||
paddingRight: '32rpx',
|
||||
paddingBottom: '16rpx'
|
||||
paddingBottom: '10rpx'
|
||||
}
|
||||
navStyle.value = {
|
||||
paddingRight: `${Math.max(0, headerPaddingRight - uni.upx2px(32))}px`
|
||||
@@ -1971,7 +2057,7 @@ function recalcBoardSize() {
|
||||
// 预留底部安全间隙,棋盘不贴到道具栏
|
||||
const zoneH = Math.max(0, footerTop - headerBottom - footerGap)
|
||||
|
||||
// 6 行 × 4 列:宽高分别约束,取较小单格像素
|
||||
// 5 行 × 4 列:宽高分别约束,取较小单格像素
|
||||
cellSizePx.value = calcMaxCellSize(zoneW - inset * 2, zoneH - inset * 2)
|
||||
const boardDim = calcBoardDimensions(cellSizePx.value)
|
||||
boardWidthPx.value = boardDim.width
|
||||
|
||||
Reference in New Issue
Block a user