feat(战斗系统): 实现伤害队列机制优化战斗处理

重构伤害处理逻辑,将直接伤害组件改为队列系统
- 新增DamageQueueComp组件管理伤害事件队列
- 添加DamageQueueHelper工具类处理伤害事件添加和查询
- 修改HeroAtkSystem改为处理伤害队列而非单个伤害
- 移除旧的DmgDataCom组件及相关引用
- 优化SkillView.apply_damage使用新队列系统
This commit is contained in:
2025-10-31 20:08:43 +08:00
parent 8e0d09fc98
commit b8f48e09d6
7 changed files with 278 additions and 85 deletions

View File

@@ -3,9 +3,9 @@ import { FacSet } from "../common/config/BoxSet";
import { Attrs } from "../common/config/HeroAttrs";
import { FightSet } from "../common/config/Mission";
import { SkillSet } from "../common/config/SkillSet";
import { DmgDataCom } from "../skill/SDataCom";
import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp";
import { DamageQueueComp, DamageEvent, DamageQueueHelper } from "./DamageQueueComp";
/** 业务层对象 */
@ecs.register('HeroAtk')
@@ -15,72 +15,99 @@ export class HeroAtkComp extends ecs.Comp {
}
}
interface FDData{
damage:number,
isCrit:boolean,
isDodge:boolean,
/** 最终伤害数据接口 */
interface FinalData {
damage: number;
isCrit: boolean;
isDodge: boolean;
}
/** 业务层业务逻辑处理对象 伤害处理系统 */
@ecs.register('HeroAtkSystem')
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate, ecs.IEntityEnterSystem {
export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
private debugMode: boolean = false; // 是否启用调试模式
/**
* 过滤器:处理拥有伤害数据的实体
* 过滤器:处理拥有伤害队列的实体
*/
filter(): ecs.IMatcher {
return ecs.allOf(HeroAttrsComp, DmgDataCom);
return ecs.allOf(HeroAttrsComp, DamageQueueComp);
}
/**
* 实体首次进入系统时调用(每个实体只调用一次
* 系统更新(每帧调用
* 处理伤害队列中的所有伤害事件
*/
entityEnter(e: ecs.Entity): void {
update(e: ecs.Entity): void {
const model = e.get(HeroAttrsComp);
const dmgData = e.get(DmgDataCom);
if (!model || !dmgData) return;
const caster = dmgData.caster;
// 深度拷贝伤害数据,避免组件移除后数据丢失
const dmgDataCopy = this.deepCopyDmgData(dmgData);
// 立即移除组件,避免重复处理
e.remove(DmgDataCom);
const damageQueue = e.get(DamageQueueComp);
// 使用拷贝的数据进行伤害计算
let FDData = this.doAttack(e, dmgDataCopy);
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到 ${caster.ent.get(HeroAttrsComp).hero_name}(uuid: ${caster.ent.get(HeroAttrsComp).hero_uuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击技能ID ${dmgDataCopy.s_uuid}`);
if (!model || !damageQueue || damageQueue.isEmpty()) return;
// 标记正在处理
damageQueue.isProcessing = true;
// 处理队列中的所有伤害事件
let processedCount = 0;
while (!damageQueue.isEmpty()) {
const damageEvent = damageQueue.getNextDamageEvent();
if (!damageEvent) break;
// 处理单个伤害事件
const FDData = this.doAttack(e, damageEvent);
processedCount++;
damageQueue.processedCount++;
if (this.debugMode) {
const casterName = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_name || "未知";
const casterUuid = damageEvent.caster?.ent?.get(HeroAttrsComp)?.hero_uuid || 0;
console.log(`[HeroAtkSystem] 英雄${model.hero_name} (uuid: ${model.hero_uuid}) 受到 ${casterName}(uuid: ${casterUuid})的 伤害 ${FDData.damage},${FDData.isCrit?"暴击":"普通"}攻击技能ID ${damageEvent.s_uuid}`);
}
// 如果目标已死亡,停止处理后续伤害
if (model.is_dead) {
if (this.debugMode) {
console.log(`[HeroAtkSystem] ${model.hero_name} 已死亡,停止处理剩余伤害`);
}
damageQueue.clear(); // 清空剩余伤害
break;
}
}
// 如果队列已空,移除伤害队列组件
if (damageQueue.isEmpty()) {
e.remove(DamageQueueComp);
if (this.debugMode && processedCount > 0) {
console.log(`[HeroAtkSystem] ${model.hero_name} 伤害队列处理完成,共处理 ${processedCount} 个伤害事件`);
}
}
}
/**
* 深度拷贝伤害数据
* 执行攻击计算
* @param target 目标实体
* @param damageEvent 伤害事件数据
* @returns 最终伤害数据
*/
private deepCopyDmgData(dmgData: DmgDataCom): any {
return {
Attrs: dmgData.Attrs ? { ...dmgData.Attrs } : null,
s_uuid: dmgData.s_uuid
};
}
/**
* 处理角色被攻击
* @param target 被攻击的目标实体
* @param dmgData 伤害数据(可以是组件或拷贝的对象)
* @returns 实际造成的伤害
*/
public doAttack(target: ecs.Entity, dmgDataCopy: any): FDData {
private doAttack(target: ecs.Entity, damageEvent: DamageEvent): FinalData {
const targetModel = target.get(HeroAttrsComp);
const targetView = target.get(HeroViewComp);
let reDate:FDData={
let reDate:FinalData={
damage:0,
isCrit:false,
isDodge:false,
}
if (!targetModel || targetModel.is_dead) return reDate;
// 获取攻击者数据
const caster = damageEvent.caster;
const casterModel = caster.ent.get(HeroAttrsComp);
if (!casterModel) return reDate;
// 获取技能配置
const skillConf = SkillSet[dmgDataCopy.s_uuid];
const skillConf = SkillSet[damageEvent.s_uuid];
if (!skillConf) return reDate;
// 触发被攻击事件
@@ -95,7 +122,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// 暴击判定
const isCrit = this.checkCrit(targetModel.Attrs[Attrs.CRITICAL]);
let damage = this.dmgCount(dmgDataCopy.Attrs,dmgDataCopy.s_uuid);
let damage = this.dmgCount(damageEvent.Attrs,damageEvent.s_uuid);
if (isCrit) {
damage = Math.floor(damage * (1 + (FightSet.CRIT_DAMAGE + targetModel.Attrs[Attrs.CRITICAL_DMG]) / 100));
reDate.isCrit=true;
@@ -114,7 +141,7 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
// ✅ 触发视图层表现(伤害数字、受击动画、后退)
if (targetView) {
targetView.do_atked(damage, isCrit, dmgDataCopy.s_uuid);
targetView.do_atked(damage, isCrit, damageEvent.s_uuid);
}
// 检查死亡
@@ -273,12 +300,5 @@ export class HeroAtkSystem extends ecs.ComblockSystem implements ecs.ISystemUpd
this.debugMode = false;
}
/**
* 系统更新(每帧调用)
* 可以在这里添加需要每帧处理的战斗逻辑
*/
update(e: ecs.Entity): void {
// 这里可以添加需要每帧处理的战斗逻辑
// 例如:持续伤害、战斗状态检查等
}
}