refactor(hero): 优化英雄与怪物实体加载与注释

- 统一英雄与怪物实体加载流程,增强代码可读性与维护性
- 为 Hero.ts 与 Mon.ts 添加详细方法级注释,说明组件职责与关键逻辑
- 在配置文件中将攻击速度(as)注释更新为技能冷却(skills[0].cd),使配置项含义更清晰
- 修复怪物技能等级未随怪物等级提升的问题,使其与英雄逻辑保持一致
- 优化对象池管理,增加容量统计与调试信息
This commit is contained in:
panw
2026-03-24 14:40:04 +08:00
parent 23cc992579
commit 1fa2be19f7
3 changed files with 120 additions and 49 deletions

View File

@@ -86,12 +86,12 @@ export interface HSkillInfo {
* skills[0]是普通攻击技能 * skills[0]是普通攻击技能
* skills[1]是等级1时的技能,skills[2]是等级2时的技能,skills[3]是等级3时的技能,最多3级 * skills[1]是等级1时的技能,skills[2]是等级2时的技能,skills[3]是等级3时的技能,最多3级
* *
* 属性基准(cards_lv:1,lv:1) SPEED:120,AP:30 |HP:300|as:1 * 属性基准(cards_lv:1,lv:1) SPEED:120,AP:30 | HP:300 | skills[0].cd=1
* 坦克(cards_lv:1,lv:1) SPEED:180,AP:25 |HP:450|as:0.75 * 坦克(cards_lv:1,lv:1) SPEED:180,AP:25 | HP:450 | skills[0].cd=0.75
* 近战dps(cards_lv:1,lv:1) SPEED:180,AP:50 |HP:250|as:1.1 * 近战dps(cards_lv:1,lv:1) SPEED:180,AP:50 | HP:250 | skills[0].cd=1.1
* 远程dps(cards_lv:1,lv:1) SPEED:120,AP:60 |HP:150|as:1.3 * 远程dps(cards_lv:1,lv:1) SPEED:120,AP:60 | HP:150 | skills[0].cd=1.3
*远程法dps(cards_lv:1,lv:1) SPEED:100,AP:60 |HP:150|as:1.4 *远程法dps(cards_lv:1,lv:1) SPEED:100,AP:60 | HP:150 | skills[0].cd=1.4
* 远程辅助(cards_lv:1,lv:1) SPEED:100,AP:20 |HP:150|as:1 * 远程辅助(cards_lv:1,lv:1) SPEED:100,AP:20 | HP:150 | skills[0].cd=1
*/ */
export const HeroInfo: Record<number, heroInfo> = { export const HeroInfo: Record<number, heroInfo> = {

View File

@@ -10,14 +10,20 @@ import { GameEvent } from "../common/config/GameEvent";
import { Attrs} from "../common/config/HeroAttrs"; import { Attrs} from "../common/config/HeroAttrs";
import { MoveComp } from "./MoveComp"; import { MoveComp } from "./MoveComp";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
/** 角色实体 */ /** 英雄实体:负责英雄节点创建、属性初始化、入场动画与销毁流程 */
@ecs.register(`Hero`) @ecs.register(`Hero`)
export class Hero extends ecs.Entity { export class Hero extends ecs.Entity {
/** 英雄数据组件引用 */
HeroModel!: HeroAttrsComp; HeroModel!: HeroAttrsComp;
/** 英雄表现组件引用 */
View!: HeroViewComp; View!: HeroViewComp;
/** 英雄移动组件引用 */
HeroMove!: MoveComp; HeroMove!: MoveComp;
debugMode: boolean = false; // 是否启用调试模式 /** 调试开关,开启后输出实体层级等调试信息 */
debugMode: boolean = false;
/** 注册实体必需组件:移动 + 属性 */
protected init() { protected init() {
this.addComponents<ecs.Comp>( this.addComponents<ecs.Comp>(
MoveComp, MoveComp,
@@ -25,88 +31,111 @@ export class Hero extends ecs.Entity {
); );
} }
/** 销毁实体并释放视图节点,防止残留碰撞体与显示对象 */
destroy(): void { destroy(): void {
// 销毁节点,防止视觉残留 // 优先销毁节点,避免实体销毁后场景仍残留可见对象
const view = this.get(HeroViewComp); const view = this.get(HeroViewComp);
if (view && view.node && view.node.isValid) { if (view && view.node && view.node.isValid) {
view.node.destroy(); view.node.destroy();
} }
// 手动移除组件,确保 ecs 侧引用及时释放
this.remove(HeroViewComp); this.remove(HeroViewComp);
this.remove(HeroAttrsComp); this.remove(HeroAttrsComp);
super.destroy(); super.destroy();
} }
/** 加载角色 */ /**
* 加载并初始化英雄
* 1) 创建节点并挂到 HERO 层
* 2) 初始化表现与属性数据
* 3) 播放下落入场并在落地后启用碰撞与移动
*/
load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001, dropToY:number = pos.y,hero_lv:number=1) { load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001, dropToY:number = pos.y,hero_lv:number=1) {
// 英雄始终朝右,表现缩放固定为正向
scale = 1 scale = 1
// 英雄等级在当前规则下上限为 3避免超配表范围
if(hero_lv>3) hero_lv=3 if(hero_lv>3) hero_lv=3
// 查找空闲英雄槽位 // 英雄尺寸随等级做轻量放大,强化成长反馈
let size=1+0.1*hero_lv let size=1+0.1*hero_lv
// 根据配置路径加载英雄预制体
var path = "game/heros/"+HeroInfo[uuid].path; var path = "game/heros/"+HeroInfo[uuid].path;
var prefab: Prefab = oops.res.get(path, Prefab)!; var prefab: Prefab = oops.res.get(path, Prefab)!;
var node = instantiate(prefab); var node = instantiate(prefab);
var scene = smc.map.MapView.scene; var scene = smc.map.MapView.scene;
// 统一挂到实体显示层 HERO 节点下
node.parent = scene.entityLayer!.node!.getChildByName("HERO")!; node.parent = scene.entityLayer!.node!.getChildByName("HERO")!;
const collider = node.getComponent(BoxCollider2D); const collider = node.getComponent(BoxCollider2D);
if (collider) collider.enabled = false; // 先禁用 // 入场过程暂不参与碰撞,防止半空触发战斗逻辑
if (collider) collider.enabled = false;
node.setScale(size*node.scale.x,size*node.scale.y); node.setScale(size*node.scale.x,size*node.scale.y);
node.setPosition(pos) node.setPosition(pos)
// 🔥 设置初始 SiblingIndex - 英雄基础层级 + 位置偏移 // 输出节点层级信息,便于排查遮挡与渲染顺序问题
mLogger.log(this.debugMode,"hero",node.getSiblingIndex()); mLogger.log(this.debugMode,"hero",node.getSiblingIndex());
var hv = node.getComponent(HeroViewComp)!; var hv = node.getComponent(HeroViewComp)!;
const model = this.get(HeroAttrsComp); const model = this.get(HeroAttrsComp);
let hero = HeroInfo[uuid]; // 共用英雄数据 // 从配置中读取英雄静态数据
let hero = HeroInfo[uuid];
// 设置 View 层属性(表现相关) // 视图层参数:朝向与碰撞阵营
hv.scale = 1; hv.scale = 1;
hv.box_group = BoxSet.HERO; hv.box_group = BoxSet.HERO;
// 设置 Model 层属性(数据相关) // 模型层参数:身份、阵营、等级、职业
model.hero_uuid = uuid; model.hero_uuid = uuid;
model.hero_name = hero.name; model.hero_name = hero.name;
model.lv = hero_lv; model.lv = hero_lv;
model.type = hero.type; model.type = hero.type;
model.fac = FacSet.HERO; model.fac = FacSet.HERO;
// 只有主角才挂载天赋组件
// ✅ 初始化技能数据(迁移到 HeroSkillsComp
// 设置基础属性 // 基础属性按等级倍率初始化
model.ap = hero.ap*model.lv; model.ap = hero.ap*model.lv;
model.hp= model.hp_max = hero.hp*model.lv; model.hp= model.hp_max = hero.hp*model.lv;
model.speed = hero.speed; model.speed = hero.speed;
// 构建技能表并注入运行时冷却字段 ccd
model.skills = {}; model.skills = {};
for (const key in hero.skills) { for (const key in hero.skills) {
const skill = hero.skills[key]; const skill = hero.skills[key];
if (!skill) continue; if (!skill) continue;
//用于增量 计算最终技能等级英雄等级与技能初始等级均从1开始需各减1抵消故-2最低等级时0 // 最终技能等级 = 初始技能等级 + 英雄等级增量,且下限为 0
model.skills[skill.uuid] = { ...skill, lv: Math.max(0,skill.lv + hero_lv - 2), ccd: 0 }; model.skills[skill.uuid] = { ...skill, lv: Math.max(0,skill.lv + hero_lv - 2), ccd: 0 };
} }
// 缓存技能射程等派生数据,减少战斗帧内重复计算
model.updateSkillDistanceCache(); model.updateSkillDistanceCache();
// 初始化 buff/debuff 系统 // 初始化属性系统(buff/debuff 等动态属性容器)
model.initAttrs(); model.initAttrs();
// 将视图组件注册到实体,打通逻辑与表现
this.add(hv); this.add(hv);
// 广播主角召唤事件,触发外部系统监听逻辑
oops.message.dispatchEvent(GameEvent.MasterCalled,{uuid:uuid}) oops.message.dispatchEvent(GameEvent.MasterCalled,{uuid:uuid})
// 初始化移动组件:方向、目标 X、站位基准 Y
const move = this.get(MoveComp); const move = this.get(MoveComp);
move.direction = 1; // 向右移动 move.direction = 1;
move.targetX = resolveFormationTargetX(model.fac, model.type); move.targetX = resolveFormationTargetX(model.fac, model.type);
move.baseY = dropToY; move.baseY = dropToY;
move.moving = false; move.moving = false;
// 依据下落距离自适应入场时长,保证手感稳定
const dropDistance = Math.abs(pos.y - dropToY); const dropDistance = Math.abs(pos.y - dropToY);
const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200)); const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200));
// 停止旧动画后执行下落 tween避免复用节点时动画叠加
Tween.stopAllByTarget(node); Tween.stopAllByTarget(node);
tween(node) tween(node)
.to(dropDuration, { position: v3(pos.x, dropToY, 0) }) .to(dropDuration, { position: v3(pos.x, dropToY, 0) })
.call(() => { .call(() => {
if (!node || !node.isValid) return; if (!node || !node.isValid) return;
// 落地后锁定最终位置,切换到落地完成状态
node.setPosition(pos.x, dropToY, 0); node.setPosition(pos.x, dropToY, 0);
hv.playEnd("down"); hv.playEnd("down");
move.moving = true; move.moving = true;
// 落地后再启用碰撞,避免空中阶段触发伤害结算
if (collider) { if (collider) {
collider.enabled = true; collider.enabled = true;
collider.group = BoxSet.HERO; collider.group = BoxSet.HERO;
@@ -114,26 +143,29 @@ export class Hero extends ecs.Entity {
} }
}) })
.start(); .start();
// 维护关卡内英雄数量统计
smc.vmdata.mission_data.hero_num++ smc.vmdata.mission_data.hero_num++
} }
/** 重置入口:复用 destroy 的释放流程 */
reset() { reset() {
// 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放
super.destroy(); super.destroy();
} }
} }
/** 英雄生命周期系统:监听实体进入与移除并输出调试日志 */
@ecs.register('HeroLifecycleSystem') @ecs.register('HeroLifecycleSystem')
export class HeroLifecycleSystem extends ecs.ComblockSystem export class HeroLifecycleSystem extends ecs.ComblockSystem
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem { implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
/** 仅处理拥有 MoveComp 的实体 */
filter() { filter() {
return ecs.allOf(MoveComp); return ecs.allOf(MoveComp);
} }
/** 实体进入世界时记录日志 */
entityEnter(e: ecs.Entity): void { entityEnter(e: ecs.Entity): void {
// 英雄实体创建时的特殊处理
const heroAttrs = e.get(HeroAttrsComp); const heroAttrs = e.get(HeroAttrsComp);
if (heroAttrs) { if (heroAttrs) {
mLogger.log(heroAttrs.debugMode, 'HeroLifecycle', `英雄进入世界: ${heroAttrs.hero_name}`); mLogger.log(heroAttrs.debugMode, 'HeroLifecycle', `英雄进入世界: ${heroAttrs.hero_name}`);
@@ -142,8 +174,8 @@ export class HeroLifecycleSystem extends ecs.ComblockSystem
} }
} }
/** 实体离开世界时记录日志 */
entityRemove(e: ecs.Entity): void { entityRemove(e: ecs.Entity): void {
// 英雄实体销毁时的清理工作
const heroAttrs = e.get(HeroAttrsComp); const heroAttrs = e.get(HeroAttrsComp);
if (heroAttrs) { if (heroAttrs) {
mLogger.log(heroAttrs.debugMode, 'HeroLifecycle', `英雄离开世界: ${heroAttrs.hero_name}`); mLogger.log(heroAttrs.debugMode, 'HeroLifecycle', `英雄离开世界: ${heroAttrs.hero_name}`);

View File

@@ -8,18 +8,26 @@ import { HeroAttrsComp } from "./HeroAttrsComp";
import { HeroViewComp } from "./HeroViewComp"; import { HeroViewComp } from "./HeroViewComp";
import { MoveComp } from "./MoveComp"; import { MoveComp } from "./MoveComp";
import { mLogger } from "../common/Logger"; import { mLogger } from "../common/Logger";
/** 角色实体 */ /** 怪物实体:负责怪物对象池复用、属性初始化、入场动画与回收 */
@ecs.register(`Monster`) @ecs.register(`Monster`)
export class Monster extends ecs.Entity { export class Monster extends ecs.Entity {
/** 怪物数据组件引用 */
HeroModel!: HeroAttrsComp; HeroModel!: HeroAttrsComp;
/** 怪物表现组件引用 */
HeroView!: HeroViewComp; HeroView!: HeroViewComp;
/** 怪物移动组件引用 */
MonMove!: MoveComp; MonMove!: MoveComp;
private debugMode: boolean = false; // 是否启用调试模式 /** 调试开关,控制生命周期日志输出 */
private debugMode: boolean = false;
// 多键对象池:Map<prefabPath, NodePool> /** 多键对象池:key 为 prefab 路径value 为对应节点池 */
static pools: Map<string, NodePool> = new Map(); static pools: Map<string, NodePool> = new Map();
/** 单个路径的池容量上限 */
static readonly MAX_POOL_SIZE: number = 12; static readonly MAX_POOL_SIZE: number = 12;
/** 所有路径合计池容量上限 */
static readonly MAX_POOL_TOTAL: number = 60; static readonly MAX_POOL_TOTAL: number = 60;
/** 计算当前所有对象池节点总量 */
private static totalPoolSize(): number { private static totalPoolSize(): number {
let total = 0; let total = 0;
this.pools.forEach((pool) => { this.pools.forEach((pool) => {
@@ -28,6 +36,7 @@ export class Monster extends ecs.Entity {
return total; return total;
} }
/** 从指定路径对象池取可用节点,取不到返回 null */
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)!;
@@ -41,6 +50,7 @@ export class Monster extends ecs.Entity {
return null; return null;
} }
/** 节点回收到对象池,超上限则直接销毁 */
static putToPool(path: string, node: Node) { static putToPool(path: string, node: Node) {
if (!node || !node.isValid) return; if (!node || !node.isValid) return;
if (!this.pools.has(path)) { if (!this.pools.has(path)) {
@@ -54,6 +64,7 @@ export class Monster extends ecs.Entity {
pool.put(node); pool.put(node);
} }
/** 清空所有对象池并销毁池内节点 */
static clearPools() { static clearPools() {
this.pools.forEach((pool) => { this.pools.forEach((pool) => {
while (pool.size() > 0) { while (pool.size() > 0) {
@@ -67,6 +78,7 @@ export class Monster extends ecs.Entity {
this.pools.clear(); this.pools.clear();
} }
/** 获取对象池统计信息,用于调试与容量监控 */
static getPoolStats() { static getPoolStats() {
let total = 0; let total = 0;
this.pools.forEach((pool) => { this.pools.forEach((pool) => {
@@ -80,6 +92,7 @@ export class Monster extends ecs.Entity {
}; };
} }
/** 注册实体必需组件:移动 + 属性 */
protected init() { protected init() {
this.addComponents<ecs.Comp>( this.addComponents<ecs.Comp>(
MoveComp, MoveComp,
@@ -87,8 +100,9 @@ export class Monster extends ecs.Entity {
); );
} }
/** 销毁实体:优先回收节点,然后释放组件 */
destroy(): void { destroy(): void {
// 回收节点到对象池 // 按英雄路径回收到对象池,提升高频刷怪性能
const model = this.get(HeroAttrsComp); const model = this.get(HeroAttrsComp);
const view = this.get(HeroViewComp); const view = this.get(HeroViewComp);
if (model && view && view.node && view.node.isValid) { if (model && view && view.node && view.node.isValid) {
@@ -96,28 +110,39 @@ export class Monster extends ecs.Entity {
Monster.putToPool(path, view.node); Monster.putToPool(path, view.node);
} }
// 手动移除组件,避免 ecs 引用滞留
this.remove(HeroViewComp); this.remove(HeroViewComp);
this.remove(HeroAttrsComp); this.remove(HeroAttrsComp);
super.destroy(); super.destroy();
} }
/** 加载角色 */ /**
load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001, is_boss:boolean=false, dropToY:number = pos.y) { * 加载并初始化怪物
* 1) 优先对象池复用节点,减少实例化开销
* 2) 初始化表现、属性、技能与阵营
* 3) 播放下落入场并在落地后启用碰撞与移动
*/
load(pos: Vec3 = Vec3.ZERO,scale:number = 1,uuid:number=1001, is_boss:boolean=false, dropToY:number = pos.y,mon_lv:number=1) {
// 怪物默认朝左,表现缩放固定为负向
scale=-1 scale=-1
// 当前怪物尺寸固定,保留变量便于后续扩展
let size=1 let size=1
var scene = smc.map.MapView.scene; var scene = smc.map.MapView.scene;
// 根据配置读取怪物预制体路径
var path = "game/heros/"+HeroInfo[uuid].path; var path = "game/heros/"+HeroInfo[uuid].path;
// 尝试从池中获取 // 优先从对象池取节点,未命中时再实例化
let node = Monster.getFromPool(path); let node = Monster.getFromPool(path);
if (!node) { if (!node) {
var prefab: Prefab = oops.res.get(path, Prefab)!; var prefab: Prefab = oops.res.get(path, Prefab)!;
node = instantiate(prefab); node = instantiate(prefab);
} }
// 统一挂到实体显示层 HERO 节点下
node.parent = scene.entityLayer!.node!.getChildByName("HERO")!; node.parent = scene.entityLayer!.node!.getChildByName("HERO")!;
var view = node.getComponent(HeroViewComp)!; var view = node.getComponent(HeroViewComp)!;
const collider = node.getComponent(BoxCollider2D); const collider = node.getComponent(BoxCollider2D);
// 入场期间关闭碰撞,防止下落时提前参与战斗
if (collider) { if (collider) {
collider.enabled = false; collider.enabled = false;
} }
@@ -125,54 +150,64 @@ export class Monster extends ecs.Entity {
node.setScale(size*node.scale.x,size*node.scale.y); node.setScale(size*node.scale.x,size*node.scale.y);
node.setPosition(pos) node.setPosition(pos)
const model = this.get(HeroAttrsComp); const model = this.get(HeroAttrsComp);
let hero = HeroInfo[uuid]; // 共用英雄数据 // 从配置表获取怪物静态数据
// 设置 View 层属性(表现相关) let hero = HeroInfo[uuid];
// 视图层参数:朝向与碰撞阵营
view.scale = scale; view.scale = scale;
view.box_group = BoxSet.MONSTER; view.box_group = BoxSet.MONSTER;
// 设置 Model 层属性 基础属性 // 模型层参数:身份、阵营、基础数值
model.hero_uuid = uuid; model.hero_uuid = uuid;
model.hero_name = hero.name; model.hero_name = hero.name;
model.hp = model.hp_max = hero.hp; model.hp = model.hp_max = hero.hp;
model.ap = hero.ap; model.ap = hero.ap;
model.speed = hero.speed; // 使用成长后的速度 model.speed = hero.speed;
model.type = hero.type; model.type = hero.type;
model.fac = FacSet.MON; model.fac = FacSet.MON;
// 标记是否 Boss非 Boss 默认记作杂兵
model.is_boss =is_boss model.is_boss =is_boss
if(!model.is_boss){ if(!model.is_boss){
model.is_kalami = true; model.is_kalami = true;
} }
// 构建技能表并注入运行时冷却字段 ccd
model.skills = {}; model.skills = {};
for (const key in hero.skills) { for (const key in hero.skills) {
const skill = hero.skills[key]; const skill = hero.skills[key];
if (!skill) continue; if (!skill) continue;
model.skills[skill.uuid] = { ...skill, ccd: 0 }; // 最终技能等级 = 初始技能等级 + 怪物等级增量,且下限为 0
model.skills[skill.uuid] = { ...skill, lv: Math.max(0,skill.lv + mon_lv - 2), ccd: 0 };
} }
// 缓存技能射程等派生数据,减少战斗帧内重复计算
model.updateSkillDistanceCache(); model.updateSkillDistanceCache();
//根据刷怪控制脚本对ap和hp进行加强
// 注册视图组件并重置对象池复用状态
this.add(view); this.add(view);
// 重置视图状态(对象池复用时必须)
view.init(); view.init();
// 广播怪物加载事件,供刷怪与战斗系统联动
oops.message.dispatchEvent("monster_load",this) oops.message.dispatchEvent("monster_load",this)
// 初始化移动参数,包括线路和生成顺序 // 初始化移动参数:方向、目标 X、站位基准 Y
const move = this.get(MoveComp); const move = this.get(MoveComp);
move.reset(); move.reset();
move.direction = -1; // 向左移动 move.direction = -1;
move.targetX = Math.max(-320, Math.min(320, pos.x)); move.targetX = Math.max(-320, Math.min(320, pos.x));
move.baseY = dropToY; move.baseY = dropToY;
move.moving = false; move.moving = false;
// 依据下落距离自适应入场时长,确保观感一致
const dropDistance = Math.abs(pos.y - dropToY); const dropDistance = Math.abs(pos.y - dropToY);
const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200)); const dropDuration = Math.max(0.18, Math.min(0.38, dropDistance / 1200));
// 停止旧动画后执行下落 tween避免复用节点时动画叠加
Tween.stopAllByTarget(node); Tween.stopAllByTarget(node);
tween(node) tween(node)
.to(dropDuration, { position: v3(pos.x, dropToY, 0) }) .to(dropDuration, { position: v3(pos.x, dropToY, 0) })
.call(() => { .call(() => {
if (!node || !node.isValid) return; if (!node || !node.isValid) return;
// 落地后锁定最终位置,切换到落地完成状态
node.setPosition(pos.x, dropToY, 0); node.setPosition(pos.x, dropToY, 0);
view.playEnd("down"); view.playEnd("down");
move.moving = true; move.moving = true;
// 落地后启用怪物碰撞分组
if (collider) { if (collider) {
collider.enabled = true; collider.enabled = true;
collider.group = BoxSet.MONSTER; collider.group = BoxSet.MONSTER;
@@ -180,27 +215,31 @@ export class Monster extends ecs.Entity {
} }
}) })
.start(); .start();
// 维护关卡内怪物数量统计
smc.vmdata.mission_data.mon_num++ smc.vmdata.mission_data.mon_num++
} }
/** 重置入口:复用 destroy 的释放流程 */
reset() { reset() {
// 注: 自定义释放逻辑,视图层实现 ecs.IComp 接口的 ecs 组件需要手动释放
super.destroy(); super.destroy();
} }
} }
/** 怪物生命周期系统:监听实体进入与移除并输出调试日志 */
@ecs.register('MonLifecycleSystem') @ecs.register('MonLifecycleSystem')
export class MonLifecycleSystem extends ecs.ComblockSystem export class MonLifecycleSystem extends ecs.ComblockSystem
implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem { implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
debugMode: boolean = false; // 是否启用调试模式 /** 调试开关,控制系统日志输出 */
debugMode: boolean = false;
/** 仅处理拥有 MoveComp 的实体 */
filter() { filter() {
return ecs.allOf(MoveComp); return ecs.allOf(MoveComp);
} }
/** 实体进入世界时记录日志 */
entityEnter(e: ecs.Entity): void { entityEnter(e: ecs.Entity): void {
// 怪物实体创建时的特殊处理
const heroAttrs = e.get(HeroAttrsComp); const heroAttrs = e.get(HeroAttrsComp);
if (heroAttrs) { if (heroAttrs) {
mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物进入世界: ${heroAttrs.hero_name}`); mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物进入世界: ${heroAttrs.hero_name}`);
@@ -209,8 +248,8 @@ export class MonLifecycleSystem extends ecs.ComblockSystem
} }
} }
/** 实体离开世界时记录日志 */
entityRemove(e: ecs.Entity): void { entityRemove(e: ecs.Entity): void {
// 怪物实体销毁时的清理工作
const heroAttrs = e.get(HeroAttrsComp); const heroAttrs = e.get(HeroAttrsComp);
if (heroAttrs) { if (heroAttrs) {
mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物离开世界: ${heroAttrs.hero_name}`); mLogger.log(this.debugMode, 'MonLifecycleSystem', `怪物离开世界: ${heroAttrs.hero_name}`);