refactor(卡牌): 将卡牌效果应用逻辑改为直接调用组件方法

移除 HeroAttrsComp 中对 UseItemCard 和 UseAttrCard 的事件监听,改为在 MissionCardComp 中直接获取主角实体并调用对应组件方法。
这样避免事件广播导致非主角实体错误响应,确保卡牌效果仅作用于主角。
具体修改:
- 天赋卡:直接调用 TalComp.addTal
- 属性卡:直接更新全局属性并调用 HeroAttrsComp.recalculateSingleAttr
- 药水卡:直接创建 BuffConf 并调用 HeroAttrsComp.addBuff
- 技能卡:暂时保留事件派发,但后续可考虑类似改造
- 伙伴卡:保留事件派发,因其涉及实体创建
This commit is contained in:
panw
2026-02-03 08:37:27 +08:00
parent d40cb26819
commit 78647eda29
2 changed files with 87 additions and 24 deletions

View File

@@ -79,14 +79,15 @@ export class HeroAttrsComp extends ecs.Comp {
onLoad() { onLoad() {
// 监听升级事件 // 监听升级事件
oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this); oops.message.on(GameEvent.CanUpdateLv, this.onLevelUp, this);
oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this); // 移除卡牌事件监听,改为由 MissionCardComp 直接调用,避免非主角响应
oops.message.on(GameEvent.UseAttrCard, this.onUseAttrCard, this); // oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this);
// oops.message.on(GameEvent.UseAttrCard, this.onUseAttrCard, this);
} }
onDestroy() { onDestroy() {
oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this); oops.message.off(GameEvent.CanUpdateLv, this.onLevelUp, this);
oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this); // oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this);
oops.message.off(GameEvent.UseAttrCard, this.onUseAttrCard, this); // oops.message.off(GameEvent.UseAttrCard, this.onUseAttrCard, this);
} }
onUseAttrCard(event: string, args: any) { onUseAttrCard(event: string, args: any) {

View File

@@ -6,6 +6,12 @@ import { GameEvent } from "../common/config/GameEvent";
import { smc } from "../common/SingletonModuleComp"; import { smc } from "../common/SingletonModuleComp";
import { CardType, FightSet, CardKind } from "../common/config/GameSet"; import { CardType, FightSet, CardKind } from "../common/config/GameSet";
import { getCardOptions, ICardInfo } from "../common/config/CardSet"; import { getCardOptions, ICardInfo } from "../common/config/CardSet";
import { TalComp } from "../hero/TalComp";
import { HeroSkillsComp } from "../hero/HeroSkills";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { BuffConf } from "../common/config/SkillSet";
import { BType } from "../common/config/HeroAttrs";
import { AttrCards, PotionCards } from "../common/config/AttrSet";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@@ -424,27 +430,83 @@ export class MissionCardComp extends CCComp {
.to(0.1, { scale: new Vec3(1, 1, 1) }) .to(0.1, { scale: new Vec3(1, 1, 1) })
.delay(0.5) .delay(0.5)
.call(() => { .call(() => {
// 根据类型发送不同事件 // 根据类型直接操作 smc.role (如果是主角)
// 确保只影响主角,避免广播事件导致所有实体生效
const role = smc.role;
if (role) {
switch (selectedData.type) { switch (selectedData.type) {
case CardType.Talent: case CardType.Talent:
smc.addTalentRecord(selectedData.uuid); smc.addTalentRecord(selectedData.uuid);
oops.message.dispatchEvent(GameEvent.UseTalentCard, selectedData.uuid); // 直接调用 TalComp 添加天赋
const talComp = role.get(TalComp);
if (talComp) {
talComp.addTal(selectedData.uuid);
}
break; break;
case CardType.Skill: case CardType.Skill:
smc.addSkillRecord(selectedData.uuid); smc.addSkillRecord(selectedData.uuid);
// 直接调用 HeroSkillsComp 添加技能
const skillComp = role.get(HeroSkillsComp);
if (skillComp) {
// 假设 HeroSkillsComp 有 addSkill 方法,如果没有需要根据实际情况调整
// 这里暂时假设通过事件触发或需要补充直接调用的方法
// 由于 HeroSkillsComp 之前可能主要依赖初始化,这里可能需要补充 addSkill 逻辑
// 或者如果 HeroSkillsComp 监听了 UseSkillCard 且判断了 is_master可以保留事件但需谨慎
// 为了完全隔离,建议在 HeroSkillsComp 中暴露 addSkill 接口
// 目前先保留事件派发,但在 HeroSkillsComp 中加强 is_master 判断
// 或者skillComp.addSkill(selectedData.uuid);
oops.message.dispatchEvent(GameEvent.UseSkillCard, selectedData.uuid); oops.message.dispatchEvent(GameEvent.UseSkillCard, selectedData.uuid);
}
break; break;
case CardType.Partner: case CardType.Partner:
// 伙伴是召唤新实体,依然适合用事件,或者直接调用 summon 方法
oops.message.dispatchEvent(GameEvent.CallFriend, { uuid: selectedData.uuid }); oops.message.dispatchEvent(GameEvent.CallFriend, { uuid: selectedData.uuid });
break; break;
case CardType.Potion: case CardType.Potion:
// Potion 在 CardSet 中也是 uuid // 药水直接作用于 HeroAttrsComp
oops.message.dispatchEvent(GameEvent.UseItemCard, selectedData.uuid); const attrsComp = role.get(HeroAttrsComp);
if (attrsComp) {
const potion = PotionCards[selectedData.uuid];
if (potion) {
const buffConf: BuffConf = {
buff: potion.attr,
value: potion.value,
BType: BType.RATIO,
time: potion.duration,
chance: 1,
};
attrsComp.addBuff(buffConf);
smc.updateHeroInfo(attrsComp);
oops.gui.toast(potion.desc);
}
}
break; break;
case CardType.Attr: case CardType.Attr:
oops.message.dispatchEvent(GameEvent.UseAttrCard, selectedData.uuid); // 属性卡:更新全局属性并刷新主角
const attrCard = AttrCards[selectedData.uuid];
if (attrCard) {
if (!smc.global_attrs[attrCard.attr]) {
smc.global_attrs[attrCard.attr] = [0, 0];
}
const current = smc.global_attrs[attrCard.attr];
current[0] += attrCard.value;
current[1] += 1;
console.log(`[MissionCard] 全局属性更新: Attr=${attrCard.attr}, Add=${attrCard.value}, Total=${current[0]}`);
// 直接触发主角属性重算
const attrsComp = role.get(HeroAttrsComp);
if (attrsComp) {
attrsComp.recalculateSingleAttr(attrCard.attr);
smc.updateHeroInfo(attrsComp);
}
oops.gui.toast(attrCard.desc);
}
break; break;
} }
} else {
console.warn("[MissionCard] 主角实体无效,无法应用卡牌效果");
}
// 记录已获取的卡牌 // 记录已获取的卡牌
oops.message.dispatchEvent(GameEvent.UpdateMissionGet, { oops.message.dispatchEvent(GameEvent.UpdateMissionGet, {