From 5d55f3bdb1297c93b00010499e92c2b85c529b67 Mon Sep 17 00:00:00 2001 From: pan Date: Tue, 21 Jul 2026 16:33:52 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E6=A0=BC=E5=BC=8F=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=B9=B6=E4=BF=AE=E5=A4=8D=E4=BB=A3=E7=A0=81=E9=A3=8E?= =?UTF-8?q?=E6=A0=BC=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次提交主要对HeroAttrsComp和HeroViewComp两个文件进行了代码风格统一优化: 1. 统一变量声明的空格规范,修复类型标注前后的空格问题 2. 修正函数参数默认值的空格格式 3. 调整空行和注释的排版一致性 4. 修复字符串类型标注的大小写问题 5. 新增等级变更脏标记和对应的UI显示逻辑 6. 优化了部分条件判断和逻辑代码的可读性 --- assets/script/game/hero/HeroAttrsComp.ts | 78 ++++--- assets/script/game/hero/HeroViewComp.ts | 285 ++++++++++++----------- 2 files changed, 193 insertions(+), 170 deletions(-) diff --git a/assets/script/game/hero/HeroAttrsComp.ts b/assets/script/game/hero/HeroAttrsComp.ts index 4c24f29a..a47c99f1 100644 --- a/assets/script/game/hero/HeroAttrsComp.ts +++ b/assets/script/game/hero/HeroAttrsComp.ts @@ -13,7 +13,7 @@ export class HeroAttrsComp extends ecs.Comp { private static readonly percentRateThreshold = 1; private static readonly minAttackCd = 0.05; - Ebus:any=null! + Ebus: any = null! // ==================== 角色基础信息 ==================== hero_uuid: number = 1001; hero_name: string = "hero"; @@ -42,7 +42,7 @@ export class HeroAttrsComp extends ecs.Comp { [SkillTriggerType.FEnd]?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; [SkillTriggerType.Atking]?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; [SkillTriggerType.Atked]?: { s_uuid: number; t_num: number; overrides?: SkillOverrides }[]; - [SkillTriggerType.Revive]?: {s_uuid: number, r_num: number, upr: number}; + [SkillTriggerType.Revive]?: { s_uuid: number, r_num: number, upr: number }; // ==================== 特殊属性 ==================== critical: number = 0; // 暴击率 @@ -64,20 +64,21 @@ export class HeroAttrsComp extends ecs.Comp { frost_end_time: number = 0; stun_end_time: number = 0; - + boom: boolean = false; // 自爆怪 // ==================== 脏标签标记 ==================== dirty_hp: boolean = false; // 血量变更标记 dirty_shield: boolean = false; // 护盾变更标记 + dirty_lv: boolean = false; // 等级变更标记 // ==================== 技能距离缓存 ==================== maxSkillDistance: number = 0; // 最远技能攻击距离(缓存,受MP影响) minSkillDistance: number = 0; // 最近技能攻击距离(缓存,不受MP影响,用于停止位置判断) - + // ==================== 阵型位置 ==================== posIndex: number = -1; - + // ==================== 标记状态 ==================== is_dead: boolean = false; is_count_dead: boolean = false; @@ -92,10 +93,10 @@ export class HeroAttrsComp extends ecs.Comp { // ==================== 计数统计 ==================== atk_count: number = 0; // 攻击次数 atked_count: number = 0; // 被攻击次数 - killed_count:number=0; + killed_count: number = 0; combat_target_eid: number = -1; enemy_in_cast_range: boolean = false; - start(){ + start() { } // ==================== BUFF 系统初始化 ==================== /** @@ -108,7 +109,7 @@ export class HeroAttrsComp extends ecs.Comp { } /*******************基础属性管理********************/ - add_hp(value:number){ + add_hp(value: number) { const oldHp = this.hp; let addValue = value; this.hp += addValue; @@ -119,7 +120,7 @@ export class HeroAttrsComp extends ecs.Comp { } return addValue; } - add_shield(value:number){ + add_shield(value: number) { const oldShield = this.shield; const addValue = Math.max(0, Math.floor(value)); if (addValue <= 0) return; @@ -131,15 +132,15 @@ export class HeroAttrsComp extends ecs.Comp { mLogger.log(this.debugMode, 'HeroAttrs', ` 护盾次数变更: ${this.hero_name}, 变化=${addValue}, ${Math.floor(oldShield)} -> ${Math.floor(this.shield)}`); } } - add_hp_max(value:number){ - this.hp_max+=value - this.hp+=value + add_hp_max(value: number) { + this.hp_max += value + this.hp += value this.dirty_hp = true; // ✅ 仅标记需要更新 return value } - add_ap(value:number){ - this.ap +=value + add_ap(value: number) { + this.ap += value return value } @@ -151,7 +152,7 @@ export class HeroAttrsComp extends ecs.Comp { add_special_attr(attr_type: Attrs, value: number) { // 利用枚举值(字符串)与类属性名一致的特性,动态访问并累加属性 const key = attr_type as keyof this; - + // 确保目标属性存在且类型为数字,避免运行时错误 if (typeof this[key] === 'number') { (this as any)[key] += value; @@ -163,15 +164,15 @@ export class HeroAttrsComp extends ecs.Comp { } - toFrost(time: number=1) { + toFrost(time: number = 1) { const frostTime = FightSet.FROST_TIME * time; this.frost_end_time = Math.max(this.frost_end_time, frostTime); } - - toStun(time: number=1) { + + toStun(time: number = 1) { const stunTime = FightSet.STUN_TIME * time; this.stun_end_time = Math.max(this.stun_end_time, stunTime); - + // 击晕时 CD 清零 for (const key in this.skills) { const skill = this.skills[key]; @@ -180,11 +181,11 @@ export class HeroAttrsComp extends ecs.Comp { } } } - - updateCD(dt: number){ + + updateCD(dt: number) { // 如果处于冰冻状态,则技能 CD 暂停刷新 if (this.isFrost()) return; - + // 如果处于击晕状态,则技能 CD 暂停刷新(且保持清零状态) if (this.isStun()) { for (const key in this.skills) { @@ -195,7 +196,7 @@ export class HeroAttrsComp extends ecs.Comp { } return; } - + for (const key in this.skills) { const skill = this.skills[key]; if (!skill) continue; @@ -344,7 +345,7 @@ export class HeroAttrsComp extends ecs.Comp { this.maxSkillDistance = maxRange; this.minSkillDistance = minRange; } - + /** * 获取缓存的最远技能攻击距离 * @returns 最远攻击距离 @@ -352,7 +353,7 @@ export class HeroAttrsComp extends ecs.Comp { public getCachedMaxSkillDistance(): number { return this.maxSkillDistance; } - + /** * 获取缓存的最近技能攻击距离 * @returns 最近攻击距离 @@ -376,7 +377,7 @@ export class HeroAttrsComp extends ecs.Comp { this.speed = 100; this.dis = 100; this.shield = 0; - + // 重置新增属性 this.skills = {}; this.call = undefined; @@ -401,16 +402,16 @@ export class HeroAttrsComp extends ecs.Comp { this.puncture_chance = 0; this.wfuny = 0; this.boom = false; - + this.frost_end_time = 0; this.stun_end_time = 0; // 重置技能距离缓存 this.maxSkillDistance = 0; this.minSkillDistance = 0; - + this.posIndex = -1; - + this.is_dead = false; this.is_count_dead = false; this.is_atking = false; @@ -420,37 +421,38 @@ export class HeroAttrsComp extends ecs.Comp { this.is_friend = false; this.is_kalami = false; this.is_reviving = false; - + this.atk_count = 0; this.atked_count = 0; - this.killed_count =0; + this.killed_count = 0; this.combat_target_eid = -1; this.enemy_in_cast_range = false; // 重置脏标签 this.dirty_hp = false; this.dirty_shield = false; + this.dirty_lv = false; } } @ecs.register('HeroBuffSystem') export class HeroBuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate { - private timer =new Timer(0.1) + private timer = new Timer(0.1) filter(): ecs.IMatcher { return ecs.allOf(HeroAttrsComp); } update(e: ecs.Entity): void { - if(this.timer.update(this.dt)){ + if (this.timer.update(this.dt)) { const attrsComp = e.get(HeroAttrsComp); - if(attrsComp.frost_end_time > 0){ + if (attrsComp.frost_end_time > 0) { attrsComp.frost_end_time -= 0.1; - if(attrsComp.frost_end_time <= 0){ + if (attrsComp.frost_end_time <= 0) { attrsComp.frost_end_time = 0; } } - if(attrsComp.stun_end_time > 0){ + if (attrsComp.stun_end_time > 0) { attrsComp.stun_end_time -= 0.1; - if(attrsComp.stun_end_time <= 0){ + if (attrsComp.stun_end_time <= 0) { attrsComp.stun_end_time = 0; } } @@ -459,5 +461,5 @@ export class HeroBuffSystem extends ecs.ComblockSystem implements ecs.ISystemUpd } } - + diff --git a/assets/script/game/hero/HeroViewComp.ts b/assets/script/game/hero/HeroViewComp.ts index 642663f8..bfd3bbee 100644 --- a/assets/script/game/hero/HeroViewComp.ts +++ b/assets/script/game/hero/HeroViewComp.ts @@ -1,11 +1,11 @@ -import { Vec3, _decorator , v3,Collider2D,Contact2DType,Label ,Node,Prefab,instantiate,ProgressBar, Component, Material, Sprite, math, clamp, Game, tween, Tween, Color, BoxCollider2D, UITransform, UIOpacity, NodeEventType} from "cc"; +import { Vec3, _decorator, v3, Collider2D, Contact2DType, Label, Node, Prefab, instantiate, ProgressBar, Component, Material, Sprite, math, clamp, Game, tween, Tween, Color, BoxCollider2D, UITransform, UIOpacity, NodeEventType } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { mLogger } from "../common/Logger"; import { HeroSpine } from "./HeroSpine"; import { BoxSet, FacSet, FightSet, NumberFormatter, TooltipTypes } from "../common/config/GameSet"; import { smc } from "../common/SingletonModuleComp"; -import { SkillSet,} from "../common/config/SkillSet"; +import { SkillSet, } from "../common/config/SkillSet"; import { HeroInfo } from "../common/config/heroSet"; import { oops } from "db://oops-framework/core/Oops"; import { UIID } from "../common/config/GameUIConfig"; @@ -32,20 +32,21 @@ export class HeroViewComp extends CCComp { // ==================== View 层属性(表现相关)==================== as: HeroSpine = null! - status:String = "" + status: String = "" scale: number = 1; // 显示方向 - box_group:number = BoxSet.HERO; // 碰撞组 - realDeadTime:number=0.1 - deadCD:number=0 - monDeadTime:number=0.1 - hp_height:number=70 - boss_hp_height:number=120 + box_group: number = BoxSet.HERO; // 碰撞组 + realDeadTime: number = 0.1 + deadCD: number = 0 + monDeadTime: number = 0.1 + hp_height: number = 70 + boss_hp_height: number = 140 // 血条显示相关 - lastBarUpdateTime:number = 0; // 最后一次血条/蓝条/护盾更新时间 + lastBarUpdateTime: number = 0; // 最后一次血条/蓝条/护盾更新时间 // ==================== UI 节点引用 ==================== private top_node: Node = null!; private topOpacity: UIOpacity = null!; private topBasePos: Vec3 = v3(); + private lvLabel: Label | null = null; // 等级显示文本 private readonly barIdleOpacity: number = 153; private readonly barActiveOpacity: number = 255; private readonly idleOpacityDelay: number = 0.25; @@ -73,34 +74,34 @@ export class HeroViewComp extends CCComp { onLoad() { this.as = this.getComponent(HeroSpine); const collider = this.node.getComponent(BoxCollider2D); - this.scheduleOnce(()=>{ + this.scheduleOnce(() => { if (collider) { collider.enabled = true; // 先禁 collider.group = this.box_group; // 设置为英雄组 } - },0.1) + }, 0.1) // let anm = this.node.getChildByName("anm") // anm.setScale(anm.scale.x*0.8,anm.scale.y*0.8); - + // 绑定点击事件,点击打开英雄信息面板弹窗 this.node.on(NodeEventType.TOUCH_END, this.onHeroClicked, this); } - + private onHeroClicked() { if (!this.model) return; if (this.model.fac !== FacSet.HERO) return; oops.audio.playEffect("music/button"); - + const eid = this.ent?.eid; if (!eid) return; - + oops.gui.remove(UIID.HInfo); oops.gui.open(UIID.HInfo, { eid: eid }); } /** 视图层逻辑代码分离演示 */ - start () { + start() { this.init(); } @@ -110,25 +111,28 @@ export class HeroViewComp extends CCComp { this.deadCD = 0; this.lastBarUpdateTime = 0; this.status_change("idle"); - + // 初始化 UI 节点 this.initUINodes(); - + /** 方向 */ - this.node.setScale(this.scale*Math.abs(this.node.scale.x), 1*this.node.scale.y); // 确保 scale.x 为正后再乘方向 - this.top_node.setScale(this.scale*this.top_node.scale.x,1*this.top_node.scale.y); + this.node.setScale(this.scale * Math.abs(this.node.scale.x), 1 * this.node.scale.y); // 确保 scale.x 为正后再乘方向 + this.top_node.setScale(this.scale * this.top_node.scale.x, 1 * this.top_node.scale.y); /* 显示角色血*/ this.top_node.getChildByName("hp").active = true; this.top_node.getChildByName("cd").active = false; this.top_node.getChildByName("shield").active = false; - this.top_node.getChildByName("lv").active = false; + this.top_node.getChildByName("lv").active = true; this.top_node.active = true; this.setTopBarOpacity(false); - + + // 初始化等级显示 + this.lv_show(); + // 🔥 重置血条 UI 显示状态 if (this.model) { this.hp_show(); - + // 根据英雄模型中的等级数据设置描边 // 注意:HeroViewComp 是挂在 node 上的,而 FlashSprite 可能挂在子节点(如 Sprite/anm 节点) let flashSprite = this.node.getComponent(FlashSprite); @@ -136,53 +140,59 @@ export class HeroViewComp extends CCComp { // 如果当前节点没有,尝试在所有子节点中查找 flashSprite = this.node.getComponentInChildren(FlashSprite); } - + if (flashSprite) { flashSprite.setOutlineByLevel(this.model.lv); } } } - + /** 初始化 UI 节点引用 */ private initUINodes() { this.top_node = this.node.getChildByName("top"); this.topOpacity = this.top_node.getComponent(UIOpacity) || this.top_node.addComponent(UIOpacity); this.top_node.setPosition(0, this.hp_height, 0); - if(this.model.is_boss) this.top_node.setPosition(0, this.boss_hp_height, 0); + if (this.model.is_boss) this.top_node.setPosition(0, this.boss_hp_height, 0); this.topBasePos = this.top_node.position.clone(); const hpNode = this.top_node.getChildByName("hp"); - if(this.model.fac==FacSet.HERO){ - hpNode.getChildByName("Bar").getComponent(Sprite).color=new Color("#2ECC71") + if (this.model.fac == FacSet.HERO) { + hpNode.getChildByName("Bar").getComponent(Sprite).color = new Color("#2ECC71") } - + // 确保血条等UI始终在最上层显示 this.top_node.setSiblingIndex(999); + + // 缓存等级显示 Label(lv 节点下的 Label 子节点) + const lvNode = this.top_node.getChildByName("lv"); + if (lvNode) { + this.lvLabel = lvNode.getChildByName("Label")?.getComponent(Label) ?? null; + } } - + /** * View 层每帧更新 * 注意:数据更新逻辑已移到 HeroAttrSystem,这里只负责显示 */ - update(dt: number){ - if(!smc.mission.play ) return; - if(smc.mission.pause) return + update(dt: number) { + if (!smc.mission.play) return; + if (smc.mission.pause) return // 🔥 修复:添加安全检查,防止在实体销毁过程中访问null的model - if(!this.ent) return; + if (!this.ent) return; if (!this.model) return; this.processDamageQueue(); - if(this.model.is_dead){ - this.deadCD+=dt - if(this.deadCD>=this.realDeadTime){ - this.deadCD=0 + if (this.model.is_dead) { + this.deadCD += dt + if (this.deadCD >= this.realDeadTime) { + this.deadCD = 0 this.realDead() - } + } return - } ; + }; // ✅ 按需更新 UI(脏标签模式)- 只在属性变化时更新 if (this.model.dirty_hp) { @@ -195,10 +205,15 @@ export class HeroViewComp extends CCComp { this.show_shield(this.model.shield); this.model.dirty_shield = false; } + + if (this.model.dirty_lv) { + this.lv_show(); + this.model.dirty_lv = false; + } } - - public cd_show(){ - return; + + public cd_show() { + return; } /** 显示护盾 */ @@ -206,15 +221,15 @@ export class HeroViewComp extends CCComp { this.lastBarUpdateTime = Date.now() / 1000; this.node.getChildByName("shielded").active = shield > 0; } - + /** 显示血量 */ private hp_show() { this.lastBarUpdateTime = Date.now() / 1000; // 不再基于血量是否满来决定显示状态,只更新进度条 - let hp=this.model.hp; - let hp_max=this.model.hp_max; + let hp = this.model.hp; + let hp_max = this.model.hp_max; // mLogger.log(this.debugMode, 'HeroViewComp', "hp_show",hp,hp_max) - + let targetProgress = hp_max > 0 ? hp / hp_max : 0; targetProgress = clamp(targetProgress, 0, 1); let hpNode = this.top_node.getChildByName("hp"); @@ -237,6 +252,12 @@ export class HeroViewComp extends CCComp { return this.model.hp >= this.model.hp_max; } + /** 更新等级显示 */ + private lv_show() { + if (!this.lvLabel || !this.model) return; + this.lvLabel.string = String(this.model.lv); + } + private setTopBarOpacity(isActive: boolean) { if (!this.top_node || !this.top_node.isValid) return; if (this.topOpacity) { @@ -269,13 +290,13 @@ export class HeroViewComp extends CCComp { }) .start(); } - + /** 升级特效 */ public lv_up() { this.spawnTimedFx("game/skill/buff/buff_lvup", this.node, 1.0); - + // 升级时同步更新描边 if (this.model) { let flashSprite = this.node.getComponent(FlashSprite); @@ -287,12 +308,12 @@ export class HeroViewComp extends CCComp { } } } - + /** 攻击力提升特效 */ private ap_up() { this.spawnTimedFx("game/skill/buff/buff_apup", this.node, 1.0); } - + /** 受击特效 */ private in_atked(anm: string = "atked", scale: number = 1) { @@ -304,24 +325,24 @@ export class HeroViewComp extends CCComp { // node.setPosition(this.node.position.x, this.node.position.y+50, this.node.position.z); // node.parent = this.node.parent; } - + /** 冰冻特效 */ in_iced(t: number = 1) { this.spawnTimedFx("game/skill/buff/iced", this.node, t); } - + /** 击晕特效 */ in_stun(t: number = 1) { this.spawnTimedFx("game/skill/buff/stun", this.node, t); } - + /** 技能提示 */ private tooltip(type: number = 1, value: string = "", s_uuid: number = 1001, y: number = 50) { let pos = v3(0, 60); pos.y = pos.y + y; Tooltip.load(pos, type, value, s_uuid, this.node); } - /** 技能提示 */ + /** 技能提示 */ public skill_name(value: string = "", s_uuid: number = 1001, triggerType: string = "", y: number = 50) { let pos = v3(0, 60); pos.y = pos.y + y; @@ -336,7 +357,7 @@ export class HeroViewComp extends CCComp { if (transform) { halfHeight = transform.height / 2; } - + // 起点设为怪物中心偏下位置,使其在血条下方 let ny = this.node.position.y + halfHeight - 15; let pos = v3(x, ny, 0); @@ -347,30 +368,30 @@ export class HeroViewComp extends CCComp { shield_tip(absorbed: number) { this.hp_tip(TooltipTypes.life, NumberFormatter.formatNumber(Math.max(0, Math.floor(absorbed)))); } - public playBuff(anm: string = ""){ - if(anm==="") return; + public playBuff(anm: string = "") { + if (anm === "") return; var path = "game/skill/buff/" + anm; this.spawnTimedFx(path, this.node, this.effectLifeTime); } - public playReady(anm: string = ""){ - if(anm==="") return; + public playReady(anm: string = "") { + if (anm === "") return; var path = "game/skill/ready/" + anm; this.spawnAnimEndFx(path, this.node, undefined); } - public playOther(anm: string = ""){ - if(anm==="") return; + public playOther(anm: string = "") { + if (anm === "") return; var path = "game/skill/ready/" + anm; // 以自身当前位置为基准,挂载到父节点,即使自身节点销毁动画也能继续播放 this.spawnAnimEndFx(path, this.node.parent, this.node.position); - } - public playEnd(anm: string = ""){ - if(anm==="") return; + } + public playEnd(anm: string = "") { + if (anm === "") return; var path = "game/skill/end/" + anm; this.spawnAnimEndFx(path, this.node, undefined); } - public playAllTime(anm: string = ""){ - if(anm==="") return; + public playAllTime(anm: string = "") { + if (anm === "") return; var path = "game/skill/buff/" + anm; // 常驻特效直接创建节点,不挂载生命周期销毁组件,随父节点(this.node)一起销毁 this.createFxNode(path, this.node, undefined); @@ -379,7 +400,7 @@ export class HeroViewComp extends CCComp { private heathed() { this.spawnAnimEndFx("game/skill/buff/heathed", this.node, undefined); } - private deaded(){ + private deaded() { this.spawnAnimEndFx("game/skill/end/dead", this.node.parent, this.node.position); } private createFxNode(path: string, parent: Node | null, worldPos?: Vec3): Node | null { @@ -409,51 +430,51 @@ export class HeroViewComp extends CCComp { } // 注意:BaseUp 逻辑已移到 HeroAttrSystem.update() // 注意:updateTemporaryBuffsDebuffs 逻辑已移到 HeroAttrSystem.update() - + get isActive() { return this.ent.has(HeroViewComp) && this.node?.isValid; } /** 状态切换(动画) */ - status_change(type:string){ - if(this.status === type) return; + status_change(type: string) { + if (this.status === type) return; this.status = type; - if(this.model.is_dead || this.model.is_reviving) return - if(type === "idle"){ + if (this.model.is_dead || this.model.is_reviving) return + if (type === "idle") { this.as.idle(); - } else if(type === "move"){ + } else if (type === "move") { this.as.move(); } } - add_shield(shield:number){ + add_shield(shield: number) { // 护盾数据更新由 Model 层处理,这里只负责视图表现 - if(this.model && this.model.shield>0) this.show_shield(this.model.shield); + if (this.model && this.model.shield > 0) this.show_shield(this.model.shield); } - + health(hp: number = 0) { // ✅ 仅显示特效和提示,不调用 hp_show() - if(hp<=20) return; + if (hp <= 20) return; this.heathed(); this.hp_tip(TooltipTypes.health, hp.toFixed(0)); this.lastBarUpdateTime = Date.now() / 1000; } - - alive(){ + + alive() { // 重置复活标记 - 必须最先重置,否则status_change会被拦截 this.model.is_reviving = false; - this.model.is_dead=false - this.model.is_count_dead=false + this.model.is_dead = false + this.model.is_count_dead = false this.deadCD = 0; - + // 恢复碰撞体 const collider = this.node.getComponent(Collider2D); if (collider) { collider.enabled = true; } - + // 恢复UI this.top_node.active = true; - + this.status_change("idle"); // 【新增】仅英雄阵营派发复活成功事件,供卡牌技能(HeroCall 类型)监听 @@ -462,26 +483,26 @@ export class HeroViewComp extends CCComp { oops.message.dispatchEvent(GameEvent.ReviveSuccess, { eid: this.ent.eid }); } } - + /** * 死亡视图表现 * 由 HeroAtkSystem 调用,只负责视觉效果和事件通知 */ - do_dead(){ + do_dead() { // 添加安全检查 if (!this.model) return; - + // 防止重复触发 - if(this.model.is_count_dead) return; + if (this.model.is_count_dead) return; this.model.is_count_dead = true; // 防止重复触发,必须存在防止重复调用 - + // 怪物使用0.5秒死亡时间,英雄使用realDeadTime - if(this.model.fac === FacSet.MON){ + if (this.model.fac === FacSet.MON) { this.realDeadTime = this.monDeadTime; } - + // 如果角色带有死亡触发技能,则由 SCastSystem 播放 playReady("dead") if (this.model && this.model.dead && this.model.dead.length > 0) { // SCastSystem will handle the "dead" ready animation @@ -490,26 +511,26 @@ export class HeroViewComp extends CCComp { this.deaded(); } } - realDead(){ + realDead() { // 🔥 修复:添加model安全检查,防止实体销毁过程中的空指针异常 if (!this.model) { mLogger.warn(this.debugMode, 'HeroViewComp', "[HeroViewComp] realDead called but model is null, skipping"); return; } - + // 隐藏UI this.top_node.active = false; - + // 在销毁实体前先禁用碰撞体,从源头减少"尸体"参与碰撞 const collider = this.node.getComponent(Collider2D); if (collider) { collider.enabled = false; } - + // 根据阵营决定飞出方向:英雄向左(负),怪物向右(正) let isHero = this.model.fac === FacSet.HERO; let dirX = isHero ? -800 : 800; - + // 死亡往后飞出屏幕动画 tween(this.node) .by(0.5, { position: v3(dirX, 700, 0) }, { easing: "quadOut" }) @@ -524,55 +545,55 @@ export class HeroViewComp extends CCComp { }) .start(); } - do_atked(damage:number,isCrit:boolean,s_uuid:number,isBack:boolean=false){ + do_atked(damage: number, isCrit: boolean, s_uuid: number, isBack: boolean = false) { // 受到攻击时更新最后更新时间 this.activateTopBar(); this.lastBarUpdateTime = Date.now() / 1000; - + if (damage <= 0) return; - + // 播放受击音效 if (isCrit) { oops.audio.playEffect("music/Critical"); } else { oops.audio.playEffect("music/Hit"); } - + // 视图层表现 - let SConf=SkillSet[s_uuid] - const hitAnm = SConf?.DAnm|| "atked"; - if (isBack) this.back() - this.in_atked(hitAnm, this.model.fac==FacSet.HERO?1:-1); + let SConf = SkillSet[s_uuid] + const hitAnm = SConf?.DAnm || "atked"; + if (isBack) this.back() + this.in_atked(hitAnm, this.model.fac == FacSet.HERO ? 1 : -1); this.showDamage(damage, isCrit); } - + private isBackingUp: boolean = false; // 🔥 添加后退状态标记 - + //后退 - back(distance: number = 0){ + back(distance: number = 0) { // 🔥 防止重复调用后退动画 if (this.isBackingUp) return; this.isBackingUp = true; // 🔥 设置后退状态 - if(this.model.fac==FacSet.MON) { + if (this.model.fac == FacSet.MON) { // 基础击退距离,加上额外的距离强化 let dist = FightSet.BACK_RANG + distance; - let tx=this.node.position.x + dist; - if(tx > 320) tx=320; + let tx = this.node.position.x + dist; + if (tx > 320) tx = 320; tween(this.node) - .to(0.1, { position:v3(tx,this.node.position.y,0)}) + .to(0.1, { position: v3(tx, this.node.position.y, 0) }) .call(() => { this.isBackingUp = false; // 🔥 动画完成后重置状态 }) .start(); } - - if(this.model.fac==FacSet.HERO) { + + if (this.model.fac == FacSet.HERO) { let dist = 5 + distance; - let tx=this.node.position.x - dist; - if(tx < -320) tx=-320; + let tx = this.node.position.x - dist; + if (tx < -320) tx = -320; tween(this.node) - .to(0.1, { position:v3(tx,this.node.position.y,0)}) + .to(0.1, { position: v3(tx, this.node.position.y, 0) }) .call(() => { this.isBackingUp = false; // 🔥 动画完成后重置状态 }) @@ -581,11 +602,11 @@ export class HeroViewComp extends CCComp { } // 伤害计算和战斗逻辑已迁移到 HeroBattleSystem - - playSkillAnm(act:string="") { - mLogger.log(this.debugMode, 'HeroViewComp', '[heroview] act'+act,) - if (act==="") return; - switch(act){ + + playSkillAnm(act: string = "") { + mLogger.log(this.debugMode, 'HeroViewComp', '[heroview] act' + act,) + if (act === "") return; + switch (act) { case "max": this.as.max() break @@ -611,12 +632,12 @@ export class HeroViewComp extends CCComp { /** 处理伤害队列 */ private processDamageQueue() { if (this.isProcessingDamage || this.damageQueue.length === 0) return; - + this.isProcessingDamage = true; const damageInfo = this.damageQueue.shift()!; - + this.showDamageImmediate(damageInfo.damage, damageInfo.isCrit); - + // 设置延时处理下一个伤 this.scheduleOnce(() => { this.isProcessingDamage = false; @@ -626,7 +647,7 @@ export class HeroViewComp extends CCComp { /** 立即显示伤害效果 */ private showDamageImmediate(damage: number, isCrit: boolean) { if (!this.model) return; - + const damageText = NumberFormatter.formatNumber(Math.max(0, Math.floor(damage))); this.hp_show(); if (isCrit) { @@ -648,18 +669,18 @@ export class HeroViewComp extends CCComp { const collider = this.getComponent(Collider2D); if (collider) { collider.off(Contact2DType.BEGIN_CONTACT); - } - this.deadCD=0 - this.lastBarUpdateTime=0 + } + this.deadCD = 0 + this.lastBarUpdateTime = 0 this.unschedule(this.restoreBarIdleOpacity); // 清理伤害队列 this.damageQueue.length = 0; this.isProcessingDamage = false; - + // 解绑点击事件 this.node.off(NodeEventType.TOUCH_END, this.onHeroClicked, this); - + // 节点生命周期由 Monster 对象池管理,此处不再销毁 // if (this.node && this.node.isValid) { // this.node.destroy();