cocos-js 的事件监听(学习)

本文详细介绍了Cocos2d-x游戏引擎中事件监听和对象缓冲池的使用方法,包括如何添加触摸事件监听器、自定义事件以及对象缓冲池的实现方式,旨在优化内存管理和提高游戏性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单方法的事件添加:

cc.eventManager.addLisener({

event: cc.Event.Lisener.Touch_One_By_one;

        onTouchBegin:function(touch,event){

            if(cc.rectContainsPoint(event.getCurrentTarget().boundingBox(),touch.getLocation()))

            {}

},

       onTouchBegin:function(touch,evnet){

}

       onTouchBegin:function(touch,evnet){

}

},this.Srite);


自定义事件:

对象缓冲池:

cc.pool的使用方法,节省内存

<think>我们正在处理的是Cocos引擎中删除相机时出现的TypeError:Cannotreadpropertiesofnull(reading'on')错误。根据用户提供的信息,错误发生在requestAnimationFrame回调中,这表明我们可能在动画帧回调中尝试访问已经被销毁的相机对象。从之前的历史回答中,我们已经知道:-删除相机后,相机对象会被销毁,变为null-如果requestAnimationFrame回调中仍然引用这个相机,就会抛出这个错误解决思路:1.在删除相机前,取消注册requestAnimationFrame回调。2.在requestAnimationFrame回调中检查相机对象是否仍然有效。具体步骤:###1.确保在销毁相机前停止动画循环如果你使用了`requestAnimationFrame`,那么在销毁相机的时候,必须取消这个回调。通常我们会使用一个标志来控制循环,或者在销毁前取消动画帧请求。例如:```javascript//在类的定义中updateCamera(){//假设这个函数会在每一帧调用if(!this.camera||!cc.isValid(this.camera)){//如果相机已经被销毁,则停止这个循环return;}//...使用相机的逻辑}startCameraLoop(){//保存animationframe的idthis._animationFrameId=requestAnimationFrame(()=>{this.updateCamera();});}stopCameraLoop(){if(this._animationFrameId){cancelAnimationFrame(this._animationFrameId);this._animationFrameId=null;}}//在销毁相机的代码中onDestroy(){this.stopCameraLoop();//其他销毁逻辑if(this.camera){this.camera.destroy();this.camera=null;}}```###2.在requestAnimationFrame回调中检查相机有效性如上例所示,在`updateCamera`函数中,我们首先检查相机对象是否存在以及`cc.isValid`(该函数检查对象是否未被销毁)。###3.使用cc.isValid判断对象有效性Cocos提供了`cc.isValid`函数,可以判断一个对象是否已经被销毁。注意:在Cocos中,销毁的对象并不会立即变成null,而是被标记为销毁,但变量仍然指向一个非null的值(此时调用对象的方法会导致错误)。因此,不能简单地用`if(this.camera)`来判断,而应该使用`cc.isValid`。所以,在回调中,我们应该这样写:```javascriptif(cc.isValid(this.camera)){//安全的操作}```###4.完整示例下面是一个更完整的示例,展示如何安全地删除相机并避免错误:```javascriptcc.Class({extends:cc.Component,properties:{camera:{default:null,type:cc.Camera}},onLoad(){this._animationFrameId=null;this.startCameraLoop();},startCameraLoop(){constupdate=()=>{this._animationFrameId=requestAnimationFrame(update);this.updateCamera();};this._animationFrameId=requestAnimationFrame(update);},stopCameraLoop(){if(this._animationFrameId!==null){cancelAnimationFrame(this._animationFrameId);this._animationFrameId=null;}},updateCamera(){//检查相机是否有效if(!cc.isValid(this.camera)){//如果相机已经销毁,停止循环this.stopCameraLoop();return;}//正常更新相机的逻辑//this.camera.someMethod();},//示例:一个删除相机的方法deleteCamera(){//先停止循环this.stopCameraLoop();if(cc.isValid(this.camera)){this.camera.destroy();this.camera=null;}},onDestroy(){this.stopCameraLoop();if(cc.isValid(this.camera)){this.camera.destroy();this.camera=null;}}});```###5.使用Cocos内置的update函数另外,如果使用的是Cocos的`update`函数(即每帧调用的函数),则无需手动控制循环,但是同样需要在`update`中检查相机有效性,并在销毁时停止使用。###总结这个错误通常是因为在相机销毁后,动画回调还在尝试访问相机对象。解决方法是:1.在销毁前停止动画循环2.在回调函数中检查相机对象是否有效按照上述步骤,应该可以解决这个错误。§§相关问题§§1.如何在CocosCreator中正确使用requestAnimationFrame?2.如何避免在Cocos中被销毁对象的空引用问题?3.Cocos中的cc.isValid()和普通的null检查有什么区别?4.在CocosCreator中销毁对象的最佳实践是什么?</think> ### Cocos引擎中删除相机时"requestAnimationFrame回调导致TypeError"的解决方案 您在Cocos引擎中遇到的`Uncaught TypeError: Cannot read properties of null (reading 'on')`错误结合`requestAnimationFrame`回调,表明存在**动画帧回调持续访问已销毁对象**的问题。根据请求动画帧的执行机制[^1]和引用[2]的调试经验,以下是完整解决方案: --- #### 核心问题分析 ```mermaid sequenceDiagram participant Main as 主线程 participant RAF as requestAnimationFrame队列 participant Camera as 相机对象 Main->>Camera: camera.destroy() activate Camera Camera-->>Main: 对象标记为null deactivate Camera RAF->>Camera: 尝试访问已销毁的相机 Camera-->>RAF: 抛出TypeError(Cannot read 'on' of null) ``` 根本原因是:**requestAnimationFrame回调未随相机销毁同步清除**,导致下一帧仍尝试访问已移除的对象。 --- #### 解决方案(分步实施) 1. **在销毁前清除动画帧回调** 在销毁相机前强制清理所有相关回调: ```javascript destroyCamera() { // 优先取消动画帧回调 if (this._frameHandler) { cancelAnimationFrame(this._frameHandler); this._frameHandler = null; } // 检查相机有效性后销毁 if (cc.isValid(this.camera)) { this.camera.node.destroy(); this.camera = null; // 显式解除引用 } } ``` 2. **在回调中添加防御性检查** 在所有访问相机的代码段前进行对象存活验证: ```javascript updateFrame() { // 前置安全校验(关键!) if (!cc.isValid(this.camera)) { return; // 相机不存在时跳过后续操作 } // 安全使用相机对象 const projection = this.camera.getProjectionMatrix(); // 递归注册下一帧回调 this._frameHandler = requestAnimationFrame(() => this.updateFrame()); } ``` 3. **使用对象有效性封装层** 创建安全访问层处理可能为空的对象: ```javascript safeCameraCall(callback) { return cc.isValid(this.camera) ? callback(this.camera) : null; } // 使用示例 this.safeCameraCall(cam => { cam.on(cc.Camera.EVENT_RENDER_POST, this.postEffect, this); }); ``` --- #### 错误场景重现及调试方法 ```javascript // ⚠️ 危险代码:没有销毁保护的动画循环 startCameraLoop() { this._frameHandler = requestAnimationFrame(() => { // 直接访问相机属性 ↓ 引发崩溃 this.camera.renderScene(); this.startCameraLoop(); }); } // ✅ 修正方案:增加销毁标记位 startCameraLoop() { if (this._isCameraDestroyed) return; // 终止条件 this._frameHandler = requestAnimationFrame(() => { if (!cc.isValid(this.camera)) { this._isCameraDestroyed = true; return; } this.camera.renderScene(); this.startCameraLoop(); }); } ``` > **调试工具推荐**: > 1. Cocos Creator调试器的**对象存活检查**(`cc.isValid()`) > 2. Chrome DevTools的**内存快照对比** > 3. 在`requestAnimationFrame`入口添加日志点: > ```javascript > console.log('[RAF] Camera valid:', cc.isValid(this.camera)); > ``` --- #### 最佳实践总结 1. **销毁顺序原则**: ``` 取消事件监听 → 停止动画帧 → 销毁对象 → 解除引用 ``` 2. **使用引用封装**: ```typescript interface SafeCamera { valid: boolean; ref: cc.Camera | null; invoke: (fn: (cam: cc.Camera) => void) => void; } ``` 3. **利用引擎生命周期**: 在`onDestroy()`中统一清理资源: ```javascript onDestroy() { cancelAnimationFrame(this._frameHandler); this.camera?.targetTexture?.destroy(); this.camera = null; } ``` > 注意:Cocos的`requestAnimationFrame`使用HTML5标准API,回调执行独立于引擎生命周期管理[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值