From db3b5f3649445a60b0a3fddfb6c9688826cfa428 Mon Sep 17 00:00:00 2001 From: pan Date: Tue, 21 Jul 2026 17:01:35 +0800 Subject: [PATCH] =?UTF-8?q?refactor(missionCard):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=8D=A1=E7=89=8C=E6=B1=A0=E5=88=B7=E6=96=B0=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E6=94=B9=E4=B8=BA=E6=95=B4=E6=B1=A0=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修改SCardComp的注释,将补卡逻辑改为整池刷新说明 2. 重构MissionCardComp的onCardUsed回调,替换单张补卡为整池刷新 3. 删除buildSingleHeroCard和buildSingleSkillCard两个单张补卡方法 4. 调整注释说明,新增特殊刷新避免重复触发的逻辑 --- assets/resources/game/heros/top.prefab | 348 +++++++++++++++++++--- assets/script/game/map/MissionCardComp.ts | 86 +----- assets/script/game/map/SCardComp.ts | 2 +- 3 files changed, 329 insertions(+), 107 deletions(-) diff --git a/assets/resources/game/heros/top.prefab b/assets/resources/game/heros/top.prefab index 9b295612..4e8ed0fe 100644 --- a/assets/resources/game/heros/top.prefab +++ b/assets/resources/game/heros/top.prefab @@ -37,11 +37,11 @@ "_active": true, "_components": [ { - "__id__": 98 + "__id__": 110 } ], "_prefab": { - "__id__": 100 + "__id__": 112 }, "_lpos": { "__type__": "cc.Vec3", @@ -1805,23 +1805,29 @@ }, { "__id__": 87 + }, + { + "__id__": 93 + }, + { + "__id__": 99 } ], "_active": true, "_components": [ { - "__id__": 93 + "__id__": 105 }, { - "__id__": 95 + "__id__": 107 } ], "_prefab": { - "__id__": 97 + "__id__": 109 }, "_lpos": { "__type__": "cc.Vec3", - "x": -26.182, + "x": -22.948, "y": -0.337, "z": 0 }, @@ -1885,7 +1891,7 @@ "_lscale": { "__type__": "cc.Vec3", "x": 0.2, - "y": 0.14, + "y": 0.2, "z": 1 }, "_mobility": 0, @@ -1913,7 +1919,7 @@ "_contentSize": { "__type__": "cc.Size", "width": 80, - "height": 100 + "height": 85 }, "_anchorPoint": { "__type__": "cc.Vec2", @@ -1943,13 +1949,13 @@ "_dstBlendFactor": 4, "_color": { "__type__": "cc.Color", - "r": 253, - "g": 213, - "b": 0, + "r": 255, + "g": 255, + "b": 255, "a": 255 }, "_spriteFrame": { - "__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@79d6f", + "__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@b4af4", "__expectedType__": "cc.SpriteFrame" }, "_type": 0, @@ -1989,14 +1995,14 @@ }, { "__type__": "cc.Node", - "_name": "Label", + "_name": "Slider_Level_02_Bg", "_objFlags": 0, "__editorExtras__": {}, "_parent": { "__id__": 80 }, "_children": [], - "_active": true, + "_active": false, "_components": [ { "__id__": 88 @@ -2010,8 +2016,280 @@ }, "_lpos": { "__type__": "cc.Vec3", - "x": -0.103, - "y": -0.601, + "x": 0, + "y": 0, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 0.6, + "y": 0.6, + "z": 1 + }, + "_mobility": 0, + "_layer": 1, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 87 + }, + "_enabled": true, + "__prefab": { + "__id__": 89 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 20, + "height": 20 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "c8MjBtG2ZAeJMgaljbWriK" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 87 + }, + "_enabled": true, + "__prefab": { + "__id__": 91 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@46c83", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 0, + "_fillType": 0, + "_sizeMode": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "d6anUnkoJCNoTLRDU0POvf" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "b5ndU4FTRH/r1NQ9j22a6H", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "Slider_Level_03_InnerBorder1", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 80 + }, + "_children": [], + "_active": false, + "_components": [ + { + "__id__": 94 + }, + { + "__id__": 96 + } + ], + "_prefab": { + "__id__": 98 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_lrot": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + }, + "_lscale": { + "__type__": "cc.Vec3", + "x": 0.6, + "y": 0.6, + "z": 1 + }, + "_mobility": 0, + "_layer": 1, + "_euler": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_id": "" + }, + { + "__type__": "cc.UITransform", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 93 + }, + "_enabled": true, + "__prefab": { + "__id__": 95 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 23, + "height": 24 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "93/XbJIIRDBJl2pf7NOTi2" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 93 + }, + "_enabled": true, + "__prefab": { + "__id__": 97 + }, + "_customMaterial": null, + "_srcBlendFactor": 2, + "_dstBlendFactor": 4, + "_color": { + "__type__": "cc.Color", + "r": 0, + "g": 0, + "b": 0, + "a": 255 + }, + "_spriteFrame": { + "__uuid__": "cb93c900-b440-4571-91d1-7da1636e3d73@95588", + "__expectedType__": "cc.SpriteFrame" + }, + "_type": 1, + "_fillType": 0, + "_sizeMode": 1, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_useGrayscale": false, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "c2U0QyM1hN9L9LRmqrayYY" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "66M2yZHdhHA4Ogo8TVzoR9", + "instance": null, + "targetOverrides": null, + "nestedPrefabInstanceRoots": null + }, + { + "__type__": "cc.Node", + "_name": "Label", + "_objFlags": 0, + "__editorExtras__": {}, + "_parent": { + "__id__": 80 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 100 + }, + { + "__id__": 102 + } + ], + "_prefab": { + "__id__": 104 + }, + "_lpos": { + "__type__": "cc.Vec3", + "x": 0.433, + "y": 2.048, "z": 0 }, "_lrot": { @@ -2043,16 +2321,16 @@ "_objFlags": 0, "__editorExtras__": {}, "node": { - "__id__": 87 + "__id__": 99 }, "_enabled": true, "__prefab": { - "__id__": 89 + "__id__": 101 }, "_contentSize": { "__type__": "cc.Size", - "width": 7.29, - "height": 40 + "width": 9.57, + "height": 25 }, "_anchorPoint": { "__type__": "cc.Vec2", @@ -2071,11 +2349,11 @@ "_objFlags": 0, "__editorExtras__": {}, "node": { - "__id__": 87 + "__id__": 99 }, "_enabled": true, "__prefab": { - "__id__": 91 + "__id__": 103 }, "_customMaterial": null, "_srcBlendFactor": 2, @@ -2087,26 +2365,26 @@ "b": 255, "a": 255 }, - "_string": "1", + "_string": "0", "_horizontalAlign": 1, "_verticalAlign": 1, - "_actualFontSize": 25, - "_fontSize": 25, + "_actualFontSize": 13, + "_fontSize": 13, "_fontFamily": "Arial", - "_lineHeight": 40, + "_lineHeight": 25, "_overflow": 0, "_enableWrapText": true, "_font": { - "__uuid__": "eca7fc51-87d0-4bb0-89e1-aa9c39411bc6", + "__uuid__": "dd574056-40e9-4545-8eec-eea63d489818", "__expectedType__": "cc.BitmapFont" }, "_isSystemFontUsed": false, "_spacingX": 0, "_isItalic": false, - "_isBold": true, + "_isBold": false, "_isUnderline": false, "_underlineHeight": 2, - "_cacheMode": 0, + "_cacheMode": 1, "_enableOutline": true, "_outlineColor": { "__type__": "cc.Color", @@ -2115,7 +2393,7 @@ "b": 0, "a": 255 }, - "_outlineWidth": 1, + "_outlineWidth": 2, "_enableShadow": false, "_shadowColor": { "__type__": "cc.Color", @@ -2159,12 +2437,12 @@ }, "_enabled": true, "__prefab": { - "__id__": 94 + "__id__": 106 }, "_contentSize": { "__type__": "cc.Size", - "width": 10, - "height": 13 + "width": 20, + "height": 20 }, "_anchorPoint": { "__type__": "cc.Vec2", @@ -2187,7 +2465,7 @@ }, "_enabled": false, "__prefab": { - "__id__": 96 + "__id__": 108 }, "_resizeMode": 1, "_layoutType": 1, @@ -2238,7 +2516,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 99 + "__id__": 111 }, "_contentSize": { "__type__": "cc.Size", diff --git a/assets/script/game/map/MissionCardComp.ts b/assets/script/game/map/MissionCardComp.ts index ddad41dd..ca1f50de 100644 --- a/assets/script/game/map/MissionCardComp.ts +++ b/assets/script/game/map/MissionCardComp.ts @@ -574,14 +574,16 @@ export class MissionCardComp extends CCComp { } /** - * 单张卡牌被成功使用后的补卡回调: + * 单张卡牌被成功使用后的整池刷新回调: * - payload 为该卡槽组件实例(CardComp 或 SCardComp)。 - * - 命中英雄卡槽 → 调用 buildSingleHeroCard 补一张英雄/升级卡。 - * - 命中技能卡槽 → 调用 buildSingleSkillCard 补一张技能卡。 - * - 未命中任何槽位(如已销毁/未缓存)→ 忽略。 + * - 命中英雄卡槽 → 重新构建 3 张英雄池卡牌并分发到所有英雄槽。 + * - 命中技能卡槽 → 重新构建 3 张技能卡并分发到所有技能槽。 + * - 未命中任何槽位 → 忽略。 * - * Why: 购买一张卡后立即补充新卡,避免出现空槽,提升抽卡体验; + * Why: 购买一张卡后立即刷新整个卡池(不扣金币),让玩家持续从新池中挑选; * 英雄卡池与技能卡池遵循同一逻辑。 + * SpecialRefresh 自身效果(onUseSpecialCard 中的 tryRefreshHeroCards) + * 已是整池刷新,因此 CardComp 对其不派发 CardUsed,避免双重刷新。 */ private onCardUsed(event: string, args: any) { const source = args; @@ -589,26 +591,20 @@ export class MissionCardComp extends CCComp { const heroIdx = this.cardComps.findIndex(c => c === source); if (heroIdx >= 0) { - const card = this.buildSingleHeroCard(); - if (card) { - this.cardComps[heroIdx].applyDrawCard(card); - } - mLogger.log(this.debugMode, "MissionCardComp", "refill hero slot", { - index: heroIdx, - uuid: card?.uuid ?? 0 + const cards = this.buildDrawCards(); + this.dispatchCardsToSlots(cards); + mLogger.log(this.debugMode, "MissionCardComp", "refresh hero pool after buy", { + triggerSlot: heroIdx }); return; } const skillIdx = this.skillCardComps.findIndex(c => c === source); if (skillIdx >= 0) { - const card = this.buildSingleSkillCard(); - if (card) { - this.skillCardComps[skillIdx].applyDrawCard(card); - } - mLogger.log(this.debugMode, "MissionCardComp", "refill skill slot", { - index: skillIdx, - uuid: card?.uuid ?? 0 + const cards = this.buildSkillDrawCards(); + this.dispatchCardsToSkillSlots(cards); + mLogger.log(this.debugMode, "MissionCardComp", "refresh skill pool after buy", { + triggerSlot: skillIdx }); return; } @@ -999,58 +995,6 @@ export class MissionCardComp extends CCComp { return filled; } - /** - * 构建单张英雄池卡牌,用于购买后补卡。 - * - * 规则与 buildDrawCards 保持一致(不含"必出轮询"逻辑): - * 1. 满员且有可升级英雄 → 仅从升级卡池按权重抽 1 张。 - * 2. 否则从 升级卡 + 未召唤英雄卡 的混合池按权重抽 1 张。 - * - * @returns 卡牌数据;池为空时返回 null - */ - private buildSingleHeroCard(): CardConfig | null { - const upgradeCards = this.buildHeroUpgradeCards(); - const aliveHeroCount = this.getAliveHeroCount(); - const heroMax = this.getMissionHeroMaxNum(); - - if (aliveHeroCount >= heroMax && upgradeCards.length > 0) { - return this.weightedPick(upgradeCards); - } - - const heroCards = CardPoolList.filter(c => c.type === CardType.Hero); - const aliveHeroUuids = this.getAliveHeroUuids(); - const availableHeroCards = heroCards.filter(c => !aliveHeroUuids.has(c.uuid)); - - const mixedPool: CardConfig[] = [...upgradeCards, ...availableHeroCards]; - if (mixedPool.length === 0) return null; - return this.weightedPick(mixedPool); - } - - /** - * 构建单张技能卡,用于购买后补卡。 - * 规则与 buildSkillDrawCards 对齐(按当前 wave 过滤)。 - * - * @returns 卡牌数据;池为空时返回 null - */ - private buildSingleSkillCard(): CardConfig | null { - const currentWave = this.getCurrentWave(); - const cards = drawCardsByRule(1, { - count: 1, - type: CardType.Skill, - wave: currentWave, - unique: true - }); - if (cards.length > 0) return cards[0]; - - // 兜底:放宽 wave 限制再尝试 - const fallback = drawCardsByRule(1, { - count: 1, - type: CardType.Skill, - unique: true - }); - return fallback[0] ?? null; - } - private tryRefreshHeroCards(heroType?: HType): boolean { const cards = drawCardsByRule(1, { count: 3, diff --git a/assets/script/game/map/SCardComp.ts b/assets/script/game/map/SCardComp.ts index 7a1e4a81..e8e7ff39 100644 --- a/assets/script/game/map/SCardComp.ts +++ b/assets/script/game/map/SCardComp.ts @@ -109,7 +109,7 @@ export class SCardComp extends CCComp { this.clearAfterUse(); this.isUsing = false; oops.message.dispatchEvent(GameEvent.UseSkillCard, used); - // 派发 CardUsed 让 MissionCardComp 立即补一张新技能卡到本槽位 + // 派发 CardUsed 让 MissionCardComp 刷新整个技能卡池 oops.message.dispatchEvent(GameEvent.CardUsed, this); }); return used;