Files
pixelheros/assets/script/game/hero/DamageQueueComp.ts
walkpan 974a6d26b2 refactor(伤害系统): 将caster从HeroViewComp改为使用casterEid
统一伤害系统中施法者的标识方式,从直接使用HeroViewComp改为使用实体ID(casterEid)
修复反伤逻辑中可能存在的空指针问题
2026-01-06 14:28:48 +08:00

190 lines
5.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { HeroViewComp } from "./HeroViewComp";
/**
* ==================== 伤害事件数据 ====================
*
* 单个伤害事件的数据结构
*/
export interface DamageEvent {
/** 伤害属性数据 */
Attrs: any;
/** 施法者ID */
casterEid: number;
/** 技能UUID */
s_uuid: number;
/** 伤害创建时间戳(用于排序和调试) */
timestamp: number;
/** 伤害事件ID用于去重和调试 */
eventId: string;
ext_dmg:number //额外伤害
dmg_ratio:number//伤害比例
}
/**
* ==================== 伤害队列组件 ====================
*
* 用途:
* - 存储一个实体在当前帧收到的所有伤害事件
* - 支持批量处理,避免同帧多伤害冲突
* - 提供伤害事件的排序和去重功能
*/
@ecs.register('DamageQueue')
export class DamageQueueComp extends ecs.Comp {
/** 伤害事件队列 */
damageEvents: DamageEvent[] = [];
/** 队列创建时间 */
createTime: number = 0;
/** 是否正在处理中 */
isProcessing: boolean = false;
/** 已处理的伤害数量 */
processedCount: number = 0;
reset() {
this.damageEvents = [];
this.createTime = 0;
this.isProcessing = false;
this.processedCount = 0;
}
/**
* 添加伤害事件到队列
*/
addDamageEvent(attrs: any, casterEid: number, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
const timestamp = Date.now();
const eventId = `${casterEid}_${s_uuid}_${timestamp}_${Math.random()}`;
const damageEvent: DamageEvent = {
Attrs: attrs ? { ...attrs } : null, // 深拷贝属性数据
casterEid: casterEid,
s_uuid: s_uuid,
timestamp: timestamp,
eventId: eventId,
ext_dmg:ext_dmg,
dmg_ratio:dmg_ratio,
};
this.damageEvents.push(damageEvent);
// 如果是第一个伤害事件,记录创建时间
if (this.damageEvents.length === 1) {
this.createTime = timestamp;
}
}
/**
* 获取下一个待处理的伤害事件
*/
getNextDamageEvent(): DamageEvent | null {
if (this.damageEvents.length === 0) return null;
return this.damageEvents.shift() || null;
}
/**
* 获取队列中剩余的伤害事件数量
*/
getRemainingCount(): number {
return this.damageEvents.length;
}
/**
* 检查队列是否为空
*/
isEmpty(): boolean {
return this.damageEvents.length === 0;
}
/**
* 清空队列
*/
clear(): void {
this.damageEvents = [];
this.processedCount = 0;
this.isProcessing = false;
}
/**
* 按时间戳排序伤害事件(可选功能)
*/
sortByTimestamp(): void {
this.damageEvents.sort((a, b) => a.timestamp - b.timestamp);
}
/**
* 去除重复的伤害事件基于eventId
*/
removeDuplicates(): void {
const seen = new Set<string>();
this.damageEvents = this.damageEvents.filter(event => {
if (seen.has(event.eventId)) {
return false;
}
seen.add(event.eventId);
return true;
});
}
/**
* 获取队列统计信息(用于调试)
*/
getQueueStats(): {
totalEvents: number;
processedEvents: number;
remainingEvents: number;
isProcessing: boolean;
createTime: number;
} {
return {
totalEvents: this.processedCount + this.damageEvents.length,
processedEvents: this.processedCount,
remainingEvents: this.damageEvents.length,
isProcessing: this.isProcessing,
createTime: this.createTime
};
}
}
/**
* ==================== 伤害队列辅助工具 ====================
*/
export class DamageQueueHelper {
/**
* 为实体添加伤害事件
* 如果实体没有伤害队列组件,会自动创建
*/
static addDamageToEntity(entity: ecs.Entity, attrs: any, casterEid: number, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
let damageQueue = entity.get(DamageQueueComp);
// 如果实体没有伤害队列组件,创建一个
if (!damageQueue) {
damageQueue = entity.add(DamageQueueComp);
}
// 添加伤害事件到队列
damageQueue.addDamageEvent(attrs, casterEid, s_uuid,ext_dmg,dmg_ratio);
}
/**
* 检查实体是否有待处理的伤害
*/
static hasPendingDamage(entity: ecs.Entity): boolean {
const damageQueue = entity.get(DamageQueueComp);
return damageQueue ? !damageQueue.isEmpty() : false;
}
/**
* 获取实体的伤害队列统计信息
*/
static getEntityDamageStats(entity: ecs.Entity): any {
const damageQueue = entity.get(DamageQueueComp);
return damageQueue ? damageQueue.getQueueStats() : null;
}
}