Files
pixelheros/assets/script/game/hero/DamageQueueComp.ts
walkpan a32aa5ad08 fix(hero): 修复DamageQueueComp中caster可能为null时的错误
当caster或caster.ent为null时,使用可选链操作符和空值合并运算符提供默认值,避免生成eventId时出现错误
2026-01-06 12:14:14 +08:00

191 lines
5.2 KiB
TypeScript
Raw 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;
/** 施法者 */
caster: HeroViewComp;
/** 技能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, caster: HeroViewComp, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
const timestamp = Date.now();
const casterEid = caster?.ent?.eid ?? -1;
const eventId = `${casterEid}_${s_uuid}_${timestamp}_${Math.random()}`;
const damageEvent: DamageEvent = {
Attrs: attrs ? { ...attrs } : null, // 深拷贝属性数据
caster: caster,
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, caster: HeroViewComp, 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, caster, 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;
}
}