Phaser 3重复调用.launch()时同类别场景重复创建问题求助
Phaser 3 + Socket.io 多人游戏场景重复实例问题
我正在用Phaser 3结合Socket.io开发一款类似马里奥派对的多人游戏,包含多个小游戏,小游戏之间由问答环节分隔。需求是房主可以选择小游戏,玩家参与游玩,且房主再次选择时可重玩该小游戏,但首次游玩后再次加载时会创建多个同类别场景实例,导致玩家端场景实例指数级增长,分数混乱。
场景加载流程
房主客户端场景顺序:
- 主页面(选择成为房主或玩家)
- 房主页面(等待玩家加入)
- 小游戏选择器(房主选择小游戏)
- 小游戏1房主端(示例中选择小游戏1)
- 小游戏选择器(重新加载)
- 小游戏1房主端(再次选择小游戏1)
- 小游戏选择器
玩家客户端场景顺序:
- 主页面
- 玩家页面(在大厅等待房主启动游戏)
- 玩家中间场景(等待房主选择小游戏)
- 小游戏1玩家端(房主选择后所有玩家进入该场景)
- 玩家中间场景
- 小游戏1玩家端×2(再次加载时同时出现2个实例,导致分数混乱)
- 玩家中间场景×2(错误呈指数级增长,再次加载会使分数更混乱,场景实例更多)
已确认问题与Socket.io事件重复触发无关,直接在玩家端启动场景也会出现相同错误。
已尝试的解决方法
- 仅使用
.launch()和.stop()启停场景 - 使用条件语句和变量阻止重复启动
- 在场景开始时清除定时器间隔
- 使用
.remove()彻底销毁场景后再用.add()重新添加到管理器 - 使用
this.events.once()确保仅触发一次
相关代码
房主小游戏场景
class minigame1Host extends Phaser.Scene { constructor() { super('mg1Host'); } create() { clearInterval(this.countdown) this.socket = this.registry.get("socket") this.val = this.registry.get("pin") let { width, height } = this.sys.game.canvas; this.timeLimit = 15 this.doneCheck = null this.timeText = this.add.text(width/2,height/2-200,this.timeLimit).setScale(2) this.countdown = setInterval(() => { this.timeLimit = this.timeLimit - 1 this.timeText.text = String(this.timeLimit) if (this.timeLimit == 0) { if(this.doneCheck != true) { this.doneCheck = true clearInterval(this.countdown) this.scene.launch("selector").stop() } } }, 1000); } update() { //some code to generate a random value for enemy spawning } }
玩家小游戏场景
class minigame1Player extends Phaser.Scene { constructor() { super('mg1Player'); } create() { clearInterval(this.countdown) this.socket = this.registry.get("socket") this.val = this.registry.get("pin") let { width, height } = this.sys.game.canvas; this.timeLimit = 15 this.score = 0 //create groups for scorers (a scorer is something a player can click to get points) this.goodScorers = this.add.group() this.badScorers = this.add.group() this.timeText = this.add.text(width/2,height/2-460,this.timeLimit).setScale(2) this.scoreText = this.add.text(width/2-200,height/2-100,this.score).setScale(2) this.doneCheck = false this.countdown = setInterval(() => { this.timeLimit = this.timeLimit - 1 this.timeText.text = String(this.timeLimit) if (this.timeLimit == 0) { if(this.doneCheck != true) { this.goodScorers.destroy() this.badScorers.destroy() this.doneCheck = true clearInterval(this.countdown) clearTimeout(this.deleteBadAfter) clearTimeout(this.deleteGoodAfter) score = score + this.score this.scene.launch("tempPlayer").stop() } } }, 1000); this.socket.on("createScorer" ,(values) => { //code that creates scorers }) } }
小游戏选择器
class pickMinigameHost extends Phaser.Scene { constructor() { super('selector'); } create() { this.socket = this.registry.get("socket") this.val = this.registry.get("pin") let { width, height } = this.sys.game.canvas; this.add.text(width/2, height/2, "Pick a minigame:") this.mg1But = this.add.image(width/2,height/2-300,"dissButton").setInteractive().setScale(0.5) this.mouseCheck = false this.mg1But.on('pointerdown', () => { if(this.mouseCheck == false) { this.mouseCheck = true this.socket.emit("startMG1", [this.val]); this.scene.launch("mg1Host").stop() } }) } }
临时玩家场景
class temporaryPlayer extends Phaser.Scene { constructor() { super('tempPlayer'); } create() { clearInterval(this.countdown) this.socket = this.registry.get("socket") let { width, height } = this.sys.game.canvas; this.add.text(width/2, height/2, "A Minigame is being selected") this.socket.on("startMg1Comp" ,() => { this.scene.launch("mg1Player").stop() }) } }
注:所有代码均为客户端代码,我认为服务器无问题,抱歉代码质量不佳,若问题简单还请见谅。
内容的提问来源于stack exchange,提问作者adoge
相关产品推荐
相关产品推荐

