|
|
|
@ -86,8 +86,8 @@ |
|
|
|
:key="card.id" |
|
|
|
:class="card.className" |
|
|
|
:style="card.style" |
|
|
|
@tap="pickCard(card)"> |
|
|
|
<text>{{card.displayIcon}}</text> |
|
|
|
@tap="pickCard(card.id)"> |
|
|
|
<text>{{card.renderIcon}}</text> |
|
|
|
<text class="debug-layer">{{card.layer}}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
@ -201,14 +201,14 @@ |
|
|
|
}, |
|
|
|
visibleCards() { |
|
|
|
return this.cards |
|
|
|
.filter(item => !item.removed && !item.selected && (item.coverDepth || 0) < 2) |
|
|
|
.filter(item => !item.removed && !item.selected) |
|
|
|
.sort((a,b)=>this.cardZIndex(a)-this.cardZIndex(b)) |
|
|
|
}, |
|
|
|
remainingCount() { |
|
|
|
return this.cards.filter(item => !item.removed && !item.selected).length |
|
|
|
}, |
|
|
|
availableCount() { |
|
|
|
return this.cards.filter(item => !item.removed && !item.selected && !item.locked).length |
|
|
|
return this.cards.filter(item => !item.removed && !item.selected && item.coverDepth === 0 && !item.locked).length |
|
|
|
}, |
|
|
|
directComboCount() { |
|
|
|
return this.collectDifficultyStats(this.cards.filter(item => !item.removed && !item.selected)).directComboCount |
|
|
|
@ -340,7 +340,7 @@ |
|
|
|
}, |
|
|
|
buildLevel() { |
|
|
|
const icons = ['🍔', '🥤', '🥟', '🏀', '🎧', '🚲', '🍜', '🔥', '☕', '🍢'] |
|
|
|
const garbageIcons = ['🚀', '🪐', '🛸'] |
|
|
|
const garbageIcons = ['🚀', '🍱', '🍗'] |
|
|
|
if (!this.roundSeed) this.roundSeed = this.newRoundSeed() |
|
|
|
let cards = [] |
|
|
|
for (let attempt = 0; attempt < 100; attempt++) { |
|
|
|
@ -459,7 +459,7 @@ |
|
|
|
const midOuter = this.seededShuffle(middle.filter(card => !this.isCenterCard(card)), seed + '_mid_outer') |
|
|
|
const assigned = {} |
|
|
|
const groupCount = Math.floor((cards.length - 6) / 3) |
|
|
|
const trapCount = Math.max(10, Math.ceil(groupCount * 0.5)) |
|
|
|
const trapCount = Math.max(10,Math.ceil(groupCount*0.5)) |
|
|
|
for (let group = 0; group < groupCount; group++) { |
|
|
|
const icon = icons[group % icons.length] |
|
|
|
let chosen = [] |
|
|
|
@ -544,7 +544,7 @@ |
|
|
|
}, |
|
|
|
shouldBuildTrapLayout() { |
|
|
|
const rand = this.seededRandom((this.roundSeed || this.levelSeed()) + '_win_rate') |
|
|
|
return rand() < 0.5 |
|
|
|
return rand() < 0.85 |
|
|
|
}, |
|
|
|
applyTrapLayout(cards) { |
|
|
|
this.cards = cards |
|
|
|
@ -558,7 +558,7 @@ |
|
|
|
if (!candidates.length) return |
|
|
|
const rand = this.seededRandom((this.roundSeed || this.levelSeed()) + '_trap_layout') |
|
|
|
this.shuffleWithRandom(candidates, rand) |
|
|
|
const trapIcons = candidates.slice(0, 8 + Math.floor(rand() * 5)) |
|
|
|
const trapIcons = candidates.slice(0, Math.min(candidates.length, 12 + Math.floor(rand() * 5))) |
|
|
|
trapIcons.forEach((targetIcon, trapIndex) => { |
|
|
|
const group = iconMap[targetIcon].slice(0, 3) |
|
|
|
if (group.length < 3) return |
|
|
|
@ -573,14 +573,14 @@ |
|
|
|
card.layer = 0 |
|
|
|
card.keyCard = true |
|
|
|
card.trap = true |
|
|
|
card.x = 180 + Math.floor(rand() * 180) |
|
|
|
card.y = 140 + Math.floor(rand() * 260) |
|
|
|
card.x = 170 + Math.floor(rand() * 200) |
|
|
|
card.y = 130 + Math.floor(rand() * 300) |
|
|
|
card.style = `left:${card.x}rpx;top:${card.y}rpx;z-index:${this.cardZIndex(card)};` |
|
|
|
this.refreshCardState() |
|
|
|
}, |
|
|
|
exposePairEarly(pair, index) { |
|
|
|
const baseX = 66 + (index % 4) * 100 |
|
|
|
const baseY = 24 + Math.floor(index / 4) * 88 |
|
|
|
const baseX = 56 + (index % 5) * 84 |
|
|
|
const baseY = 18 + Math.floor(index / 5) * 76 |
|
|
|
pair.forEach((card, i) => { |
|
|
|
card.layer = 2 |
|
|
|
card.trap = true |
|
|
|
@ -595,12 +595,12 @@ |
|
|
|
return card.id !== key.id && !card.garbage && !card.keyCard && !card.trap && card.layer > 0 |
|
|
|
}) |
|
|
|
this.shuffleWithRandom(covers, rand) |
|
|
|
const count = 4 + (index % 2) |
|
|
|
const count = 5 + (index % 3) |
|
|
|
for (let i = 0; i < count && i < covers.length; i++) { |
|
|
|
const cover = covers[i] |
|
|
|
cover.layer = i % 2 === 0 ? 1 : 2 |
|
|
|
cover.x = key.x + (i % 2 === 0 ? 16 : -16) + Math.floor(rand() * 10) |
|
|
|
cover.y = key.y + (i < 2 ? 16 : -16) + Math.floor(rand() * 10) |
|
|
|
cover.x = key.x + (i % 2 === 0 ? 14 : -14) + Math.floor(rand() * 10) |
|
|
|
cover.y = key.y + (i % 3 === 0 ? 14 : -14) + Math.floor(rand() * 10) |
|
|
|
cover.style = `left:${cover.x}rpx;top:${cover.y}rpx;z-index:${this.cardZIndex(cover)};` |
|
|
|
} |
|
|
|
this.refreshCardState() |
|
|
|
@ -668,7 +668,7 @@ |
|
|
|
}).length |
|
|
|
}, |
|
|
|
isGarbageIcon(icon) { |
|
|
|
return icon === '🚀' || icon === '🪐' || icon === '🛸' |
|
|
|
return icon === '🚀' || icon === '🍱' || icon === '🍗' |
|
|
|
}, |
|
|
|
isCenterCard(card) { |
|
|
|
return card.x >= 160 && card.x <= 400 && card.y >= 120 && card.y <= 440 |
|
|
|
@ -681,12 +681,14 @@ |
|
|
|
}, |
|
|
|
isOverlap(a, b) { |
|
|
|
const size = 76 |
|
|
|
return !( |
|
|
|
a.x + size <= b.x || |
|
|
|
b.x + size <= a.x || |
|
|
|
a.y + size <= b.y || |
|
|
|
b.y + size <= a.y |
|
|
|
) |
|
|
|
const overlapX = Math.min(a.x + size, b.x + size) - Math.max(a.x, b.x) |
|
|
|
const overlapY = Math.min(a.y + size, b.y + size) - Math.max(a.y, b.y) |
|
|
|
if (overlapX <= 0 || overlapY <= 0) return false |
|
|
|
const minAxis = 12 |
|
|
|
const minAreaRatio = 0.08 |
|
|
|
return overlapX >= minAxis && |
|
|
|
overlapY >= minAxis && |
|
|
|
(overlapX * overlapY) >= size * size * minAreaRatio |
|
|
|
}, |
|
|
|
getRealZ(card) { |
|
|
|
return (card.layer || 0) * 1000 + (card.order || 0) |
|
|
|
@ -700,7 +702,9 @@ |
|
|
|
card.displayIcon = this.displayIcon(card.icon) |
|
|
|
card.locked = false |
|
|
|
card.coverDepth = 0 |
|
|
|
card.className = '' |
|
|
|
card.displayState = 'top' |
|
|
|
card.renderIcon = card.displayIcon |
|
|
|
card.className = 'active' |
|
|
|
card.style = `left:${card.x}rpx;top:${card.y}rpx;z-index:${this.cardZIndex(card)};` |
|
|
|
}) |
|
|
|
}, |
|
|
|
@ -712,12 +716,14 @@ |
|
|
|
refreshCardState() { |
|
|
|
this.cards.forEach(card => { |
|
|
|
const depth = this.coverDepth(card) |
|
|
|
const locked = !card.removed && !card.selected && depth > 0 |
|
|
|
card.locked = locked |
|
|
|
card.locked = !card.removed && !card.selected && depth > 0 |
|
|
|
card.coverDepth = depth |
|
|
|
card.displayState = depth === 0 ? 'top' : (depth === 1 ? 'middle' : 'deep') |
|
|
|
card.renderIcon = card.displayState === 'deep' ? '' : (card.displayIcon || this.displayIcon(card.icon)) |
|
|
|
card.className = [ |
|
|
|
depth === 0 ? 'active' : '', |
|
|
|
depth === 1 ? 'locked' : '', |
|
|
|
depth >= 2 ? 'hidden-deep' : '', |
|
|
|
depth >= 2 ? 'hidden-card' : '', |
|
|
|
card.selected ? 'selected' : '' |
|
|
|
].filter(Boolean).join(' ') |
|
|
|
}) |
|
|
|
@ -730,7 +736,9 @@ |
|
|
|
return this.getRealZ(other) > this.getRealZ(card) && this.isOverlap(card, other) |
|
|
|
}).length |
|
|
|
}, |
|
|
|
pickCard(card) { |
|
|
|
pickCard(id) { |
|
|
|
const card = this.cards.find(item => item.id === id) |
|
|
|
if (!card) return |
|
|
|
if (this.cleared) { |
|
|
|
this.tui.toast('今日已助推,明天再来') |
|
|
|
return |
|
|
|
@ -740,11 +748,11 @@ |
|
|
|
return |
|
|
|
} |
|
|
|
this.refreshCardState() |
|
|
|
const lockedNow = this.isLocked(card) |
|
|
|
if (card.removed || card.selected || lockedNow) { |
|
|
|
if (card.coverDepth > 0) { |
|
|
|
this.tui.toast('这张卡被压住了') |
|
|
|
return |
|
|
|
} |
|
|
|
if (card.removed || card.selected) return |
|
|
|
if (this.slots.length >= this.slotLimit) return |
|
|
|
card.displayIcon = this.displayIcon(card.icon) |
|
|
|
card.selected = true |
|
|
|
@ -999,11 +1007,11 @@ |
|
|
|
.tile { position: absolute; width: 76rpx; height: 76rpx; border-radius: 22rpx; background: #fff; display: flex; align-items: center; justify-content: center; box-shadow: 0 10rpx 22rpx rgba(66,99,94,0.12); border: 2rpx solid rgba(255,255,255,0.9); transition: transform .12s ease, opacity .12s ease; } |
|
|
|
.tile text { font-size: 42rpx; } |
|
|
|
.tile .debug-layer { position: absolute; right: 6rpx; bottom: 4rpx; font-size: 16rpx; color: #8AA09C; line-height: 1; } |
|
|
|
.tile.locked { |
|
|
|
opacity: .42; |
|
|
|
pointer-events: none; |
|
|
|
} |
|
|
|
.tile.hidden-deep { display: none; pointer-events: none; } |
|
|
|
.tile.active { background: #fff; box-shadow: 0 12rpx 24rpx rgba(66,99,94,0.14); } |
|
|
|
.tile.locked { opacity: .45; filter: grayscale(100%); background: #F3F6F5; box-shadow: 0 6rpx 14rpx rgba(66,99,94,0.08); pointer-events: none; } |
|
|
|
.tile.hidden-card { opacity: .32; background: #fff; border-radius: 22rpx; box-shadow: none; color: #BFC9D4; pointer-events: none; } |
|
|
|
.tile.hidden-card text:first-child { display: none; } |
|
|
|
.tile.hidden-card::after { content: '?'; font-size: 36rpx; color: #BFC9D4; } |
|
|
|
.tile.selected { opacity: 0; transform: scale(.5); pointer-events: none; } |
|
|
|
.slot-wrap { margin-top: 24rpx; } |
|
|
|
.slot-title { color: #6B817D; font-size: 24rpx; margin-bottom: 14rpx; } |
|
|
|
|