refactor(hero): 重构英雄属性与状态管理

- 将增益效果属性组移到武器进化属性后以优化结构
- 新增 in_stun 和 in_frost 状态标志替代 isStun/isFrost 方法
- 更新状态检查逻辑以使用新的状态标志
- 移除 HeroSkillsComp 依赖以简化移动系统
- 修改伤害计算直接使用 HeroAttrsComp 属性而非 Attrs 映射
- 简化暴击、击退等判定逻辑,移除闪避和抗性计算
- 优化 reset 方法,设置合理的默认值并重置新增状态标志
- 添加状态变化时的调试日志输出
This commit is contained in:
walkpan
2026-03-11 22:51:48 +08:00
parent 48769e699e
commit 9d6075be6e
4 changed files with 53 additions and 58 deletions

View File

@@ -7,7 +7,6 @@ import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp";
import { DamageQueueComp, DamageEvent } from "./DamageQueueComp";
import { smc } from "../common/SingletonModuleComp";
import { TalAttrs } from "../common/config/TalSet";
import { oops } from "db://oops-framework/core/Oops";
import { GameEvent } from "../common/config/GameEvent";
@@ -141,19 +140,9 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 触发被攻击事件
this.onAttacked(target);
// 闪避判定
// 闪避成功概率 = 被攻击者闪避率 - 施法者命中率
// TAttrsComp.Attrs[Attrs.DODGE]: 被攻击者的实时闪避属性
// damageEvent.Attrs[Attrs.HIT]: 施法者在技能创建时的命中属性快照
const isDodge =this.checkChance((TAttrsComp.Attrs[Attrs.DODGE]-damageEvent.Attrs[Attrs.HIT]) || 0);
if (isDodge) {
// TODO: 触发闪避视图表现
reDate.isDodge=true;
return reDate;
}
// 暴击判定
// 使用施法者的暴击率属性damageEvent.Attrs 快照),- 被攻击者的暴击抗性属性TAttrsComp.Attrs[Attrs.CRITICAL_RES]
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]-TAttrsComp.Attrs[Attrs.CRITICAL_RES]);
// 使用施法者的暴击率属性damageEvent.Attrs 快照),- 被攻击者的暴击抗性属
const isCrit = this.checkChance(damageEvent.Attrs[Attrs.CRITICAL]);
// 计算基础伤害
let damage = this.dmgCount(damageEvent,TAttrsComp);
@@ -165,7 +154,6 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
const casterCritDmg = damageEvent.Attrs[Attrs.CRITICAL_DMG] || 0;
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + casterCritDmg) / 100));
reDate.isCrit=true;
CAttrsComp?.useValueTalByAttr(Attrs.CRITICAL); // 清除施法者的暴击buff
}
mLogger.log(this.debugMode, 'HeroAtkSystem', " after crit",damage)
@@ -187,8 +175,6 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// targetView.back();
// }
smc.updateHeroInfo(TAttrsComp); // 更新英雄数据到 VM
const casterName = CAttrsComp?.hero_name || "未知";
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 英雄${TAttrsComp.hero_name} (uuid: ${TAttrsComp.hero_uuid}) 受到 ${casterName}(eid: ${casterEid})的 伤害 ${damage},${isCrit?"暴击":"普通"}攻击,技能ID ${damageEvent.s_uuid}`);
@@ -197,8 +183,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 击退判定
// 使用施法者的击退概率属性damageEvent.Attrs 快照) - 被攻击者的控制抗性
// 击退成功后需要清理施法者的相关天赋buff
const isBack = this.checkChance((damageEvent.Attrs[Attrs.BACK_CHANCE] || 0) - (TAttrsComp.Attrs[Attrs.CON_RES] || 0));
if (isBack) CAttrsComp?.useValueTalByAttr(Attrs.BACK_CHANCE);
const isBack = this.checkChance((damageEvent.Attrs[Attrs.BACK_CHANCE] || 0));
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
@@ -208,8 +193,8 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 检查死亡
if (TAttrsComp.hp <= 0) {
// 复活机制:如果玩家属性内的复活属性值>=1 则执行复活,原地50%血量复活
if (TAttrsComp.is_master && TAttrsComp.Attrs[Attrs.REVIVE_COUNT] >= 1) {
TAttrsComp.Attrs[Attrs.REVIVE_COUNT]--;
if (TAttrsComp.is_master && TAttrsComp.revive_count >= 1) {
TAttrsComp.revive_count--;
TAttrsComp.is_reviving = true; // 标记为正在复活
// 停止怪物行动
@@ -222,18 +207,18 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
targetView.scheduleRevive(1.0);
}
mLogger.log(this.debugMode, 'HeroAtkSystem', ` Hero waiting to revive! Lives left: ${TAttrsComp.Attrs[Attrs.REVIVE_COUNT]}`);
mLogger.log(this.debugMode, 'HeroAtkSystem', ` Hero waiting to revive! Lives left: ${TAttrsComp.revive_count}`);
return reDate;
}
// 增加被击杀计数
if (caster) CAttrsComp.Attrs.killed_count++;
if (caster) CAttrsComp.killed_count++;
// 玩家英雄死亡后,怪物停止刷新和移动
if (TAttrsComp.is_master&&TAttrsComp.Attrs[Attrs.REVIVE_COUNT] <= 0) {
if (TAttrsComp.is_master&&TAttrsComp.revive_count <= 0) {
smc.mission.stop_mon_action = true;
oops.message.dispatchEvent(GameEvent.HeroDead, { hero_uuid: TAttrsComp.hero_uuid});
mLogger.log(this.debugMode, 'HeroAtkSystem', " Hero died, stopping monster action (spawn/move)"+TAttrsComp.Attrs[Attrs.REVIVE_COUNT]);
mLogger.log(this.debugMode, 'HeroAtkSystem', " Hero died, stopping monster action (spawn/move)"+TAttrsComp.revive_count);
}
this.doDead(target);
@@ -268,8 +253,8 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 检查死亡
if (CAttrs.hp <= 0) {
// 复活机制
if (CAttrs.is_master && CAttrs.Attrs[Attrs.REVIVE_COUNT] >= 1) {
CAttrs.Attrs[Attrs.REVIVE_COUNT]--;
if (CAttrs.is_master && CAttrs.revive_count >= 1) {
CAttrs.revive_count--;
CAttrs.is_reviving = true;
smc.mission.stop_mon_action = true;
@@ -279,12 +264,12 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
CView.scheduleRevive(1.0);
}
mLogger.log(this.debugMode, 'HeroAtkSystem', ` Hero waiting to revive from Thorns! Lives left: ${CAttrs.Attrs[Attrs.REVIVE_COUNT]}`);
mLogger.log(this.debugMode, 'HeroAtkSystem', ` Hero waiting to revive from Thorns! Lives left: ${CAttrs.revive_count}`);
return;
}
// 玩家英雄死亡后,怪物停止刷新和移动
if (CAttrs.is_master&&CAttrs.Attrs[Attrs.REVIVE_COUNT] <= 0) {
if (CAttrs.is_master&&CAttrs.revive_count <= 0) {
smc.mission.stop_mon_action = true;
oops.message.dispatchEvent(GameEvent.HeroDead, { hero_uuid: CAttrs.hero_uuid});
mLogger.log(this.debugMode, 'HeroAtkSystem', " Hero died from thorns, stopping monster action (spawn/move)");
@@ -292,7 +277,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.doDead(caster);
// 增加击杀计数
if (caster) TAttrsComp.Attrs.killed_count++;
if (caster) TAttrsComp.killed_count++;
// ✅ 触发死亡视图表现
if (CView) {
CView.do_dead();
@@ -320,7 +305,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
private dmgCount(damageEvent:DamageEvent,TAttrsComp:HeroAttrsComp){
// 1. 获取技能配置 - 如果技能不存在直接返回0伤害
const CAttrs=damageEvent.Attrs;
const TAttrs=TAttrsComp.Attrs;
const TAttrs=TAttrsComp;
let sConf = SkillSet[damageEvent.s_uuid];
if (!sConf) return 0;
mLogger.log(this.debugMode, 'HeroAtkSystem', ` 伤害处理对象`,CAttrs,TAttrs);

View File

@@ -49,17 +49,19 @@ export class HeroAttrsComp extends ecs.Comp {
back_chance: number = 0; // 击退概率
slow_chance: number = 0; // 减速概率
// ==================== 增益效果属性 ====================
revive_count: number = 0; // 复活次数
revive_time: number = 0; // 复活时间
invincible_time: number = 0;// 无敌时间
// ==================== 武器进化相关 ====================
puncture: number = 0; // 穿刺次数
puncture_dmg: number = 0; // 穿刺伤害
wfuny: number = 0; // 风怒
// ==================== 增益效果属性 ====================
revive_count: number = 0; // 复活次数
revive_time: number = 0; // 复活时间
invincible_time: number = 0;// 无敌时间
in_stun=false
in_frost=false
boom: boolean = false; // 自爆怪
@@ -303,9 +305,8 @@ export class HeroAttrsComp extends ecs.Comp {
private updateStatusFlags() {
// 检查特定状态的 Debuff 列表是否为空,来更新 boolean 标志
// 例如:冰冻
this.checkStatus(Attrs.IN_FROST, 'is_stop'); // 假设冰冻会停止行动
// this.checkStatus(Attrs.IN_STUN, 'is_stunned'); // 需要在类里定义 is_stunned
this.checkStatus(Attrs.IN_FROST, 'in_frost');
this.checkStatus(Attrs.IN_STUN, 'in_stun');
}
private checkStatus(attr: Attrs, flagName: string) {
@@ -314,9 +315,11 @@ export class HeroAttrsComp extends ecs.Comp {
// 只有当状态改变时才赋值,避免每帧赋值
if (this[flagName] !== hasBuff) {
// 特殊处理:有些状态可能由其他逻辑控制,这里强行覆盖可能会冲突
// 但作为 Buff 系统,它应该拥有最高解释权之一
this[flagName] = hasBuff;
// 状态变化日志
if (this.debugMode) {
mLogger.log(this.debugMode, 'HeroAttrs', `状态变更: ${this.hero_name}, ${flagName} = ${hasBuff}`);
}
}
}
@@ -363,11 +366,12 @@ export class HeroAttrsComp extends ecs.Comp {
this.lv = 1;
this.type = 0;
this.fac = 0;
this.rangeType = SkillRange.Melee;
this.ap = 0;
this.hp = 100;
this.hp_max = 100;
this.speed = 100;
this.dis = 0;
this.hp = 100;
this.dis = 100;
this.shield = 0;
this.shield_max = 0;
@@ -389,12 +393,16 @@ export class HeroAttrsComp extends ecs.Comp {
this.puncture_dmg = 0;
this.wfuny = 0;
this.boom = false;
this.in_frost = false;
this.in_stun = false;
this.BUFFS = {};
this.DEBUFFS = {};
// 重置技能距离缓存
this.maxSkillDistance = 0;
this.minSkillDistance = 0;
this.is_dead = false;
this.is_count_dead = false;
this.is_atking = false;
@@ -405,9 +413,13 @@ export class HeroAttrsComp extends ecs.Comp {
this.is_friend = false;
this.is_kalami = false;
this.is_reviving = false;
this.atk_count = 0;
this.atked_count = 0;
this.killed_count =0;
this.atk_id = 0;
this.skill_id = 0;
// 重置脏标签
this.dirty_hp = false;
this.dirty_shield = false;

View File

@@ -1,7 +1,6 @@
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroViewComp } from "./HeroViewComp";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroSkillsComp } from "./HeroSkills";
import { smc } from "../common/SingletonModuleComp";
import { FacSet } from "../common/config/GameSet";
import { HType } from "../common/config/heroSet";
@@ -29,7 +28,7 @@ export class HeroMoveComp extends ecs.Comp {
@ecs.register('HeroMoveSystem')
export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
filter(): ecs.IMatcher {
return ecs.allOf(HeroMoveComp, HeroViewComp, HeroAttrsComp, HeroSkillsComp);
return ecs.allOf(HeroMoveComp, HeroViewComp, HeroAttrsComp);
}
update(e: ecs.Entity) {
@@ -47,7 +46,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
if (!move.moving) return;
// 2. 异常状态检查 (死亡/复活/眩晕/冰冻)
if (model.is_stop || model.is_dead || model.is_reviving || model.isStun() || model.isFrost()) {
if (model.is_stop || model.is_dead || model.is_reviving || model.in_stun || model.in_frost) {
if (!model.is_reviving) view.status_change("idle");
return;
}
@@ -119,7 +118,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
view.status_change("idle");
model.is_atking = true;
} else {
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
this.moveEntity(view, move.direction, speed);
model.is_atking = false;
}
@@ -145,7 +144,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.performRetreat(view, move, model, currentX);
} else if (dist > maxRange) {
// 太远了,追击
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
this.moveEntity(view, move.direction, speed);
model.is_atking = false;
} else {
@@ -175,7 +174,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.performRetreat(view, move, model, currentX);
} else if (dist > maxRange) {
// 太远了,追击
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
this.moveEntity(view, move.direction, speed);
model.is_atking = false;
} else {
@@ -189,7 +188,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
private performRetreat(view: HeroViewComp, move: HeroMoveComp, model: HeroAttrsComp, currentX: number) {
const safeRetreatX = currentX - move.direction * 50;
if (safeRetreatX >= -300 && safeRetreatX <= 300) {
const retreatSpeed = (model.Attrs[Attrs.SPEED] / 3) * 0.8;
const retreatSpeed = (model.speed / 3) * 0.8;
this.moveEntity(view, -move.direction, retreatSpeed);
model.is_atking = false;
} else {
@@ -214,7 +213,7 @@ export class HeroMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
if (Math.abs(currentX - targetX) > 5) {
const dir = targetX > currentX ? 1 : -1;
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
// 修正朝向:回正
move.direction = 1;

View File

@@ -1,7 +1,6 @@
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroViewComp } from "./HeroViewComp";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroSkillsComp } from "./HeroSkills";
import { smc } from "../common/SingletonModuleComp";
import { FacSet, IndexSet } from "../common/config/GameSet";
import { Attrs } from "../common/config/HeroAttrs";
@@ -38,7 +37,7 @@ export class MonMoveComp extends ecs.Comp {
@ecs.register('MonMoveSystem')
export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
filter(): ecs.IMatcher {
return ecs.allOf(MonMoveComp, HeroViewComp, HeroAttrsComp, HeroSkillsComp);
return ecs.allOf(MonMoveComp, HeroViewComp, HeroAttrsComp);
}
update(e: ecs.Entity) {
@@ -61,7 +60,7 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
if (!move.moving) return;
// 2. 异常状态检查 (死亡/复活/眩晕/冰冻)
if (model.is_stop || model.is_dead || model.isStun() || model.isFrost()) {
if (model.is_stop || model.is_dead || model.in_stun|| model.in_frost) {
view.status_change("idle");
return;
}
@@ -136,7 +135,7 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
view.status_change("idle");
model.is_atking = true;
} else {
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
this.moveEntity(view, move.direction, speed);
model.is_atking = false;
}
@@ -162,7 +161,7 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
this.performRetreat(view, move, model, currentX);
} else if (dist > maxRange) {
// 太远了,追击
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
this.moveEntity(view, move.direction, speed);
model.is_atking = false;
} else {
@@ -192,7 +191,7 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
this.performRetreat(view, move, model, currentX);
} else if (dist > maxRange) {
// 太远了,追击
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
this.moveEntity(view, move.direction, speed);
model.is_atking = false;
} else {
@@ -207,7 +206,7 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
const safeRetreatX = currentX - move.direction * 50;
// 怪物活动范围通常宽一些
if (safeRetreatX >= -450 && safeRetreatX <= 450) {
const retreatSpeed = (model.Attrs[Attrs.SPEED] / 3) * 0.8;
const retreatSpeed = (model.speed / 3) * 0.8;
this.moveEntity(view, -move.direction, retreatSpeed);
model.is_atking = false;
} else {
@@ -227,7 +226,7 @@ export class MonMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpda
if (Math.abs(currentX - targetX) > 5) {
const dir = targetX > currentX ? 1 : -1;
const speed = model.Attrs[Attrs.SPEED] / 3;
const speed = model.speed / 3;
// 修正朝向
move.direction = dir;