refactor(英雄管理): 将英雄与金币数据迁移至全局任务数据

- 移除 Hero.ts 中手动维护的 hero_num 计数逻辑
- 在 SingletonModuleComp 的 mission_data 中添加 hero_max_num、hero_extend_max_num 字段
- 重构 MissionCardComp,使其通过 smc.vmdata.mission_data 读写英雄数量、金币等状态
- 新增辅助方法统一数据访问与同步,避免状态分散管理
This commit is contained in:
walkpan
2026-03-25 23:32:55 +08:00
parent 8a151a3922
commit afe11291f1
4 changed files with 958 additions and 870 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,8 @@ export class SingletonModuleComp extends ecs.Comp {
mission_data:{ mission_data:{
mon_num:0,//怪物数量 mon_num:0,//怪物数量
hero_num:0,//英雄数量 hero_num:0,//英雄数量
hero_max_num:5,//英雄可召唤上限
hero_extend_max_num:6,//英雄可拓展上限
wave_time_num:0,//波次时间 wave_time_num:0,//波次时间
in_fight:false, in_fight:false,
fight_time:0,//战斗时间 fight_time:0,//战斗时间

View File

@@ -150,8 +150,6 @@ export class Hero extends ecs.Entity {
} }
}) })
.start(); .start();
// 维护关卡内英雄数量统计
smc.vmdata.mission_data.hero_num++
} }
/** 重置入口:复用 destroy 的释放流程 */ /** 重置入口:复用 destroy 的释放流程 */
@@ -197,10 +195,6 @@ export class BattleEntityLifecycleSystem extends ecs.ComblockSystem
if (heroAttrs) { if (heroAttrs) {
mLogger.log(heroAttrs.debugMode, 'BattleEntityLifecycle', `${label}离开世界: ${heroAttrs.hero_name}`); mLogger.log(heroAttrs.debugMode, 'BattleEntityLifecycle', `${label}离开世界: ${heroAttrs.hero_name}`);
if (heroAttrs.fac === FacSet.HERO) { if (heroAttrs.fac === FacSet.HERO) {
const missionData = smc.vmdata?.mission_data;
if (missionData) {
missionData.hero_num = Math.max(0, (missionData.hero_num ?? 0) - 1);
}
oops.message.dispatchEvent(GameEvent.HeroDead, { oops.message.dispatchEvent(GameEvent.HeroDead, {
eid: e.eid, eid: e.eid,
model: heroAttrs model: heroAttrs

View File

@@ -8,6 +8,7 @@ import { CardComp } from "./CardComp";
import { oops } from "db://oops-framework/core/Oops"; import { oops } from "db://oops-framework/core/Oops";
import { HeroAttrsComp } from "../hero/HeroAttrsComp"; import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { HInfoComp } from "./HInfoComp"; import { HInfoComp } from "./HInfoComp";
import { smc } from "../common/SingletonModuleComp";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -50,14 +51,8 @@ export class MissionCardComp extends CCComp {
private cardComps: CardComp[] = []; private cardComps: CardComp[] = [];
/** 当前卡池等级(仅影响抽卡来源,不直接改卡槽现有内容) */ /** 当前卡池等级(仅影响抽卡来源,不直接改卡槽现有内容) */
private poolLv: number = CARD_POOL_INIT_LEVEL; private poolLv: number = CARD_POOL_INIT_LEVEL;
private coin: number = CardInitCoins;
private readonly heroInfoItemGap: number = 86; private readonly heroInfoItemGap: number = 86;
private heroInfoSyncTimer: number = 0; private heroInfoSyncTimer: number = 0;
private readonly heroDefaultMaxCount: number = 5;
private readonly heroExtendMaxCount: number = 6;
private heroMaxCount: number = this.heroDefaultMaxCount;
private heroCurrentCount: number = 0;
private heroNumLabel: Label | null = null;
private heroInfoItems: Map<number, { private heroInfoItems: Map<number, {
node: Node, node: Node,
model: HeroAttrsComp, model: HeroAttrsComp,
@@ -86,9 +81,13 @@ export class MissionCardComp extends CCComp {
/** 任务开始时重置卡池等级、清空4槽、显示面板 刷新一次卡池*/ /** 任务开始时重置卡池等级、清空4槽、显示面板 刷新一次卡池*/
onMissionStart() { onMissionStart() {
this.poolLv = CARD_POOL_INIT_LEVEL; this.poolLv = CARD_POOL_INIT_LEVEL;
this.coin = CardInitCoins const missionData = this.getMissionData();
this.heroMaxCount = this.heroDefaultMaxCount; if (missionData) {
this.heroCurrentCount = 0; missionData.coin = CardInitCoins;
missionData.hero_num = 0;
missionData.hero_max_num = 5;
missionData.hero_extend_max_num = 6;
}
this.clearHeroInfoPanels(); this.clearHeroInfoPanels();
this.layoutCardSlots(); this.layoutCardSlots();
this.clearAllCards(); this.clearAllCards();
@@ -98,7 +97,6 @@ export class MissionCardComp extends CCComp {
this.resetButtonScale(this.cards_chou); this.resetButtonScale(this.cards_chou);
this.resetButtonScale(this.cards_up); this.resetButtonScale(this.cards_up);
this.updatePoolLvUI(); this.updatePoolLvUI();
this.updateCoinUI();
this.updateHeroNumUI(false, false); this.updateHeroNumUI(false, false);
this.node.active = true; this.node.active = true;
const cards = this.buildDrawCards(); const cards = this.buildDrawCards();
@@ -151,9 +149,10 @@ export class MissionCardComp extends CCComp {
} }
private onCoinAdd(args:any){ private onCoinAdd(args:any){
const v = typeof args === 'number' ? args : (args?.delta ?? args?.value ?? 0); const v = typeof args === 'number' ? args : (args?.delta ?? args?.value ?? 0);
this.coin = Math.max(0, (this.coin ?? 0) + v); if (v === 0) return;
this.setMissionCoin(this.getMissionCoin() + v);
this.updatePoolLvUI(); this.updatePoolLvUI();
this.updateCoinUI(); this.playCoinChangeAnim(v > 0);
} }
/** 解除按钮监听,避免节点销毁后回调泄漏 */ /** 解除按钮监听,避免节点销毁后回调泄漏 */
@@ -174,9 +173,10 @@ export class MissionCardComp extends CCComp {
const eid = Number(payload?.eid ?? 0); const eid = Number(payload?.eid ?? 0);
const model = payload?.model as HeroAttrsComp | undefined; const model = payload?.model as HeroAttrsComp | undefined;
if (!eid || !model) return; if (!eid || !model) return;
const before = this.heroCurrentCount; const before = this.getAliveHeroCount();
this.ensureHeroInfoPanel(eid, model); this.ensureHeroInfoPanel(eid, model);
this.updateHeroNumUI(true, this.heroCurrentCount > before); const after = this.getAliveHeroCount();
this.updateHeroNumUI(true, after > before);
} }
private onHeroDead() { private onHeroDead() {
@@ -188,11 +188,12 @@ export class MissionCardComp extends CCComp {
const payload = args ?? event; const payload = args ?? event;
if (!payload) return; if (!payload) return;
const current = this.getAliveHeroCount(); const current = this.getAliveHeroCount();
this.heroCurrentCount = current; this.syncMissionHeroData(current);
if (current >= this.heroMaxCount) { const heroMax = this.getMissionHeroMaxNum();
if (current >= heroMax) {
payload.cancel = true; payload.cancel = true;
payload.reason = "hero_limit"; payload.reason = "hero_limit";
oops.gui.toast(`英雄已满 (${current}/${this.heroMaxCount})`); oops.gui.toast(`英雄已满 (${current}/${heroMax})`);
this.playHeroNumDeniedAnim(); this.playHeroNumDeniedAnim();
} }
} }
@@ -246,7 +247,7 @@ export class MissionCardComp extends CCComp {
return; return;
} }
const cost = this.getUpgradeCost(this.poolLv); const cost = this.getUpgradeCost(this.poolLv);
const currentCoin = this.coin ?? 0; const currentCoin = this.getMissionCoin();
if (currentCoin < cost) { if (currentCoin < cost) {
oops.gui.toast(`金币不足,升级需要${cost}`); oops.gui.toast(`金币不足,升级需要${cost}`);
this.updatePoolLvUI(); this.updatePoolLvUI();
@@ -257,14 +258,14 @@ export class MissionCardComp extends CCComp {
}); });
return; return;
} }
this.coin = currentCoin - cost; this.setMissionCoin(currentCoin - cost);
this.poolLv += 1; this.poolLv += 1;
this.updateCoinUI(); this.playCoinChangeAnim(false);
this.updatePoolLvUI(); this.updatePoolLvUI();
mLogger.log(this.debugMode, "MissionCardComp", "pool level up", { mLogger.log(this.debugMode, "MissionCardComp", "pool level up", {
poolLv: this.poolLv, poolLv: this.poolLv,
cost, cost,
leftCoin: this.coin leftCoin: this.getMissionCoin()
}); });
} }
@@ -359,7 +360,7 @@ export class MissionCardComp extends CCComp {
} }
private canUpPool() { private canUpPool() {
if (this.poolLv >= CARD_POOL_MAX_LEVEL) return false; if (this.poolLv >= CARD_POOL_MAX_LEVEL) return false;
const currentCoin = this.coin ?? 0; const currentCoin = this.getMissionCoin();
return currentCoin >= this.getUpgradeCost(this.poolLv); return currentCoin >= this.getUpgradeCost(this.poolLv);
} }
/** 更新升级按钮上的等级文案,反馈当前卡池层级 */ /** 更新升级按钮上的等级文案,反馈当前卡池层级 */
@@ -388,11 +389,17 @@ export class MissionCardComp extends CCComp {
}); });
} }
private updateCoinUI() { private playCoinChangeAnim(isIncrease: boolean) {
if (!this.coins_node) return; if (!this.coins_node || !this.coins_node.isValid) return;
const label = this.coins_node.getChildByName("num")?.getComponent(Label); const target = this.coins_node.getChildByName("num") || this.coins_node;
if (!label) return; if (!target || !target.isValid) return;
label.string = `${this.coin ?? 0}`; const peak = isIncrease ? 1.16 : 1.08;
Tween.stopAllByTarget(target);
target.setScale(1, 1, 1);
tween(target)
.to(0.08, { scale: new Vec3(peak, peak, 1) })
.to(0.1, { scale: new Vec3(1, 1, 1) })
.start();
} }
private getUpgradeCost(lv: number): number { private getUpgradeCost(lv: number): number {
@@ -488,26 +495,32 @@ export class MissionCardComp extends CCComp {
} }
} }
this.heroInfoSyncTimer = 0; this.heroInfoSyncTimer = 0;
this.heroCurrentCount = 0; this.syncMissionHeroData(0);
this.updateHeroNumUI(false, false); this.updateHeroNumUI(false, false);
} }
public setHeroMaxCount(max: number) { public setHeroMaxCount(max: number) {
const next = Math.max(this.heroDefaultMaxCount, Math.min(this.heroExtendMaxCount, Math.floor(max || this.heroDefaultMaxCount))); const missionData = this.getMissionData();
if (next === this.heroMaxCount) return; if (!missionData) return;
this.heroMaxCount = next; const min = 5;
const limit = Math.max(min, missionData.hero_extend_max_num ?? 6);
const next = Math.max(min, Math.min(limit, Math.floor(max || min)));
if (next === missionData.hero_max_num) return;
missionData.hero_max_num = next;
this.updateHeroNumUI(true, false); this.updateHeroNumUI(true, false);
} }
public tryExpandHeroMax(add: number = 1): boolean { public tryExpandHeroMax(add: number = 1): boolean {
const next = this.heroMaxCount + Math.max(0, Math.floor(add)); const missionData = this.getMissionData();
const before = this.heroMaxCount; if (!missionData) return false;
const before = this.getMissionHeroMaxNum();
const next = before + Math.max(0, Math.floor(add));
this.setHeroMaxCount(next); this.setHeroMaxCount(next);
return this.heroMaxCount > before; return this.getMissionHeroMaxNum() > before;
} }
public canUseHeroCard(): boolean { public canUseHeroCard(): boolean {
return this.getAliveHeroCount() < this.heroMaxCount; return this.getAliveHeroCount() < this.getMissionHeroMaxNum();
} }
private getAliveHeroCount(): number { private getAliveHeroCount(): number {
@@ -522,15 +535,7 @@ export class MissionCardComp extends CCComp {
} }
private updateHeroNumUI(animate: boolean, isIncrease: boolean) { private updateHeroNumUI(animate: boolean, isIncrease: boolean) {
this.heroCurrentCount = this.getAliveHeroCount(); this.syncMissionHeroData();
if (!this.hero_num_node || !this.hero_num_node.isValid) return;
const numNode = this.hero_num_node.getChildByName("num");
if (!this.heroNumLabel) {
this.heroNumLabel = numNode?.getComponent(Label) || numNode?.getComponentInChildren(Label) || null;
}
if (this.heroNumLabel) {
this.heroNumLabel.string = `${this.heroCurrentCount}/${this.heroMaxCount}`;
}
if (!animate || !isIncrease) return; if (!animate || !isIncrease) return;
this.playHeroNumGainAnim(); this.playHeroNumGainAnim();
} }
@@ -561,6 +566,38 @@ export class MissionCardComp extends CCComp {
.start(); .start();
} }
private getMissionData(): any {
return smc?.vmdata?.mission_data ?? null;
}
private getMissionHeroNum(): number {
const missionData = this.getMissionData();
return Math.max(0, Math.floor(missionData?.hero_num ?? 0));
}
private getMissionCoin(): number {
const missionData = this.getMissionData();
return Math.max(0, Math.floor(missionData?.coin ?? 0));
}
private setMissionCoin(value: number) {
const missionData = this.getMissionData();
if (!missionData) return;
missionData.coin = Math.max(0, Math.floor(value));
}
private getMissionHeroMaxNum(): number {
const missionData = this.getMissionData();
return Math.max(5, Math.floor(missionData?.hero_max_num ?? 5));
}
private syncMissionHeroData(count?: number) {
const missionData = this.getMissionData();
if (!missionData) return;
const safeCount = Math.max(0, Math.floor(count ?? this.getAliveHeroCount()));
missionData.hero_num = safeCount;
}
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
reset() { reset() {
this.clearHeroInfoPanels(); this.clearHeroInfoPanels();