wangfukang 4 days ago
parent
commit
ee32770ba2
  1. 78
      package1/planet/adventure.vue

78
package1/planet/adventure.vue

@ -88,6 +88,7 @@
:style="card.style"
@tap="pickCard(card)">
<text>{{card.displayIcon}}</text>
<text class="debug-layer">{{card.layer}}</text>
</view>
</view>
@ -162,8 +163,8 @@
cards: [],
slots: [],
slotLimit: 7,
timeLimit: 150,
timeLeft: 150,
timeLimit: 300,
timeLeft: 300,
timer: null,
roundSeed: '',
moveCount: 0,
@ -199,7 +200,9 @@
return Math.max(16, Math.min(100, Math.round((mine.score || 0) * 100 / top.score)))
},
visibleCards() {
return this.cards.filter(item => !item.removed && !item.selected)
return this.cards
.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
@ -225,7 +228,7 @@
return cells
},
timerText() {
return this.playing ? `${this.timeLeft}s` : '150s限时'
return this.playing ? `${this.timeLeft}s` : '300s限时'
},
timerPercent() {
return Math.max(0, Math.min(100, Math.round(this.timeLeft * 100 / this.timeLimit)))
@ -240,7 +243,7 @@
if (!this.playing) return '开始后进入倒计时'
if (this.timeLeft <= 30) return '最后冲刺,槽位别满'
if (this.timeLeft <= 60) return '时间紧张,加快决策'
return '150秒内完成助推'
return '300秒内完成助推'
},
riskText() {
if (this.slots.length >= this.slotLimit - 1) return '危险:差1格就满'
@ -274,7 +277,7 @@
const elapsed = Math.floor((Date.now() - this.startTs) / 1000)
this.timeLeft = Math.max(0, this.timeLimit - elapsed)
if (this.timeLeft <= 0) {
this.failLevel('时间到了', '超过150秒,本关失败。不消耗次数,调整顺序再来一次。')
this.failLevel('时间到了', '超过300秒,本关失败。不消耗次数,调整顺序再来一次。')
} else {
this.startTimer(false)
}
@ -356,6 +359,9 @@
if (this.shouldBuildTrapLayout()) {
this.applyTrapLayout(cards)
}
if (!this.validateTileCounts(cards)) {
this.repairTileCounts(cards, icons, garbageIcons)
}
this.cards = cards
this.slots = []
this.moveCount = 0
@ -481,6 +487,7 @@
assigned[card.id] = true
})
}
this.cards = cards
this.repositionKeyCovers(cards, seed)
const freeCards = cards.filter(card => !assigned[card.id])
const garbageCards = this.seededShuffle(freeCards.slice(), seed + '_garbage').slice(0, 6)
@ -511,11 +518,36 @@
})
return positions
},
validateTileCounts(cards) {
const counts = {}
cards.forEach(card => {
if (!card.icon) return
counts[card.icon] = (counts[card.icon] || 0) + 1
})
return Object.keys(counts).every(icon => {
const unit = this.isGarbageIcon(icon) ? 2 : 3
return counts[icon] % unit === 0
})
},
repairTileCounts(cards, icons, garbageIcons) {
const sorted = cards.slice().sort((a, b) => this.cardZIndex(a) - this.cardZIndex(b))
sorted.forEach((card, index) => {
if (index < 6) {
card.icon = garbageIcons[Math.floor(index / 2) % garbageIcons.length]
card.garbage = true
} else {
card.icon = icons[Math.floor((index - 6) / 3) % icons.length]
card.garbage = false
}
card.displayIcon = this.displayIcon(card.icon)
})
},
shouldBuildTrapLayout() {
const rand = this.seededRandom((this.roundSeed || this.levelSeed()) + '_win_rate')
return rand() < 0.5
},
applyTrapLayout(cards) {
this.cards = cards
const iconMap = {}
cards.forEach(card => {
if (this.isGarbageIcon(card.icon)) return
@ -544,6 +576,7 @@
card.x = 180 + Math.floor(rand() * 180)
card.y = 140 + Math.floor(rand() * 260)
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
@ -555,6 +588,7 @@
card.y = baseY + i * 58
card.style = `left:${card.x}rpx;top:${card.y}rpx;z-index:${this.cardZIndex(card)};`
})
this.refreshCardState()
},
buildCoverChain(key, cards, index, rand) {
const covers = cards.filter(card => {
@ -569,6 +603,7 @@
cover.y = key.y + (i < 2 ? 16 : -16) + Math.floor(rand() * 10)
cover.style = `left:${cover.x}rpx;top:${cover.y}rpx;z-index:${this.cardZIndex(cover)};`
}
this.refreshCardState()
},
repositionKeyCovers(cards, seed) {
const rand = this.seededRandom(seed + '_cover')
@ -583,6 +618,7 @@
cover.style = `left:${cover.x}rpx;top:${cover.y}rpx;z-index:${this.cardZIndex(cover)};`
}
})
this.refreshCardState()
},
takeNext(pool, assigned) {
while (pool.length) {
@ -627,7 +663,7 @@
},
coverCount(card, cards) {
return cards.filter(other => {
if (other.id === card.id || other.layer <= card.layer) return false
if (other.id === card.id || this.getRealZ(other) <= this.getRealZ(card)) return false
return this.isOverlap(card, other)
}).length
},
@ -639,15 +675,24 @@
},
isBlockedIn(card, list) {
return list.some(other => {
if (other.id === card.id || other.layer <= card.layer) return false
if (other.id === card.id || this.getRealZ(other) <= this.getRealZ(card)) return false
return this.isOverlap(card, other)
})
},
isOverlap(a, b) {
return Math.abs(a.x - b.x) < 82 && Math.abs(a.y - b.y) < 82
const size = 76
return !(
a.x + size <= b.x ||
b.x + size <= a.x ||
a.y + size <= b.y ||
b.y + size <= a.y
)
},
getRealZ(card) {
return (card.layer || 0) * 1000 + (card.order || 0)
},
cardZIndex(card) {
return (card.layer || 0) * 100 + (card.order || 0) + 1
return this.getRealZ(card) + 1
},
normalizeCards(icons) {
this.cards.forEach((card, index) => {
@ -683,8 +728,9 @@
return
}
this.refreshCardState()
if (card.removed || card.selected || card.locked || this.isLocked(card)) {
this.tui.toast('这张还被压住,先消上面的牌')
const lockedNow = this.isLocked(card)
if (card.removed || card.selected || lockedNow) {
this.tui.toast('这张卡被压住了')
return
}
if (this.slots.length >= this.slotLimit) return
@ -713,7 +759,7 @@
const elapsed = Math.floor((Date.now() - this.startTs) / 1000)
this.timeLeft = Math.max(0, this.timeLimit - elapsed)
if (this.timeLeft <= 0) {
this.failLevel('时间到了', '超过150秒,本关失败。不消耗次数,调整顺序再来一次。')
this.failLevel('时间到了', '超过300秒,本关失败。不消耗次数,调整顺序再来一次。')
}
}, 1000)
},
@ -752,8 +798,9 @@
},
isLocked(card) {
return this.cards.some(other => {
if (other.removed || other.selected || other.layer <= card.layer) return false
return this.isOverlap(card, other)
if (other.id === card.id) return false
if (other.removed || other.selected) return false
return this.getRealZ(other) > this.getRealZ(card) && this.isOverlap(card, other)
})
},
finishClear() {
@ -943,6 +990,7 @@
.board { margin-top: 22rpx; height: 620rpx; border-radius: 36rpx; background: linear-gradient(155deg, rgba(234,248,255,0.9), rgba(255,248,222,0.72)); position: relative; overflow: hidden; z-index: 1; }
.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;

Loading…
Cancel
Save