perf: 优化战斗系统内存与性能,增加对象池限制与内存监控面板
- 为Skill和Monster对象池添加最大容量限制(64/24),防止内存泄漏 - 实现DamageQueueComp的环形队列优化,减少数组操作开销 - 在MissionComp中添加内存监控面板,实时显示堆内存、实体数量、对象池状态 - 优化MoveSystem的渲染排序性能,缓存查询结果减少GC压力 - 调整角色控制器UI位置与样式,关闭调试日志减少性能开销 - 战斗结束时自动清理对象池,确保内存可回收
This commit is contained in:
@@ -184,7 +184,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 1120,
|
"y": 1070,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -196,8 +196,8 @@
|
|||||||
},
|
},
|
||||||
"_lscale": {
|
"_lscale": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 1,
|
"x": 2,
|
||||||
"y": 1,
|
"y": 2,
|
||||||
"z": 1
|
"z": 1
|
||||||
},
|
},
|
||||||
"_mobility": 0,
|
"_mobility": 0,
|
||||||
@@ -234,7 +234,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": -50.705,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 200,
|
"width": 200,
|
||||||
"height": 100
|
"height": 200
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
@@ -305,9 +305,9 @@
|
|||||||
"_dstBlendFactor": 4,
|
"_dstBlendFactor": 4,
|
||||||
"_color": {
|
"_color": {
|
||||||
"__type__": "cc.Color",
|
"__type__": "cc.Color",
|
||||||
"r": 255,
|
"r": 0,
|
||||||
"g": 255,
|
"g": 0,
|
||||||
"b": 255,
|
"b": 0,
|
||||||
"a": 255
|
"a": 255
|
||||||
},
|
},
|
||||||
"_spriteFrame": {
|
"_spriteFrame": {
|
||||||
@@ -373,7 +373,7 @@
|
|||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": 0,
|
"x": 0,
|
||||||
"y": 0,
|
"y": 67.606,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"_lrot": {
|
"_lrot": {
|
||||||
@@ -2674,6 +2674,8 @@
|
|||||||
"__id__": 0
|
"__id__": 0
|
||||||
},
|
},
|
||||||
"fileId": "a2T+9jtpFDK6TbGmUuF01c",
|
"fileId": "a2T+9jtpFDK6TbGmUuF01c",
|
||||||
|
"instance": null,
|
||||||
|
"targetOverrides": null,
|
||||||
"nestedPrefabInstanceRoots": null
|
"nestedPrefabInstanceRoots": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3667,6 +3669,8 @@
|
|||||||
"__id__": 0
|
"__id__": 0
|
||||||
},
|
},
|
||||||
"fileId": "92fF6VNGhL4KGhc565gFRM",
|
"fileId": "92fF6VNGhL4KGhc565gFRM",
|
||||||
|
"instance": null,
|
||||||
|
"targetOverrides": null,
|
||||||
"nestedPrefabInstanceRoots": null
|
"nestedPrefabInstanceRoots": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5593,6 +5597,8 @@
|
|||||||
"__id__": 0
|
"__id__": 0
|
||||||
},
|
},
|
||||||
"fileId": "24VpHkRBxCuZkdMazUpc/Y",
|
"fileId": "24VpHkRBxCuZkdMazUpc/Y",
|
||||||
|
"instance": null,
|
||||||
|
"targetOverrides": null,
|
||||||
"nestedPrefabInstanceRoots": null
|
"nestedPrefabInstanceRoots": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -8937,6 +8943,7 @@
|
|||||||
"__id__": 397
|
"__id__": 397
|
||||||
},
|
},
|
||||||
"debugMode": false,
|
"debugMode": false,
|
||||||
|
"showMemoryPanel": true,
|
||||||
"coins_node": null,
|
"coins_node": null,
|
||||||
"lv_node": null,
|
"lv_node": null,
|
||||||
"chou_node": null,
|
"chou_node": null,
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export interface DamageEvent {
|
|||||||
export class DamageQueueComp extends ecs.Comp {
|
export class DamageQueueComp extends ecs.Comp {
|
||||||
/** 伤害事件队列 */
|
/** 伤害事件队列 */
|
||||||
damageEvents: DamageEvent[] = [];
|
damageEvents: DamageEvent[] = [];
|
||||||
|
private readIndex: number = 0;
|
||||||
|
|
||||||
/** 队列创建时间 */
|
/** 队列创建时间 */
|
||||||
createTime: number = 0;
|
createTime: number = 0;
|
||||||
@@ -49,7 +50,8 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
processedCount: number = 0;
|
processedCount: number = 0;
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.damageEvents = [];
|
this.damageEvents.length = 0;
|
||||||
|
this.readIndex = 0;
|
||||||
this.createTime = 0;
|
this.createTime = 0;
|
||||||
this.isProcessing = false;
|
this.isProcessing = false;
|
||||||
this.processedCount = 0;
|
this.processedCount = 0;
|
||||||
@@ -60,14 +62,13 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
*/
|
*/
|
||||||
addDamageEvent(attrs: any, casterEid: number, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
|
addDamageEvent(attrs: any, casterEid: number, s_uuid: number,ext_dmg:number=0,dmg_ratio:number=1): void {
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
const eventId = `${casterEid}_${s_uuid}_${timestamp}_${Math.random()}`;
|
|
||||||
|
|
||||||
const damageEvent: DamageEvent = {
|
const damageEvent: DamageEvent = {
|
||||||
Attrs: attrs ? { ...attrs } : null, // 深拷贝属性数据
|
Attrs: attrs || null,
|
||||||
casterEid: casterEid,
|
casterEid: casterEid,
|
||||||
s_uuid: s_uuid,
|
s_uuid: s_uuid,
|
||||||
timestamp: timestamp,
|
timestamp: timestamp,
|
||||||
eventId: eventId,
|
eventId: "",
|
||||||
ext_dmg:ext_dmg,
|
ext_dmg:ext_dmg,
|
||||||
dmg_ratio:dmg_ratio,
|
dmg_ratio:dmg_ratio,
|
||||||
};
|
};
|
||||||
@@ -75,7 +76,7 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
this.damageEvents.push(damageEvent);
|
this.damageEvents.push(damageEvent);
|
||||||
|
|
||||||
// 如果是第一个伤害事件,记录创建时间
|
// 如果是第一个伤害事件,记录创建时间
|
||||||
if (this.damageEvents.length === 1) {
|
if (this.getRemainingCount() === 1) {
|
||||||
this.createTime = timestamp;
|
this.createTime = timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,29 +85,36 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
* 获取下一个待处理的伤害事件
|
* 获取下一个待处理的伤害事件
|
||||||
*/
|
*/
|
||||||
getNextDamageEvent(): DamageEvent | null {
|
getNextDamageEvent(): DamageEvent | null {
|
||||||
if (this.damageEvents.length === 0) return null;
|
if (this.readIndex >= this.damageEvents.length) return null;
|
||||||
return this.damageEvents.shift() || null;
|
const event = this.damageEvents[this.readIndex];
|
||||||
|
this.readIndex += 1;
|
||||||
|
if (this.readIndex >= 32 && this.readIndex * 2 >= this.damageEvents.length) {
|
||||||
|
this.damageEvents = this.damageEvents.slice(this.readIndex);
|
||||||
|
this.readIndex = 0;
|
||||||
|
}
|
||||||
|
return event || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取队列中剩余的伤害事件数量
|
* 获取队列中剩余的伤害事件数量
|
||||||
*/
|
*/
|
||||||
getRemainingCount(): number {
|
getRemainingCount(): number {
|
||||||
return this.damageEvents.length;
|
return this.damageEvents.length - this.readIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查队列是否为空
|
* 检查队列是否为空
|
||||||
*/
|
*/
|
||||||
isEmpty(): boolean {
|
isEmpty(): boolean {
|
||||||
return this.damageEvents.length === 0;
|
return this.readIndex >= this.damageEvents.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清空队列
|
* 清空队列
|
||||||
*/
|
*/
|
||||||
clear(): void {
|
clear(): void {
|
||||||
this.damageEvents = [];
|
this.damageEvents.length = 0;
|
||||||
|
this.readIndex = 0;
|
||||||
this.processedCount = 0;
|
this.processedCount = 0;
|
||||||
this.isProcessing = false;
|
this.isProcessing = false;
|
||||||
}
|
}
|
||||||
@@ -115,6 +123,10 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
* 按时间戳排序伤害事件(可选功能)
|
* 按时间戳排序伤害事件(可选功能)
|
||||||
*/
|
*/
|
||||||
sortByTimestamp(): void {
|
sortByTimestamp(): void {
|
||||||
|
if (this.readIndex > 0) {
|
||||||
|
this.damageEvents = this.damageEvents.slice(this.readIndex);
|
||||||
|
this.readIndex = 0;
|
||||||
|
}
|
||||||
this.damageEvents.sort((a, b) => a.timestamp - b.timestamp);
|
this.damageEvents.sort((a, b) => a.timestamp - b.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +135,10 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
*/
|
*/
|
||||||
removeDuplicates(): void {
|
removeDuplicates(): void {
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
|
if (this.readIndex > 0) {
|
||||||
|
this.damageEvents = this.damageEvents.slice(this.readIndex);
|
||||||
|
this.readIndex = 0;
|
||||||
|
}
|
||||||
this.damageEvents = this.damageEvents.filter(event => {
|
this.damageEvents = this.damageEvents.filter(event => {
|
||||||
if (seen.has(event.eventId)) {
|
if (seen.has(event.eventId)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -145,7 +161,7 @@ export class DamageQueueComp extends ecs.Comp {
|
|||||||
return {
|
return {
|
||||||
totalEvents: this.processedCount + this.damageEvents.length,
|
totalEvents: this.processedCount + this.damageEvents.length,
|
||||||
processedEvents: this.processedCount,
|
processedEvents: this.processedCount,
|
||||||
remainingEvents: this.damageEvents.length,
|
remainingEvents: this.getRemainingCount(),
|
||||||
isProcessing: this.isProcessing,
|
isProcessing: this.isProcessing,
|
||||||
createTime: this.createTime
|
createTime: this.createTime
|
||||||
};
|
};
|
||||||
@@ -187,4 +203,4 @@ export class DamageQueueHelper {
|
|||||||
const damageQueue = entity.get(DamageQueueComp);
|
const damageQueue = entity.get(DamageQueueComp);
|
||||||
return damageQueue ? damageQueue.getQueueStats() : null;
|
return damageQueue ? damageQueue.getQueueStats() : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ interface IntervalBuffState {
|
|||||||
}
|
}
|
||||||
@ecs.register('HeroAttrs')
|
@ecs.register('HeroAttrs')
|
||||||
export class HeroAttrsComp extends ecs.Comp {
|
export class HeroAttrsComp extends ecs.Comp {
|
||||||
public debugMode: boolean = true;
|
public debugMode: boolean = false;
|
||||||
|
|
||||||
Ebus:any=null!
|
Ebus:any=null!
|
||||||
// ==================== 角色基础信息 ====================
|
// ==================== 角色基础信息 ====================
|
||||||
@@ -159,7 +159,9 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
this.hp += addValue;
|
this.hp += addValue;
|
||||||
this.hp = Math.max(0, Math.min(this.hp, this.hp_max));
|
this.hp = Math.max(0, Math.min(this.hp, this.hp_max));
|
||||||
this.dirty_hp = true; // ✅ 仅标记需要更新
|
this.dirty_hp = true; // ✅ 仅标记需要更新
|
||||||
mLogger.log(this.debugMode, 'HeroAttrs', ` HP变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldHp.toFixed(1)} -> ${this.hp.toFixed(1)}`);
|
if (this.debugMode) {
|
||||||
|
mLogger.log(this.debugMode, 'HeroAttrs', ` HP变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldHp.toFixed(1)} -> ${this.hp.toFixed(1)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_shield(value:number,isValue:boolean){
|
add_shield(value:number,isValue:boolean){
|
||||||
@@ -173,7 +175,9 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
if (this.shield < 0) this.shield = 0;
|
if (this.shield < 0) this.shield = 0;
|
||||||
if (this.shield_max < 0) this.shield_max = 0;
|
if (this.shield_max < 0) this.shield_max = 0;
|
||||||
this.dirty_shield = true; // 标记护盾需要更新
|
this.dirty_shield = true; // 标记护盾需要更新
|
||||||
mLogger.log(this.debugMode, 'HeroAttrs', ` 护盾变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldShield.toFixed(1)} -> ${this.shield.toFixed(1)}`);
|
if (this.debugMode) {
|
||||||
|
mLogger.log(this.debugMode, 'HeroAttrs', ` 护盾变更: ${this.hero_name}, 变化=${addValue.toFixed(1)}, ${oldShield.toFixed(1)} -> ${this.shield.toFixed(1)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ==================== BUFF 管理 ====================
|
// ==================== BUFF 管理 ====================
|
||||||
/**
|
/**
|
||||||
@@ -225,7 +229,9 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
|
|
||||||
this.applyAttrChange(buffConf.buff, normalized.value, normalized.BType);
|
this.applyAttrChange(buffConf.buff, normalized.value, normalized.BType);
|
||||||
|
|
||||||
mLogger.log(this.debugMode, 'HeroAttrs', `添加Buff: ${buffConf.name}, 属性:${buffConf.buff}, 值:${normalized.value}, 时间:${duration}`);
|
if (this.debugMode) {
|
||||||
|
mLogger.log(this.debugMode, 'HeroAttrs', `添加Buff: ${buffConf.name}, 属性:${buffConf.buff}, 值:${normalized.value}, 时间:${duration}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -410,7 +416,9 @@ export class HeroAttrsComp extends ecs.Comp {
|
|||||||
this.applyAttrChange(buff.attr, buff.value, buff.BType, true);
|
this.applyAttrChange(buff.attr, buff.value, buff.BType, true);
|
||||||
|
|
||||||
buffs.splice(i, 1);
|
buffs.splice(i, 1);
|
||||||
mLogger.log(this.debugMode, 'HeroAttrs', `Buff过期: 属性:${buff.attr}, 恢复值:${buff.value}`);
|
if (this.debugMode) {
|
||||||
|
mLogger.log(this.debugMode, 'HeroAttrs', `Buff过期: 属性:${buff.attr}, 恢复值:${buff.value}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,22 +20,51 @@ export class Monster extends ecs.Entity {
|
|||||||
|
|
||||||
// 多键对象池:Map<prefabPath, NodePool>
|
// 多键对象池:Map<prefabPath, NodePool>
|
||||||
static pools: Map<string, NodePool> = new Map();
|
static pools: Map<string, NodePool> = new Map();
|
||||||
|
static readonly MAX_POOL_SIZE: number = 24;
|
||||||
|
|
||||||
static getFromPool(path: string): Node | null {
|
static getFromPool(path: string): Node | null {
|
||||||
if (this.pools.has(path)) {
|
if (this.pools.has(path)) {
|
||||||
const pool = this.pools.get(path)!;
|
const pool = this.pools.get(path)!;
|
||||||
if (pool.size() > 0) {
|
while (pool.size() > 0) {
|
||||||
return pool.get();
|
const node = pool.get();
|
||||||
|
if (node && node.isValid) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static putToPool(path: string, node: Node) {
|
static putToPool(path: string, node: Node) {
|
||||||
|
if (!node || !node.isValid) return;
|
||||||
if (!this.pools.has(path)) {
|
if (!this.pools.has(path)) {
|
||||||
this.pools.set(path, new NodePool());
|
this.pools.set(path, new NodePool());
|
||||||
}
|
}
|
||||||
this.pools.get(path)!.put(node);
|
const pool = this.pools.get(path)!;
|
||||||
|
if (pool.size() >= this.MAX_POOL_SIZE) {
|
||||||
|
node.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pool.put(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static clearPools() {
|
||||||
|
this.pools.forEach((pool) => {
|
||||||
|
pool.clear();
|
||||||
|
});
|
||||||
|
this.pools.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static getPoolStats() {
|
||||||
|
let total = 0;
|
||||||
|
this.pools.forEach((pool) => {
|
||||||
|
total += pool.size();
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
paths: this.pools.size,
|
||||||
|
total,
|
||||||
|
maxPerPath: this.MAX_POOL_SIZE
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected init() {
|
protected init() {
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
private readonly minSpacingY = 30;
|
private readonly minSpacingY = 30;
|
||||||
private readonly renderSortInterval = 0.05;
|
private readonly renderSortInterval = 0.05;
|
||||||
private renderSortElapsed = 0;
|
private renderSortElapsed = 0;
|
||||||
|
private heroMoveMatcher: ecs.IMatcher | null = null;
|
||||||
|
private heroViewMatcher: ecs.IMatcher | null = null;
|
||||||
|
private readonly renderEntries: { node: Node; frontScore: number; spawnOrder: number; eid: number }[] = [];
|
||||||
|
private renderEntryCount = 0;
|
||||||
|
|
||||||
private readonly facConfigs: Record<number, MoveFacConfig> = {
|
private readonly facConfigs: Record<number, MoveFacConfig> = {
|
||||||
[FacSet.HERO]: {
|
[FacSet.HERO]: {
|
||||||
@@ -57,6 +61,20 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private getHeroMoveMatcher(): ecs.IMatcher {
|
||||||
|
if (!this.heroMoveMatcher) {
|
||||||
|
this.heroMoveMatcher = ecs.allOf(HeroAttrsComp, HeroViewComp, MoveComp);
|
||||||
|
}
|
||||||
|
return this.heroMoveMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getHeroViewMatcher(): ecs.IMatcher {
|
||||||
|
if (!this.heroViewMatcher) {
|
||||||
|
this.heroViewMatcher = ecs.allOf(HeroAttrsComp, HeroViewComp);
|
||||||
|
}
|
||||||
|
return this.heroViewMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
filter(): ecs.IMatcher {
|
filter(): ecs.IMatcher {
|
||||||
return ecs.allOf(MoveComp, HeroViewComp, HeroAttrsComp);
|
return ecs.allOf(MoveComp, HeroViewComp, HeroAttrsComp);
|
||||||
}
|
}
|
||||||
@@ -239,7 +257,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
const selfPriority = selfAttrs ? this.getCombatPriority(selfAttrs) : 0;
|
const selfPriority = selfAttrs ? this.getCombatPriority(selfAttrs) : 0;
|
||||||
let nearestAheadX = Infinity;
|
let nearestAheadX = Infinity;
|
||||||
let nearestBehindX = -Infinity;
|
let nearestBehindX = -Infinity;
|
||||||
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp, MoveComp)).forEach(e => {
|
ecs.query(this.getHeroMoveMatcher()).forEach(e => {
|
||||||
if (e === self) return;
|
if (e === self) return;
|
||||||
const attrs = e.get(HeroAttrsComp);
|
const attrs = e.get(HeroAttrsComp);
|
||||||
const view = e.get(HeroViewComp);
|
const view = e.get(HeroViewComp);
|
||||||
@@ -272,7 +290,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
private hasAnyActorTooClose(self: ecs.Entity, x: number, y: number): boolean {
|
private hasAnyActorTooClose(self: ecs.Entity, x: number, y: number): boolean {
|
||||||
const myAttrs = self.get(HeroAttrsComp);
|
const myAttrs = self.get(HeroAttrsComp);
|
||||||
if (!myAttrs) return false;
|
if (!myAttrs) return false;
|
||||||
return ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).some(e => {
|
return ecs.query(this.getHeroViewMatcher()).some(e => {
|
||||||
if (e === self) return false;
|
if (e === self) return false;
|
||||||
const attrs = e.get(HeroAttrsComp);
|
const attrs = e.get(HeroAttrsComp);
|
||||||
if (!attrs || attrs.is_dead) return false;
|
if (!attrs || attrs.is_dead) return false;
|
||||||
@@ -303,7 +321,7 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
let minDis = Infinity;
|
let minDis = Infinity;
|
||||||
|
|
||||||
// 优化查询:一次遍历
|
// 优化查询:一次遍历
|
||||||
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp)).forEach(e => {
|
ecs.query(this.getHeroViewMatcher()).forEach(e => {
|
||||||
const m = e.get(HeroAttrsComp);
|
const m = e.get(HeroAttrsComp);
|
||||||
if (m.fac !== myFac && !m.is_dead) {
|
if (m.fac !== myFac && !m.is_dead) {
|
||||||
const v = e.get(HeroViewComp);
|
const v = e.get(HeroViewComp);
|
||||||
@@ -332,8 +350,8 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
if (this.renderSortElapsed < this.renderSortInterval) return;
|
if (this.renderSortElapsed < this.renderSortInterval) return;
|
||||||
this.renderSortElapsed = 0;
|
this.renderSortElapsed = 0;
|
||||||
|
|
||||||
const renderList: { node: Node; frontScore: number; spawnOrder: number; eid: number }[] = [];
|
this.renderEntryCount = 0;
|
||||||
ecs.query(ecs.allOf(HeroAttrsComp, HeroViewComp, MoveComp)).forEach(e => {
|
ecs.query(this.getHeroMoveMatcher()).forEach(e => {
|
||||||
const attrs = e.get(HeroAttrsComp);
|
const attrs = e.get(HeroAttrsComp);
|
||||||
const actorView = e.get(HeroViewComp);
|
const actorView = e.get(HeroViewComp);
|
||||||
const actorMove = e.get(MoveComp);
|
const actorMove = e.get(MoveComp);
|
||||||
@@ -343,21 +361,27 @@ export class MoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate
|
|||||||
actorView.node.parent = actorRoot;
|
actorView.node.parent = actorRoot;
|
||||||
}
|
}
|
||||||
const frontScore = attrs.fac === FacSet.HERO ? actorView.node.position.x : -actorView.node.position.x;
|
const frontScore = attrs.fac === FacSet.HERO ? actorView.node.position.x : -actorView.node.position.x;
|
||||||
renderList.push({
|
const entryIndex = this.renderEntryCount;
|
||||||
node: actorView.node,
|
let entry = this.renderEntries[entryIndex];
|
||||||
frontScore,
|
if (!entry) {
|
||||||
spawnOrder: actorMove.spawnOrder,
|
entry = { node: actorView.node, frontScore: 0, spawnOrder: 0, eid: 0 };
|
||||||
eid: e.eid
|
this.renderEntries.push(entry);
|
||||||
});
|
}
|
||||||
|
entry.node = actorView.node;
|
||||||
|
entry.frontScore = frontScore;
|
||||||
|
entry.spawnOrder = actorMove.spawnOrder;
|
||||||
|
entry.eid = e.eid;
|
||||||
|
this.renderEntryCount += 1;
|
||||||
});
|
});
|
||||||
|
this.renderEntries.length = this.renderEntryCount;
|
||||||
|
|
||||||
renderList.sort((a, b) => {
|
this.renderEntries.sort((a, b) => {
|
||||||
if (a.frontScore !== b.frontScore) return a.frontScore - b.frontScore;
|
if (a.frontScore !== b.frontScore) return a.frontScore - b.frontScore;
|
||||||
if (a.spawnOrder !== b.spawnOrder) return a.spawnOrder - b.spawnOrder;
|
if (a.spawnOrder !== b.spawnOrder) return a.spawnOrder - b.spawnOrder;
|
||||||
return a.eid - b.eid;
|
return a.eid - b.eid;
|
||||||
});
|
});
|
||||||
|
|
||||||
renderList.forEach((item, index) => {
|
this.renderEntries.forEach((item, index) => {
|
||||||
item.node.setSiblingIndex(index);
|
item.node.setSiblingIndex(index);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { UIID } from "../common/config/GameUIConfig";
|
|||||||
import { SkillView } from "../skill/SkillView";
|
import { SkillView } from "../skill/SkillView";
|
||||||
import { FightSet } from "../common/config/GameSet";
|
import { FightSet } from "../common/config/GameSet";
|
||||||
import { mLogger } from "../common/Logger";
|
import { mLogger } from "../common/Logger";
|
||||||
|
import { Monster } from "../hero/Mon";
|
||||||
|
import { Skill } from "../skill/Skill";
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
|
||||||
@@ -22,6 +24,8 @@ const { ccclass, property } = _decorator;
|
|||||||
export class MissionComp extends CCComp {
|
export class MissionComp extends CCComp {
|
||||||
@property({ tooltip: "是否启用调试日志" })
|
@property({ tooltip: "是否启用调试日志" })
|
||||||
private debugMode: boolean = false;
|
private debugMode: boolean = false;
|
||||||
|
@property({ tooltip: "是否显示战斗内存观测面板" })
|
||||||
|
private showMemoryPanel: boolean = true;
|
||||||
|
|
||||||
// VictoryComp:any = null;
|
// VictoryComp:any = null;
|
||||||
// reward:number = 0;
|
// reward:number = 0;
|
||||||
@@ -50,6 +54,19 @@ export class MissionComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lastTimeStr: string = "";
|
private lastTimeStr: string = "";
|
||||||
|
private lastTimeSecond: number = -1;
|
||||||
|
private memoryLabel: Label | null = null;
|
||||||
|
private memoryRefreshTimer: number = 0;
|
||||||
|
private lastMemoryText: string = "";
|
||||||
|
private perfDtAcc: number = 0;
|
||||||
|
private perfFrameCount: number = 0;
|
||||||
|
private heapBaseMB: number = -1;
|
||||||
|
private heapPeakMB: number = 0;
|
||||||
|
private heapTrendPerMinMB: number = 0;
|
||||||
|
private heapTrendTimer: number = 0;
|
||||||
|
private heapTrendBaseMB: number = -1;
|
||||||
|
private readonly heroViewMatcher = ecs.allOf(HeroViewComp);
|
||||||
|
private readonly skillViewMatcher = ecs.allOf(SkillView);
|
||||||
|
|
||||||
// 记录已触发的特殊刷怪索引
|
// 记录已触发的特殊刷怪索引
|
||||||
private spawnedSpecialIndices: Set<number> = new Set();
|
private spawnedSpecialIndices: Set<number> = new Set();
|
||||||
@@ -60,7 +77,7 @@ export class MissionComp extends CCComp {
|
|||||||
// this.on(GameEvent.FightEnd,this.fight_end,this)
|
// this.on(GameEvent.FightEnd,this.fight_end,this)
|
||||||
this.on(GameEvent.MissionEnd,this.mission_end,this)
|
this.on(GameEvent.MissionEnd,this.mission_end,this)
|
||||||
this.on(GameEvent.DO_AD_BACK,this.do_ad,this)
|
this.on(GameEvent.DO_AD_BACK,this.do_ad,this)
|
||||||
|
this.initMemoryPanel()
|
||||||
}
|
}
|
||||||
protected update(dt: number): void {
|
protected update(dt: number): void {
|
||||||
if(!smc.mission.play) return
|
if(!smc.mission.play) return
|
||||||
@@ -73,12 +90,16 @@ export class MissionComp extends CCComp {
|
|||||||
// 检查特殊刷怪时间
|
// 检查特殊刷怪时间
|
||||||
this.checkSpecialSpawns(smc.vmdata.mission_data.fight_time);
|
this.checkSpecialSpawns(smc.vmdata.mission_data.fight_time);
|
||||||
this.update_time();
|
this.update_time();
|
||||||
|
this.updateMemoryPanel(dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_time(){
|
update_time(){
|
||||||
let time = Math.max(0, this.FightTime);
|
const time = Math.max(0, this.FightTime);
|
||||||
let m = Math.floor(time / 60);
|
const remainSecond = Math.floor(time);
|
||||||
let s = Math.floor(time % 60);
|
if (remainSecond === this.lastTimeSecond) return;
|
||||||
|
this.lastTimeSecond = remainSecond;
|
||||||
|
let m = Math.floor(remainSecond / 60);
|
||||||
|
let s = remainSecond % 60;
|
||||||
let str = `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
|
let str = `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
|
||||||
if(str != this.lastTimeStr){
|
if(str != this.lastTimeStr){
|
||||||
this.time_node.getChildByName("time").getComponent(Label).string = str;
|
this.time_node.getChildByName("time").getComponent(Label).string = str;
|
||||||
@@ -99,6 +120,77 @@ export class MissionComp extends CCComp {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private initMemoryPanel() {
|
||||||
|
if (!this.showMemoryPanel || !this.time_node) return;
|
||||||
|
let panel = this.time_node.getChildByName("mem_panel");
|
||||||
|
if (!panel) {
|
||||||
|
panel = new Node("mem_panel");
|
||||||
|
panel.parent = this.time_node;
|
||||||
|
panel.setPosition(0, -32, 0);
|
||||||
|
}
|
||||||
|
let label = panel.getComponent(Label);
|
||||||
|
if (!label) {
|
||||||
|
label = panel.addComponent(Label);
|
||||||
|
}
|
||||||
|
label.fontSize = 16;
|
||||||
|
label.lineHeight = 20;
|
||||||
|
this.memoryLabel = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateMemoryPanel(dt: number) {
|
||||||
|
if (!this.showMemoryPanel || !this.memoryLabel) return;
|
||||||
|
this.perfDtAcc += dt;
|
||||||
|
this.perfFrameCount += 1;
|
||||||
|
this.memoryRefreshTimer += dt;
|
||||||
|
if (this.memoryRefreshTimer < 0.5) return;
|
||||||
|
this.memoryRefreshTimer = 0;
|
||||||
|
let heroCount = 0;
|
||||||
|
ecs.query(this.heroViewMatcher).forEach(() => {
|
||||||
|
heroCount++;
|
||||||
|
});
|
||||||
|
let skillCount = 0;
|
||||||
|
ecs.query(this.skillViewMatcher).forEach(() => {
|
||||||
|
skillCount++;
|
||||||
|
});
|
||||||
|
const monPool = Monster.getPoolStats();
|
||||||
|
const skillPool = Skill.getPoolStats();
|
||||||
|
const perf = (globalThis as any).performance;
|
||||||
|
const heapBytes = perf && perf.memory ? perf.memory.usedJSHeapSize : 0;
|
||||||
|
let heapMB = heapBytes > 0 ? heapBytes / 1024 / 1024 : -1;
|
||||||
|
if (heapMB > 0 && this.heapBaseMB < 0) {
|
||||||
|
this.heapBaseMB = heapMB;
|
||||||
|
this.heapPeakMB = heapMB;
|
||||||
|
this.heapTrendBaseMB = heapMB;
|
||||||
|
this.heapTrendTimer = 0;
|
||||||
|
}
|
||||||
|
if (heapMB > this.heapPeakMB) {
|
||||||
|
this.heapPeakMB = heapMB;
|
||||||
|
}
|
||||||
|
this.heapTrendTimer += 0.5;
|
||||||
|
if (heapMB > 0 && this.heapTrendBaseMB > 0 && this.heapTrendTimer >= 10) {
|
||||||
|
const deltaMB = heapMB - this.heapTrendBaseMB;
|
||||||
|
this.heapTrendPerMinMB = (deltaMB / this.heapTrendTimer) * 60;
|
||||||
|
this.heapTrendBaseMB = heapMB;
|
||||||
|
this.heapTrendTimer = 0;
|
||||||
|
}
|
||||||
|
const heapText = heapMB > 0 ? heapMB.toFixed(1) : "N/A";
|
||||||
|
const heapDeltaText = this.heapBaseMB > 0 && heapMB > 0 ? (heapMB - this.heapBaseMB).toFixed(1) : "N/A";
|
||||||
|
const heapPeakText = this.heapPeakMB > 0 ? this.heapPeakMB.toFixed(1) : "N/A";
|
||||||
|
const avgDt = this.perfFrameCount > 0 ? this.perfDtAcc / this.perfFrameCount : 0;
|
||||||
|
const fps = avgDt > 0 ? 1 / avgDt : 0;
|
||||||
|
this.perfDtAcc = 0;
|
||||||
|
this.perfFrameCount = 0;
|
||||||
|
const text =
|
||||||
|
`Heap:${heapText}MB Δ:${heapDeltaText} Peak:${heapPeakText}\n` +
|
||||||
|
`Trend:${this.heapTrendPerMinMB.toFixed(2)}MB/min\n` +
|
||||||
|
`Perf dt:${(avgDt * 1000).toFixed(1)}ms fps:${fps.toFixed(1)}\n` +
|
||||||
|
`Ent H:${heroCount} S:${skillCount}\n` +
|
||||||
|
`Pool M:${monPool.total}(${monPool.paths}) K:${skillPool.total}(${skillPool.paths})`;
|
||||||
|
if (text === this.lastMemoryText) return;
|
||||||
|
this.lastMemoryText = text;
|
||||||
|
this.memoryLabel.string = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//奖励发放
|
//奖励发放
|
||||||
do_reward(){
|
do_reward(){
|
||||||
@@ -180,6 +272,7 @@ do_ad(){
|
|||||||
this.scheduleOnce(() => {
|
this.scheduleOnce(() => {
|
||||||
smc.mission.play=false
|
smc.mission.play=false
|
||||||
this.cleanComponents()
|
this.cleanComponents()
|
||||||
|
this.clearBattlePools()
|
||||||
}, 0.5)
|
}, 0.5)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +281,7 @@ do_ad(){
|
|||||||
// 合并 FightEnd 逻辑:清理组件、停止游戏循环
|
// 合并 FightEnd 逻辑:清理组件、停止游戏循环
|
||||||
smc.mission.play=false
|
smc.mission.play=false
|
||||||
this.cleanComponents()
|
this.cleanComponents()
|
||||||
|
this.clearBattlePools()
|
||||||
this.node.active=false
|
this.node.active=false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +299,17 @@ do_ad(){
|
|||||||
this.rewards=[] // 改为数组,用于存储掉落物品列表
|
this.rewards=[] // 改为数组,用于存储掉落物品列表
|
||||||
this.revive_times = 1; // 每次任务开始重置复活次数
|
this.revive_times = 1; // 每次任务开始重置复活次数
|
||||||
this.spawnedSpecialIndices.clear(); // 重置特殊刷怪记录
|
this.spawnedSpecialIndices.clear(); // 重置特殊刷怪记录
|
||||||
|
this.lastTimeStr = "";
|
||||||
|
this.lastTimeSecond = -1;
|
||||||
|
this.memoryRefreshTimer = 0;
|
||||||
|
this.lastMemoryText = "";
|
||||||
|
this.perfDtAcc = 0;
|
||||||
|
this.perfFrameCount = 0;
|
||||||
|
this.heapBaseMB = -1;
|
||||||
|
this.heapPeakMB = 0;
|
||||||
|
this.heapTrendPerMinMB = 0;
|
||||||
|
this.heapTrendTimer = 0;
|
||||||
|
this.heapTrendBaseMB = -1;
|
||||||
|
|
||||||
// 重置全局属性加成和主角引用 (确保新一局数据干净)
|
// 重置全局属性加成和主角引用 (确保新一局数据干净)
|
||||||
// smc.role = null;
|
// smc.role = null;
|
||||||
@@ -217,14 +322,19 @@ do_ad(){
|
|||||||
private cleanComponents() {
|
private cleanComponents() {
|
||||||
// 优化销毁顺序:直接销毁实体,让ECS系统自动处理组件清理
|
// 优化销毁顺序:直接销毁实体,让ECS系统自动处理组件清理
|
||||||
// 这样可以避免在组件reset方法中访问已经被销毁的实体引用
|
// 这样可以避免在组件reset方法中访问已经被销毁的实体引用
|
||||||
ecs.query(ecs.allOf(HeroViewComp)).forEach(entity => {
|
ecs.query(this.heroViewMatcher).forEach(entity => {
|
||||||
entity.destroy();
|
entity.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
ecs.query(ecs.allOf(SkillView)).forEach(entity => {
|
ecs.query(this.skillViewMatcher).forEach(entity => {
|
||||||
entity.destroy();
|
entity.destroy();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private clearBattlePools() {
|
||||||
|
Monster.clearPools();
|
||||||
|
Skill.clearPools();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** 视图层逻辑代码分离演示 */
|
/** 视图层逻辑代码分离演示 */
|
||||||
@@ -233,4 +343,4 @@ do_ad(){
|
|||||||
reset() {
|
reset() {
|
||||||
this.node.destroy();
|
this.node.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class Skill extends ecs.Entity {
|
|||||||
private debugMode: boolean = false;
|
private debugMode: boolean = false;
|
||||||
/** 多键对象池:Map<prefabPath, NodePool> */
|
/** 多键对象池:Map<prefabPath, NodePool> */
|
||||||
static pools: Map<string, NodePool> = new Map();
|
static pools: Map<string, NodePool> = new Map();
|
||||||
|
static readonly MAX_POOL_SIZE: number = 64;
|
||||||
|
|
||||||
static getFromPool(path: string): Node | null {
|
static getFromPool(path: string): Node | null {
|
||||||
if (this.pools.has(path)) {
|
if (this.pools.has(path)) {
|
||||||
@@ -38,7 +39,31 @@ export class Skill extends ecs.Entity {
|
|||||||
if (!this.pools.has(path)) {
|
if (!this.pools.has(path)) {
|
||||||
this.pools.set(path, new NodePool());
|
this.pools.set(path, new NodePool());
|
||||||
}
|
}
|
||||||
this.pools.get(path)!.put(node);
|
const pool = this.pools.get(path)!;
|
||||||
|
if (pool.size() >= this.MAX_POOL_SIZE) {
|
||||||
|
node.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pool.put(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static clearPools() {
|
||||||
|
this.pools.forEach((pool) => {
|
||||||
|
pool.clear();
|
||||||
|
});
|
||||||
|
this.pools.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static getPoolStats() {
|
||||||
|
let total = 0;
|
||||||
|
this.pools.forEach((pool) => {
|
||||||
|
total += pool.size();
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
paths: this.pools.size,
|
||||||
|
total,
|
||||||
|
maxPerPath: this.MAX_POOL_SIZE
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ---------- 数据层 ---------- */
|
/** ---------- 数据层 ---------- */
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class SkillView extends CCComp {
|
|||||||
atk_y: number = 0
|
atk_y: number = 0
|
||||||
|
|
||||||
@property({ tooltip: "是否启用调试日志" })
|
@property({ tooltip: "是否启用调试日志" })
|
||||||
private debugMode: boolean = true;
|
private debugMode: boolean = false;
|
||||||
|
|
||||||
anim:Animation=null;
|
anim:Animation=null;
|
||||||
group:number=0;
|
group:number=0;
|
||||||
@@ -65,13 +65,14 @@ export class SkillView extends CCComp {
|
|||||||
}
|
}
|
||||||
if (this.isDisposing) return;
|
if (this.isDisposing) return;
|
||||||
if (!this.node || !this.node.activeInHierarchy) return;
|
if (!this.node || !this.node.activeInHierarchy) return;
|
||||||
// 安全获取双方信息用于日志
|
|
||||||
const casterName = this.sData.caster?.ent?.get(HeroAttrsComp)?.hero_name ?? '未知施法者';
|
|
||||||
const casterEid = this.sData.casterEid;
|
|
||||||
const targetView = oCol.getComponent(HeroViewComp);
|
const targetView = oCol.getComponent(HeroViewComp);
|
||||||
const targetName = targetView?.ent?.get(HeroAttrsComp)?.hero_name ?? '非英雄对象';
|
if (this.debugMode) {
|
||||||
const targetEid = targetView?.ent?.eid ?? '未知EID';
|
const casterName = this.sData.caster?.ent?.get(HeroAttrsComp)?.hero_name ?? '未知施法者';
|
||||||
mLogger.log(this.debugMode, 'SkillView', `[skillView] 碰撞1 [${this.sData.caster.box_group}][${casterName}][${casterEid}]的[${seCol.group}]:[${this.SConf.name}][${this.ent.eid}]碰撞了 [${oCol.group}]:[ ${targetName}][${targetEid}]`);
|
const casterEid = this.sData.casterEid;
|
||||||
|
const targetName = targetView?.ent?.get(HeroAttrsComp)?.hero_name ?? '非英雄对象';
|
||||||
|
const targetEid = targetView?.ent?.eid ?? '未知EID';
|
||||||
|
mLogger.log(this.debugMode, 'SkillView', `[skillView] 碰撞1 [${this.sData.caster.box_group}][${casterName}][${casterEid}]的[${seCol.group}]:[${this.SConf.name}][${this.ent.eid}]碰撞了 [${oCol.group}]:[ ${targetName}][${targetEid}]`);
|
||||||
|
}
|
||||||
if (oCol.group === seCol.group) return;
|
if (oCol.group === seCol.group) return;
|
||||||
if (this.pendingDisableCollider) return;
|
if (this.pendingDisableCollider) return;
|
||||||
if (this.sData.hit_count >= this.sData.max_hit_count) {
|
if (this.sData.hit_count >= this.sData.max_hit_count) {
|
||||||
@@ -91,7 +92,9 @@ export class SkillView extends CCComp {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let model = targetView.ent.get(HeroAttrsComp);
|
let model = targetView.ent.get(HeroAttrsComp);
|
||||||
mLogger.log(this.debugMode, 'SkillView', `[skillView] 碰撞3`, oCol.group, seCol.group, model);
|
if (this.debugMode) {
|
||||||
|
mLogger.log(this.debugMode, 'SkillView', `[skillView] 碰撞3`, oCol.group, seCol.group, model);
|
||||||
|
}
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
if (model.is_dead) return;
|
if (model.is_dead) return;
|
||||||
if (this.sData.fac == model.fac) return;
|
if (this.sData.fac == model.fac) return;
|
||||||
@@ -126,11 +129,11 @@ export class SkillView extends CCComp {
|
|||||||
if (!target.ent) return;
|
if (!target.ent) return;
|
||||||
if (!this.sData) return;
|
if (!this.sData) return;
|
||||||
if (!this.SConf) return;
|
if (!this.SConf) return;
|
||||||
// 安全获取名称,防止实体销毁导致的空指针异常
|
if (this.debugMode) {
|
||||||
const casterName = this.sData.caster?.ent?.get(HeroAttrsComp)?.hero_name ?? "未知施法者";
|
const casterName = this.sData.caster?.ent?.get(HeroAttrsComp)?.hero_name ?? "未知施法者";
|
||||||
const targetName = target.ent.get(HeroAttrsComp)?.hero_name ?? "未知目标";
|
const targetName = target.ent.get(HeroAttrsComp)?.hero_name ?? "未知目标";
|
||||||
|
mLogger.log(this.debugMode, 'SkillView', `[skillView] 伤害 [${this.group}][${casterName}][${this.sData.casterEid}]的 [${this.SConf.name}]对 [${target.box_group}][ ${targetName}][${target.ent.eid}]`);
|
||||||
mLogger.log(this.debugMode, 'SkillView', `[skillView] 伤害 [${this.group}][${casterName}][${this.sData.casterEid}]的 [${this.SConf.name}]对 [${target.box_group}][ ${targetName}][${target.ent.eid}]`);
|
}
|
||||||
// 使用伤害队列系统处理伤害
|
// 使用伤害队列系统处理伤害
|
||||||
DamageQueueHelper.addDamageToEntity(
|
DamageQueueHelper.addDamageToEntity(
|
||||||
target.ent,
|
target.ent,
|
||||||
|
|||||||
Reference in New Issue
Block a user