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:{
mon_num:0,//怪物数量
hero_num:0,//英雄数量
hero_max_num:5,//英雄可召唤上限
hero_extend_max_num:6,//英雄可拓展上限
wave_time_num:0,//波次时间
in_fight:false,
fight_time:0,//战斗时间

View File

@@ -150,8 +150,6 @@ export class Hero extends ecs.Entity {
}
})
.start();
// 维护关卡内英雄数量统计
smc.vmdata.mission_data.hero_num++
}
/** 重置入口:复用 destroy 的释放流程 */
@@ -197,10 +195,6 @@ export class BattleEntityLifecycleSystem extends ecs.ComblockSystem
if (heroAttrs) {
mLogger.log(heroAttrs.debugMode, 'BattleEntityLifecycle', `${label}离开世界: ${heroAttrs.hero_name}`);
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, {
eid: e.eid,
model: heroAttrs

View File

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