Phaser3切换场景后音乐异常及销毁音乐报错问题求助
问题分析与解决方案
核心错误点
事件重复绑定
你在update函数里绑定PointerDown事件,而update是每帧执行的方法,这会导致每次刷新都给文本元素添加新的事件监听。点击一次"New game"会触发多次startGame,场景切换逻辑混乱,这也是移除菜单音乐后问题仍存在的根本原因。音乐处理不当
直接调用this.music.destroy()报错,是因为重复触发的事件会多次执行destroy,第一次销毁后this.music变为null,后续调用就会抛出"Cannot read properties of null"的错误。同时,菜单音乐未停止就切换场景,会和游戏场景音乐叠加,导致播放异常。
修复步骤
1. 把事件监听移到create方法中
create方法只在场景初始化时执行一次,不会重复绑定事件:
public create(): void { super.create(); this.newGameText = this.add .text(+this.game.config.width / 2, +this.game.config.height / 2 - 72, "New game", { fontSize: "72px", color: "#fff" }) .setOrigin(0.5, 0.5) .setInteractive() .on(Keys.MouseEvents.PointerDown, () => this.startGame()); // 直接在创建时绑定事件 this.exitGameText = this.add .text(+this.game.config.width / 2, +this.game.config.height / 2 + 72, "Exit game", { fontSize: "72px", color: "#fff" }) .setOrigin(0.5, 0.5) .setInteractive() .on(Keys.MouseEvents.PointerDown, () => this.exitGame()); // 直接绑定事件 this.music = this.sound.add(Keys.Musics.MainMenu, { loop: true }); this.music.play(); } // 清空update里的事件绑定代码,保留必要逻辑即可 public update(time: number, delta: number): void { super.update(time, delta); }
2. 正确处理场景切换时的音乐
切换场景前停止菜单音乐,避免叠加;如果需要释放资源,建议用场景生命周期钩子shutdown来处理,确保只执行一次:
private startGame(): void { this.scene.start(Keys.Scenes.Game); } // 重写场景的shutdown方法,在场景关闭时处理音乐 public shutdown(): void { super.shutdown(); if (this.music?.isPlaying) { this.music.stop(); this.music.destroy(); // 这里destroy只会执行一次,不会报错 } }
如果不想用生命周期钩子,也可以在startGame里安全停止音乐:
private startGame(): void { if (this.music?.isPlaying) { this.music.stop(); // 若不需要立即释放资源,可不用destroy,Phaser会在场景销毁时自动处理 // this.music.destroy(); } this.scene.start(Keys.Scenes.Game); }
验证效果
修改后,点击"New game"只会触发一次场景切换,菜单音乐正常停止,游戏场景音乐可以正常播放,也不会再出现destroy报错的问题。
内容的提问来源于stack exchange,提问作者Robouste
相关产品推荐
相关产品推荐

