如何正确移除关联射线检测且超出屏幕的游戏对象?
动态创建/销毁带射线检测的汽车对象时的引用清理问题
我在主游戏类中实现了createCar方法,用于动态创建汽车对象,并遍历已有汽车互相映射射线检测(使汽车可检测彼此距离):
createCar(scene, x, y, angle, speed, name) { const car = new Car(scene, x, y, angle, speed); car.name = name; // 调试用 this.carsGroup.children.iterate((c) => { c.raycaster.mapGameObjects(car, true); car.raycaster.mapGameObjects(c, true); }); this.carsGroup.add(car); }
这段逻辑运行正常,但删除超出屏幕的汽车时出现问题,当前删除逻辑如下:
update() { this.carsGroup.children.iterate((car) => { // 判断汽车是否超出屏幕 if (!this.cameras.main.worldView.contains(car.x, car.y)) { this.carsGroup.remove(car); this.carsGroup.children.iterate((c) => { c.raycaster.removeMappedObjects(car); car.raycaster.removeMappedObjects(c); }); car.destroy(); } else { car.update(); car.debug(); } }); }
执行删除操作时触发错误,内部尝试获取raycasterMap并销毁时失败:
object.data.get('raycasterMap').destroy();
具体报错信息:
raycaster-core.js:396 Uncaught TypeError: Cannot read properties of undefined (reading 'destroy') at Raycaster.removeMappedObjects (raycaster-core.js:396:48) at game.js:51:23
若直接调用car.destroy(),其他汽车会因射线检测仍保留对该汽车的引用而抛出异常,我无法找到正确从场景和内存中移除汽车的方法。
问题分析与修复方案
错误根源
- 遍历组时直接修改组:在
this.carsGroup.children.iterate循环中直接调用this.carsGroup.remove(car),会导致迭代过程中数组结构变化,可能出现遍历不完整或对象引用异常。 - 无效对象的射线清理操作:移除汽车后再调用
car.raycaster.removeMappedObjects(c),此时car的部分内部资源可能已经开始释放,导致raycasterMap无法被正常获取。
修复代码
修改update方法,先收集待删除汽车,再批量清理引用并销毁:
update() { // 第一步:收集所有需要删除的汽车 const carsToRemove = []; this.carsGroup.children.iterate((car) => { if (!this.cameras.main.worldView.contains(car.x, car.y)) { carsToRemove.push(car); } else { car.update(); car.debug(); } }); // 第二步:批量处理删除与引用清理 carsToRemove.forEach(car => { // 清理其他汽车射线检测中对当前汽车的映射 this.carsGroup.children.iterate((c) => { if (c !== car) { c.raycaster.removeMappedObjects(car); } }); // 清理当前汽车射线检测中的所有映射(无需逐个遍历,直接清空) car.raycaster.removeMappedObjects(); // 从组中移除并销毁汽车 this.carsGroup.remove(car); car.destroy(); }); }
额外优化建议
- 确认
raycaster.removeMappedObjects()无参数时是否会清空所有映射对象(根据报错的raycaster库API,通常支持此用法),这样可以避免逐个遍历其他汽车,提升效率。 - 检查
Car类的destroy方法,确保内部已正确清理raycaster相关资源;若未实现,可在car.destroy()前手动调用car.raycaster.destroy()(如果库支持该方法)。
内容的提问来源于stack exchange,提问作者Vololodymyr
相关产品推荐
相关产品推荐

