From 95422c0cfc73b1c201244246701101d546f25fb1 Mon Sep 17 00:00:00 2001 From: wangfukang <15630117759@163.com> Date: Wed, 3 Jun 2026 10:33:45 +0800 Subject: [PATCH] 1 --- package1/planet/adventure.vue | 183 ++++++++++++++++++++++++++++------ 1 file changed, 154 insertions(+), 29 deletions(-) diff --git a/package1/planet/adventure.vue b/package1/planet/adventure.vue index 059f8df..36addc5 100644 --- a/package1/planet/adventure.vue +++ b/package1/planet/adventure.vue @@ -433,11 +433,11 @@ ] }, hell: { - layerCounts: [36, 30, 24], + layerCounts: [52, 40, 28], zones: [ - { x: 58, y: 18, cols: 6, gapX: 86, gapY: 82, offsetX: 0, offsetY: 0, stagger: 4 }, - { x: 102, y: 58, cols: 5, gapX: 86, gapY: 82, offsetX: 0, offsetY: 0, stagger: 4 }, - { x: 144, y: 98, cols: 4, gapX: 86, gapY: 82, offsetX: 0, offsetY: 0, stagger: 4 } + { x: 44, y: 14, cols: 7, gapX: 76, gapY: 72, offsetX: 0, offsetY: 0, stagger: 4 }, + { x: 72, y: 42, cols: 6, gapX: 76, gapY: 72, offsetX: 0, offsetY: 0, stagger: 4 }, + { x: 34, y: 18, cols: 7, gapX: 76, gapY: 88, offsetX: 0, offsetY: 0, stagger: 0 } ] } } @@ -450,6 +450,7 @@ card.trap = false card.keyCard = false card.garbage = false + card.openingSafe = false }) const bottom = this.seededShuffle(cards.filter(card => card.layer === 0), seed + '_bottom') const middle = this.seededShuffle(cards.filter(card => card.layer === 1), seed + '_middle') @@ -459,7 +460,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(20,Math.ceil(groupCount*0.62)) for (let group = 0; group < groupCount; group++) { const icon = icons[group % icons.length] let chosen = [] @@ -543,8 +544,7 @@ }) }, shouldBuildTrapLayout() { - const rand = this.seededRandom((this.roundSeed || this.levelSeed()) + '_win_rate') - return rand() < 0.85 + return true }, applyTrapLayout(cards) { this.cards = cards @@ -558,49 +558,168 @@ if (!candidates.length) return const rand = this.seededRandom((this.roundSeed || this.levelSeed()) + '_trap_layout') this.shuffleWithRandom(candidates, rand) - const trapIcons = candidates.slice(0, Math.min(candidates.length, 12 + Math.floor(rand() * 5))) + const trapIcons = candidates.slice(0, Math.min(candidates.length, 8 + Math.floor(rand() * 2))) trapIcons.forEach((targetIcon, trapIndex) => { - const group = iconMap[targetIcon].slice(0, 3) + const group = this.seededShuffle(iconMap[targetIcon].slice(), (this.roundSeed || this.levelSeed()) + '_trap_icon_' + trapIndex).slice(0, 3) if (group.length < 3) return const key = group[0] const pair = group.slice(1, 3) - this.placeDeepKeyCard(key, trapIndex, rand) this.exposePairEarly(pair, trapIndex) + this.placeDeepKeyCard(key, trapIndex, rand) this.buildCoverChain(key, cards, trapIndex, rand) }) + this.exposeOpeningCombos(cards, candidates, rand) + this.tightenOpeningPressure(cards, rand) }, placeDeepKeyCard(card, index, rand) { card.layer = 0 card.keyCard = true card.trap = true - card.x = 170 + Math.floor(rand() * 200) - card.y = 130 + Math.floor(rand() * 300) + card.order = 20 + index + card.x = 188 + Math.floor(rand() * 150) + card.y = 150 + Math.floor(rand() * 250) card.style = `left:${card.x}rpx;top:${card.y}rpx;z-index:${this.cardZIndex(card)};` this.refreshCardState() }, exposePairEarly(pair, index) { - const baseX = 56 + (index % 5) * 84 - const baseY = 18 + Math.floor(index / 5) * 76 + const slots = [ + { x: 34, y: 16 }, { x: 138, y: 16 }, { x: 242, y: 16 }, { x: 346, y: 16 }, { x: 450, y: 16 }, + { x: 34, y: 114 }, { x: 138, y: 114 }, { x: 242, y: 114 }, { x: 346, y: 114 }, { x: 450, y: 114 }, + { x: 34, y: 314 }, { x: 138, y: 314 }, { x: 242, y: 314 }, { x: 346, y: 314 }, { x: 450, y: 314 }, + { x: 34, y: 412 }, { x: 138, y: 412 }, { x: 242, y: 412 }, { x: 346, y: 412 }, { x: 450, y: 412 } + ] + const first = slots[index % 10] + const second = slots[index % 10 + 10] pair.forEach((card, i) => { card.layer = 2 + card.order = 900 + index * 4 + i card.trap = true - card.x = baseX + i * 8 - card.y = baseY + i * 58 + card.x = i === 0 ? first.x : second.x + card.y = i === 0 ? first.y : second.y card.style = `left:${card.x}rpx;top:${card.y}rpx;z-index:${this.cardZIndex(card)};` }) this.refreshCardState() }, + exposeOpeningCombos(cards, candidates, rand) { + const slots = [ + { x: 38, y: 16 }, { x: 122, y: 16 }, { x: 206, y: 16 }, + { x: 310, y: 16 }, { x: 394, y: 16 }, { x: 478, y: 16 }, + { x: 38, y: 118 }, { x: 122, y: 118 }, { x: 206, y: 118 }, + { x: 310, y: 118 }, { x: 394, y: 118 }, { x: 478, y: 118 }, + { x: 38, y: 408 }, { x: 122, y: 408 }, { x: 206, y: 408 } + ] + const safeIcons = candidates.slice(-4) + let slotIndex = 0 + safeIcons.forEach((icon, groupIndex) => { + const group = cards.filter(card => card.icon === icon && !card.garbage && !card.keyCard && !card.trap).slice(0, 3) + if (group.length < 3 || slotIndex + 2 >= slots.length) return + group.forEach(card => { + const slot = slots[slotIndex++] + card.layer = 2 + card.trap = false + card.keyCard = false + card.openingSafe = true + card.order = 1100 + groupIndex * 8 + slotIndex + card.x = slot.x + Math.floor(rand() * 4) + card.y = slot.y + Math.floor(rand() * 4) + 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 => { - return card.id !== key.id && !card.garbage && !card.keyCard && !card.trap && card.layer > 0 + return card.id !== key.id && !card.garbage && !card.keyCard && !card.trap && !card.openingSafe && card.layer > 0 }) this.shuffleWithRandom(covers, rand) - const count = 5 + (index % 3) + const count = 7 + (index % 3) + const offsets = [ + { x: 0, y: 0 }, + { x: 8, y: 8 }, + { x: -8, y: 10 }, + { x: 10, y: -8 }, + { x: -10, y: -6 }, + { x: 2, y: 14 }, + { x: 14, y: 2 }, + { x: -14, y: 4 }, + { x: 4, y: -14 }, + { x: -4, y: 16 }, + { x: 16, y: -4 }, + { x: -16, y: -2 } + ] 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 ? 14 : -14) + Math.floor(rand() * 10) - cover.y = key.y + (i % 3 === 0 ? 14 : -14) + Math.floor(rand() * 10) + const offset = offsets[i % offsets.length] + cover.layer = i < 5 ? 1 : 2 + cover.order = 520 + index * 28 + i + cover.x = key.x + offset.x + Math.floor(rand() * 5) + cover.y = key.y + offset.y + Math.floor(rand() * 5) + cover.style = `left:${cover.x}rpx;top:${cover.y}rpx;z-index:${this.cardZIndex(cover)};` + } + this.refreshCardState() + }, + tightenOpeningPressure(cards, rand) { + let buryIndex = 0 + for (let round = 0; round < 3; round++) { + this.refreshCardState() + const visibleMap = {} + cards.forEach(card => { + if (card.removed || card.selected || card.coverDepth > 0 || this.isGarbageIcon(card.icon)) return + if (!visibleMap[card.icon]) visibleMap[card.icon] = [] + visibleMap[card.icon].push(card) + }) + let changed = false + Object.keys(visibleMap).forEach(icon => { + const list = visibleMap[icon].sort((a, b) => { + if (a.openingSafe !== b.openingSafe) return a.openingSafe ? -1 : 1 + if (a.trap !== b.trap) return a.trap ? -1 : 1 + return this.getRealZ(b) - this.getRealZ(a) + }) + const keepCount = list.some(card => card.openingSafe) ? 3 : (list.some(card => !card.trap) ? 3 : 2) + list.slice(keepCount).forEach(card => { + changed = true + this.buryOpeningCard(card, cards, buryIndex++, rand) + }) + }) + if (!changed) break + } + this.refreshCardState() + const visible = cards.filter(card => !card.removed && !card.selected && card.coverDepth === 0 && !this.isGarbageIcon(card.icon) && !card.openingSafe) + visible + .sort((a, b) => { + if (a.trap !== b.trap) return a.trap ? -1 : 1 + return this.getRealZ(b) - this.getRealZ(a) + }) + .slice(30) + .forEach(card => { + this.buryOpeningCard(card, cards, buryIndex++, rand) + }) + this.refreshCardState() + }, + buryOpeningCard(card, cards, index, rand) { + card.layer = 0 + card.trap = true + card.keyCard = true + card.order = 40 + index + card.x = 170 + (index % 5) * 44 + Math.floor(rand() * 10) + card.y = 150 + Math.floor(index / 5) * 54 + Math.floor(rand() * 12) + card.style = `left:${card.x}rpx;top:${card.y}rpx;z-index:${this.cardZIndex(card)};` + this.buildCoverChain(card, cards, 20 + index, rand) + if (this.coverCount(card, cards) < 3) { + this.forceCoverBuriedCard(card, cards, index, rand) + } + }, + forceCoverBuriedCard(card, cards, index, rand) { + const covers = cards.filter(item => { + return item.id !== card.id && !item.garbage && !item.keyCard && !item.trap && !item.openingSafe && item.layer > 0 + }) + this.shuffleWithRandom(covers, rand) + for (let i = 0; i < 3 && i < covers.length; i++) { + const cover = covers[i] + cover.layer = i === 0 ? 1 : 2 + cover.order = 980 + index * 8 + i + cover.x = card.x + (i === 0 ? 0 : (i === 1 ? 12 : -12)) + Math.floor(rand() * 4) + cover.y = card.y + (i === 0 ? 0 : (i === 1 ? 10 : -10)) + Math.floor(rand() * 4) cover.style = `left:${cover.x}rpx;top:${cover.y}rpx;z-index:${this.cardZIndex(cover)};` } this.refreshCardState() @@ -664,7 +783,7 @@ coverCount(card, cards) { return cards.filter(other => { if (other.id === card.id || this.getRealZ(other) <= this.getRealZ(card)) return false - return this.isOverlap(card, other) + return this.covers(other, card) }).length }, isGarbageIcon(icon) { @@ -676,7 +795,7 @@ isBlockedIn(card, list) { return list.some(other => { if (other.id === card.id || this.getRealZ(other) <= this.getRealZ(card)) return false - return this.isOverlap(card, other) + return this.covers(other, card) }) }, isOverlap(a, b) { @@ -690,6 +809,13 @@ overlapY >= minAxis && (overlapX * overlapY) >= size * size * minAreaRatio }, + // upper 是否真正压住 lower:同层不会重叠,故只要两轴都有实质重叠即判定被压 + covers(upper, lower) { + const size = 76 + const overlapX = Math.min(upper.x + size, lower.x + size) - Math.max(upper.x, lower.x) + const overlapY = Math.min(upper.y + size, lower.y + size) - Math.max(upper.y, lower.y) + return overlapX >= 10 && overlapY >= 10 + }, getRealZ(card) { return (card.layer || 0) * 1000 + (card.order || 0) }, @@ -719,7 +845,7 @@ 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.renderIcon = card.displayState === 'deep' ? '?' : (card.displayIcon || this.displayIcon(card.icon)) card.className = [ depth === 0 ? 'active' : '', depth === 1 ? 'locked' : '', @@ -733,7 +859,7 @@ return this.cards.filter(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) + return this.getRealZ(other) > this.getRealZ(card) && this.covers(other, card) }).length }, pickCard(id) { @@ -1008,10 +1134,9 @@ .tile text { font-size: 42rpx; } .tile .debug-layer { position: absolute; right: 6rpx; bottom: 4rpx; font-size: 16rpx; color: #8AA09C; line-height: 1; } .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.locked { opacity: .45; filter: grayscale(100%); background: #F3F6F5; box-shadow: 0 6rpx 14rpx rgba(66,99,94,0.08); } + .tile.hidden-card { opacity: .32; background: #fff; border-radius: 22rpx; box-shadow: none; color: #BFC9D4; } + .tile.hidden-card text:first-child { display: block; 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; }