You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 09:45:43