fix(skill): 修复技能碰撞检测逻辑和组件初始化问题
- 在Skill.ts中确保节点激活并添加SkillView组件缺失的错误处理 - 修复SkillView中碰撞体启用/禁用逻辑,避免同一帧内重复触发伤害 - 增加pendingDisableCollider标志防止异步操作中的竞争条件 - 完善组件重置逻辑,正确清理事件监听和定时器 - 修复动画事件监听可能重复绑定的问题
This commit is contained in:
@@ -99,11 +99,17 @@ export class Skill extends ecs.Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
node.parent = skillParent;
|
node.parent = skillParent;
|
||||||
|
node.active = true;
|
||||||
// 设置节点属性
|
// 设置节点属性
|
||||||
let face=caster.node.scale.x < 0 ? -1 : 1
|
let face=caster.node.scale.x < 0 ? -1 : 1
|
||||||
node.setScale(v3(node.scale.x*face,node.scale.y,1))
|
node.setScale(v3(node.scale.x*face,node.scale.y,1))
|
||||||
// 初始视图
|
// 初始视图
|
||||||
const SView = node.getComponent(SkillView);
|
const SView = node.getComponent(SkillView);
|
||||||
|
if (!SView) {
|
||||||
|
mLogger.error(this.debugMode, 'Skill', "[Skill] SkillView 组件缺失:", path);
|
||||||
|
if (node.isValid) node.destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(config.EType!=EType.collision){
|
if(config.EType!=EType.collision){
|
||||||
const collider=node.getComponent(BoxCollider2D);
|
const collider=node.getComponent(BoxCollider2D);
|
||||||
if(collider){
|
if(collider){
|
||||||
@@ -163,6 +169,7 @@ export class Skill extends ecs.Entity {
|
|||||||
sDataCom.s_uuid=s_uuid
|
sDataCom.s_uuid=s_uuid
|
||||||
sDataCom.fac=cAttrsComp.fac
|
sDataCom.fac=cAttrsComp.fac
|
||||||
sDataCom.ext_dmg=ext_dmg
|
sDataCom.ext_dmg=ext_dmg
|
||||||
|
SView.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 模块资源释放 */
|
/** 模块资源释放 */
|
||||||
|
|||||||
@@ -30,27 +30,27 @@ export class SkillView extends CCComp {
|
|||||||
sData:SDataCom=null;
|
sData:SDataCom=null;
|
||||||
s_uuid:number=1001
|
s_uuid:number=1001
|
||||||
private collider: Collider2D = null; // 缓存碰撞体引用
|
private collider: Collider2D = null; // 缓存碰撞体引用
|
||||||
|
private pendingDisableCollider: boolean = false;
|
||||||
private attackFrameCount: number = 0; // 攻击帧计数器
|
private attackFrameCount: number = 0; // 攻击帧计数器
|
||||||
private maxAttackFrames: number = 1; // 最大攻击帧数,可配置
|
private maxAttackFrames: number = 1; // 最大攻击帧数,可配置
|
||||||
// 已命中目标追踪,防止重复伤害
|
// 已命中目标追踪,防止重复伤害
|
||||||
start() {
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
this.anim = this.node.getComponent(Animation)
|
this.anim = this.node.getComponent(Animation)
|
||||||
this.node.active = true;
|
this.node.active = true;
|
||||||
|
this.pendingDisableCollider = false;
|
||||||
this.collider = this.getComponent(Collider2D);
|
this.collider = this.getComponent(Collider2D);
|
||||||
if(this.collider) {
|
if(this.collider) {
|
||||||
this.collider.group = this.group;
|
this.collider.group = this.group;
|
||||||
|
this.collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||||||
this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||||||
this.collider.enabled = true; // 确保复用时开启
|
this.collider.enabled = this.SConf?.EType === EType.collision;
|
||||||
}
|
}
|
||||||
if(this.node.getComponent(Animation)){
|
if(this.node.getComponent(Animation)){
|
||||||
let anim = this.node.getComponent(Animation);
|
let anim = this.node.getComponent(Animation);
|
||||||
mLogger.log(this.debugMode, 'SkillView', "[SkillCom]:has anim",anim)
|
mLogger.log(this.debugMode, 'SkillView', "[SkillCom]:has anim",anim)
|
||||||
|
anim.off(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
||||||
anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
||||||
|
|
||||||
// 对象池复用时,需要手动播放默认动画(因为 Play On Load 只在首次生效)
|
// 对象池复用时,需要手动播放默认动画(因为 Play On Load 只在首次生效)
|
||||||
@@ -74,6 +74,7 @@ export class SkillView extends CCComp {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (oCol.group === seCol.group) return;
|
if (oCol.group === seCol.group) return;
|
||||||
|
if (this.pendingDisableCollider) return;
|
||||||
// 不是 HeroViewComp,直接忽略
|
// 不是 HeroViewComp,直接忽略
|
||||||
if (!targetView) return;
|
if (!targetView) return;
|
||||||
// 🔥 方案A:防御性检查 - 在获取model前强制检查ent是否存在
|
// 🔥 方案A:防御性检查 - 在获取model前强制检查ent是否存在
|
||||||
@@ -101,6 +102,7 @@ export class SkillView extends CCComp {
|
|||||||
|
|
||||||
// 开启碰撞检测
|
// 开启碰撞检测
|
||||||
if(this.collider) {
|
if(this.collider) {
|
||||||
|
this.pendingDisableCollider = false;
|
||||||
this.collider.enabled = true;
|
this.collider.enabled = true;
|
||||||
mLogger.log(this.debugMode, 'SkillView', `[SkillView] [${this.SConf?.name}] 第${this.attackFrameCount}次攻击帧开启碰撞检测`);
|
mLogger.log(this.debugMode, 'SkillView', `[SkillView] [${this.SConf?.name}] 第${this.attackFrameCount}次攻击帧开启碰撞检测`);
|
||||||
}
|
}
|
||||||
@@ -121,7 +123,7 @@ export class SkillView extends CCComp {
|
|||||||
// 对于非持续碰撞类型的技能,在造成伤害后立即关闭碰撞检测
|
// 对于非持续碰撞类型的技能,在造成伤害后立即关闭碰撞检测
|
||||||
// 这样可以避免同一帧内的重复伤害
|
// 这样可以避免同一帧内的重复伤害
|
||||||
if(this.SConf.EType !== EType.collision && this.collider) {
|
if(this.SConf.EType !== EType.collision && this.collider) {
|
||||||
this.collider.enabled = false;
|
this.close_collider();
|
||||||
mLogger.log(this.debugMode, 'SkillView', `[SkillView] [${this.SConf.name}] 伤害后关闭碰撞检测`);
|
mLogger.log(this.debugMode, 'SkillView', `[SkillView] [${this.SConf.name}] 伤害后关闭碰撞检测`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,17 +159,26 @@ export class SkillView extends CCComp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
close_collider(){
|
close_collider(){
|
||||||
if (this.collider) {
|
if (!this.collider || this.pendingDisableCollider) return;
|
||||||
this.collider.enabled = false;
|
this.pendingDisableCollider = true;
|
||||||
}
|
this.scheduleOnce(() => {
|
||||||
|
if (this.collider && this.collider.isValid) {
|
||||||
|
this.collider.enabled = false;
|
||||||
|
}
|
||||||
|
this.pendingDisableCollider = false;
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||||
reset() {
|
reset() {
|
||||||
// 清理碰撞体事件监听
|
// 清理碰撞体事件监听
|
||||||
if (this.collider) {
|
if (this.collider) {
|
||||||
this.collider.off(Contact2DType.BEGIN_CONTACT);
|
this.collider.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||||||
this.collider.enabled = false;
|
this.collider.enabled = false;
|
||||||
}
|
}
|
||||||
|
this.pendingDisableCollider = false;
|
||||||
|
if (this.anim) {
|
||||||
|
this.anim.off(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
||||||
|
}
|
||||||
// 取消所有定时器
|
// 取消所有定时器
|
||||||
this.unscheduleAllCallbacks();
|
this.unscheduleAllCallbacks();
|
||||||
if (this.node && this.node.isValid) {
|
if (this.node && this.node.isValid) {
|
||||||
|
|||||||
Reference in New Issue
Block a user