refactor(skill): 重构碰撞上限处理与伤害派发逻辑

- 将碰撞上限处理抽离为独立的 handle_collision_limit 方法
- 移除 apply_damage 方法中冗余的销毁逻辑,使职责更清晰
- 优化注释以更准确描述组件职责与关键逻辑
- 添加生命周期保护标记,避免销毁阶段重复处理
This commit is contained in:
panw
2026-03-16 11:40:38 +08:00
parent 4db8788589
commit 5a630b4de5

View File

@@ -10,7 +10,7 @@ import { mLogger } from "../common/Logger";
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
/** 视图层对象 */ /** 技能视图组件:负责碰撞窗口、碰撞回调与伤害派发 */
@ccclass('SkillView') @ccclass('SkillView')
@ecs.register('SkillView', false) @ecs.register('SkillView', false)
export class SkillView extends CCComp { export class SkillView extends CCComp {
@@ -31,7 +31,7 @@ export class SkillView extends CCComp {
private collider: Collider2D = null; // 缓存碰撞体引用 private collider: Collider2D = null; // 缓存碰撞体引用
private pendingDisableCollider: boolean = false; private pendingDisableCollider: boolean = false;
private isDisposing: boolean = false; private isDisposing: boolean = false;
// 已命中目标追踪,防止重复伤害 // 生命周期保护标记,避免在销毁阶段重复处理碰撞
init() { init() {
this.SConf = SkillSet[this.s_uuid] this.SConf = SkillSet[this.s_uuid]
this.sData = this.ent.get(SDataCom) this.sData = this.ent.get(SDataCom)
@@ -75,13 +75,14 @@ export class SkillView extends CCComp {
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) {
this.close_collider(); this.handle_collision_limit();
return; return;
} }
this.sData.hit_count++; this.sData.hit_count++;
if (this.sData.hit_count >= this.sData.max_hit_count) { if (this.sData.hit_count >= this.sData.max_hit_count) {
this.close_collider(); this.handle_collision_limit();
} }
// 命中次数按碰撞事件统计:不依赖是否最终造成伤害
// 不是 HeroViewComp直接忽略 // 不是 HeroViewComp直接忽略
if (!targetView) return; if (!targetView) return;
// 🔥 方案A防御性检查 - 在获取model前强制检查ent是否存在 // 🔥 方案A防御性检查 - 在获取model前强制检查ent是否存在
@@ -99,12 +100,13 @@ export class SkillView extends CCComp {
} }
onAnimationFinished(){ onAnimationFinished(){
// animationEnd 类型:动画结束后再关闭碰撞并销毁
if(this.SConf.EType==EType.animationEnd){ if(this.SConf.EType==EType.animationEnd){
this.disable_collider_now(); this.disable_collider_now();
this.ent.destroy() this.ent.destroy()
} }
} }
// //动画帧事件 atk 触发 // 动画帧事件 atk:仅负责开启一帧碰撞窗口,不负责伤害与计数
public atk(args:any){ public atk(args:any){
if(!this.SConf) return; if(!this.SConf) return;
if(this.SConf.EType==EType.collision) return if(this.SConf.EType==EType.collision) return
@@ -117,7 +119,7 @@ export class SkillView extends CCComp {
}, 0); }, 0);
} }
} }
//伤害应用 // 仅负责伤害派发,不处理命中次数与实体销毁
apply_damage(target:HeroViewComp,is_range:boolean=false){ apply_damage(target:HeroViewComp,is_range:boolean=false){
if(target == null) return; if(target == null) return;
// 安全检查:如果目标实体已不存在,直接返回 // 安全检查:如果目标实体已不存在,直接返回
@@ -138,19 +140,6 @@ export class SkillView extends CCComp {
this.sData.ext_dmg, this.sData.ext_dmg,
this.sData.dmg_ratio, this.sData.dmg_ratio,
); );
if (
(this.SConf.DTType != DTType.range) &&
(this.SConf.EType != EType.animationEnd) &&
(this.SConf.EType != EType.timeEnd)
) {
// 修复:物理回调中不能直接销毁刚体,需延迟到下一帧
this.close_collider();
this.scheduleOnce(() => {
if (this.ent) {
this.ent.destroy();
}
}, 0);
}
} }
close_collider(){ close_collider(){
if (!this.collider) return; if (!this.collider) return;
@@ -165,6 +154,18 @@ export class SkillView extends CCComp {
this.isDisposing = true; this.isDisposing = true;
this.close_collider(); this.close_collider();
} }
// 碰撞上限收口先关碰撞collision 类型再延迟销毁实体
private handle_collision_limit() {
this.close_collider();
if (this.SConf?.EType !== EType.collision) return;
if (this.isDisposing) return;
this.isDisposing = true;
this.scheduleOnce(() => {
if (this.ent) {
this.ent.destroy();
}
}, 0);
}
private enable_collider_safely(): boolean { private enable_collider_safely(): boolean {
if (!this.collider || !this.collider.isValid) return false; if (!this.collider || !this.collider.isValid) return false;
if (this.isDisposing) return false; if (this.isDisposing) return false;