feat: 新增装备商店系统,调整英雄站位与抽卡逻辑

1.  重构抽卡函数,新增排除装备卡参数,装备卡改为商店直购
2.  添加装备商店面板,支持装备浏览与购买,跨波次保留购买记录
3.  调整英雄出场点位坐标,优化战场布局
4.  扩展技能卡槽位,新增两行技能槽位置
5.  重构EquipListComp组件,适配装备商店UI逻辑
6.  删除废弃的melist预制件与相关元文件
7.  调整hnode预制件布局参数
This commit is contained in:
pan
2026-07-22 10:44:01 +08:00
parent d37fadf5cf
commit 401b02be96
9 changed files with 14396 additions and 4153 deletions

View File

@@ -35,13 +35,14 @@
* - smc.vmdata.mission_data —— 局内数据coin / hero_num / hero_max_num
*/
import { mLogger } from "../common/Logger";
import { _decorator, Label, Node, NodeEventType, Prefab, Tween, tween, Vec3 } from "cc";
import { _decorator, instantiate, Label, Node, NodeEventType, Prefab, Tween, tween, Vec3 } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { GameEvent } from "../common/config/GameEvent";
import { CardConfig, CardPoolList, CardType, drawCardsByRule, SpecialRefreshCardList, SpecialRefreshHeroType, SpecialUpgradeCardList } from "../common/config/CardSet";
import { CardConfig, CardPoolList, CardType, drawCardsByRule, isEquipmentCard, SpecialRefreshCardList, SpecialRefreshHeroType, SpecialUpgradeCardList } from "../common/config/CardSet";
import { CardComp } from "./CardComp";
import { SCardComp } from "./SCardComp";
import { EquipListComp } from "./EquipListComp";
import { oops } from "db://oops-framework/core/Oops";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { smc } from "../common/SingletonModuleComp";
@@ -165,6 +166,8 @@ export class MissionCardComp extends CCComp {
private cardComps: CardComp[] = [];
/** 技能卡槽控制器缓存 */
private skillCardComps: SCardComp[] = [];
/** 已购买装备的 UUID 集合(跨波次保持,防止重复购买) */
private purchasedEquipUuids: Set<number> = new Set();
/** 是否已缓存卡牌面板基准缩放 */
private hasCachedCardsBaseScale: boolean = false;
/** 卡牌面板基准缩放(从场景读取) */
@@ -214,6 +217,12 @@ export class MissionCardComp extends CCComp {
if (this.closeHeros && this.closeHeros.isValid) {
this.closeHeros.off(NodeEventType.TOUCH_END, this.onCloseHerosClick, this);
}
if (this.showEquips && this.showEquips.isValid) {
this.showEquips.off(NodeEventType.TOUCH_END, this.onShowEquipsClick, this);
}
if (this.closeEquips && this.closeEquips.isValid) {
this.closeEquips.off(NodeEventType.TOUCH_END, this.onCloseEquipsClick, this);
}
this.unbindEvents();
}
@@ -256,12 +265,17 @@ export class MissionCardComp extends CCComp {
const cards = this.buildDrawCards();
this.dispatchCardsToSlots(cards);
// 重置购买记录并填充装备商店
this.purchasedEquipUuids.clear();
this.populateEquipments();
mLogger.log(this.debugMode, "MissionCardComp", "mission start");
}
/** 任务结束:清空 3 槽 + 英雄面板并隐藏整个节点 */
/** 任务结束:清空 3 槽 + 装备商店 + 英雄面板并隐藏整个节点 */
onMissionEnd() {
this.clearAllCards();
this.clearEquipments();
if (this.node && this.node.isValid) {
this.node.active = false;
}
@@ -319,6 +333,11 @@ export class MissionCardComp extends CCComp {
/** 关闭英雄卡池按钮 */
this.closeHeros?.on(NodeEventType.TOUCH_END, this.onCloseHerosClick, this);
/** 装备商店显示/隐藏切换按钮 */
this.showEquips?.on(NodeEventType.TOUCH_END, this.onShowEquipsClick, this);
/** 关闭装备商店按钮 */
this.closeEquips?.on(NodeEventType.TOUCH_END, this.onCloseEquipsClick, this);
/** 技能卡刷新按钮 */
this.skill_refresh?.on(NodeEventType.TOUCH_START, this.onSkillDrawTouchStart, this);
this.skill_refresh?.on(NodeEventType.TOUCH_END, this.onSkillDrawTouchEnd, this);
@@ -456,6 +475,12 @@ export class MissionCardComp extends CCComp {
// 由 onCardUsed 立即向被使用的槽位补充一张新技能卡。
// 弹窗由外部(按钮/阶段切换)控制显隐。
// 追踪装备购买记录EquipListComp 购买后也会派发此事件)
const usedCard = args as CardConfig;
if (usedCard && isEquipmentCard(usedCard)) {
this.purchasedEquipUuids.add(usedCard.uuid);
}
// 修复:独立判断 guide2 的关闭 和 guide3 的开启
if (!smc.finish_guides.includes(2)) {
smc.finish_guides.push(2);
@@ -492,6 +517,12 @@ export class MissionCardComp extends CCComp {
if (this.closeHeros && this.closeHeros.isValid) {
this.closeHeros.off(NodeEventType.TOUCH_END, this.onCloseHerosClick, this);
}
if (this.showEquips && this.showEquips.isValid) {
this.showEquips.off(NodeEventType.TOUCH_END, this.onShowEquipsClick, this);
}
if (this.closeEquips && this.closeEquips.isValid) {
this.closeEquips.off(NodeEventType.TOUCH_END, this.onCloseEquipsClick, this);
}
if (this.skill_refresh && this.skill_refresh.isValid) {
this.skill_refresh.off(NodeEventType.TOUCH_START, this.onSkillDrawTouchStart, this);
this.skill_refresh.off(NodeEventType.TOUCH_END, this.onSkillDrawTouchEnd, this);
@@ -680,6 +711,71 @@ export class MissionCardComp extends CCComp {
oops.gui.remove(UIID.HInfo);
}
// ======================== 装备商店面板 ========================
/**
* 装备商店显隐切换按钮回调:
* 切换 equipsPanNode 的 active 状态。
*/
private onShowEquipsClick() {
if (!this.equipsPanNode || !this.equipsPanNode.isValid) return;
oops.audio.playEffect("music/button");
this.equipsPanNode.active = !this.equipsPanNode.active;
}
/** 关闭装备商店按钮回调 */
private onCloseEquipsClick() {
if (!this.equipsPanNode || !this.equipsPanNode.isValid) return;
oops.audio.playEffect("music/button");
this.equipsPanNode.active = false;
}
/**
* 填充装备列表:
* 从 CardPoolList 获取所有装备卡trigger_type=Field
* 实例化 equipPrefab 到 equipsBoxNode
* 每个装备项由 EquipListComp 渲染并处理购买。
*
* 已购买的装备会标记为已购状态(隐藏购买按钮)。
*/
private populateEquipments() {
if (!this.equipsBoxNode || !this.equipPrefab) return;
// 清空旧列表
this.equipsBoxNode.removeAllChildren();
// 获取所有装备卡
const equipments = CardPoolList.filter(c => isEquipmentCard(c));
for (const equip of equipments) {
const node = instantiate(this.equipPrefab);
this.equipsBoxNode.addChild(node);
const comp = node.getComponent(EquipListComp) || node.addComponent(EquipListComp);
comp.applyCardData(equip);
// 已购买的装备标记为已购
if (this.purchasedEquipUuids.has(equip.uuid)) {
comp.setPurchased();
}
}
// 默认显示装备面板
if (this.equipsPanNode) {
this.equipsPanNode.active = true;
}
mLogger.log(this.debugMode, "MissionCardComp", "populate equipments", {
count: equipments.length
});
}
/** 清空装备列表 */
private clearEquipments() {
if (this.equipsBoxNode && this.equipsBoxNode.isValid) {
this.equipsBoxNode.removeAllChildren();
}
}
// ======================== 技能抽卡按钮回调 ========================
private onSkillDrawTouchStart() {
this.playButtonPressAnim(this.skill_refresh);
@@ -986,11 +1082,13 @@ export class MissionCardComp extends CCComp {
private buildSkillDrawCards(): CardConfig[] {
const currentWave = this.getCurrentWave();
// 使用明确规则的 drawCardsByRule指定只要 3 张技能卡,并且过滤对应 wave
// 装备卡已改为商店直购,不再参与抽卡
const cards = drawCardsByRule(1, {
count: 3,
type: CardType.Skill,
wave: currentWave,
unique: true // 保证技能牌不重复
unique: true, // 保证技能牌不重复
excludeEquipment: true, // 排除装备卡
});
if (cards.length >= 3) return cards.slice(0, 3);
@@ -1000,7 +1098,8 @@ export class MissionCardComp extends CCComp {
count: 3,
type: CardType.Skill,
wave: currentWave,
unique: true
unique: true,
excludeEquipment: true,
});
if (fallback.length === 0) break;
@@ -1345,6 +1444,7 @@ export class MissionCardComp extends CCComp {
// 关键:在 reset/销毁 时将 Map 置空,彻底切断引用
this.cardComps = [] as any;
this.skillCardComps = [] as any;
this.purchasedEquipUuids.clear();
if (this.node && this.node.isValid) {
this.node.destroy();