Phaser 3场景切换后客户端无法看到其他玩家移动的问题
问题根源与修复方案
核心问题
- 服务端未按场景广播移动事件:当前服务端所有玩家移动都广播
playerMoved,但第二场景客户端监听的是playerMoved2,完全收不到移动消息。 - 场景切换未更新用户位置信息:玩家切换场景时,服务端没有更新数据库中用户的
location字段,导致后续无法正确识别玩家所在场景。 - 客户端函数变量错误:
addOtherPlayer函数中使用全局this定义otherPlayer,导致添加其他玩家时出现作用域错误。 - 场景切换未清理旧玩家数据:切换场景后,旧场景的其他玩家没有被移除,可能导致混淆,但这不是移动不显示的直接原因。
具体修复步骤
1. 服务端修复:按场景分组广播移动事件
修改点:
- 新增场景切换的事件处理,更新用户的
location字段 - 修改
playerMovement事件,根据用户当前所在场景,广播对应场景的移动事件
io.on('connection', (socket) => { console.log('A user connected'); if (socket.handshake.session && socket.handshake.session.user) { const userId = socket.handshake.session.user.id; // 处理从场景1切换到场景2 socket.on('switchToScene2', async () => { try { await pool.query('UPDATE users SET location = 2 WHERE id = ?', [userId]); socket.emit('TriggerFirstScene'); // 可选:通知场景2其他玩家有新用户加入 const [userRow] = await pool.query('SELECT id, x_position, y_position FROM users WHERE id = ?', [userId]); socket.broadcast.emit('newPlayer2', [userRow[0]]); } catch (error) { console.error(error); } }); // 处理从场景2切换到场景1 socket.on('switchToScene1', async () => { try { await pool.query('UPDATE users SET location = 1 WHERE id = ?', [userId]); socket.emit('TriggerSecondScene'); const [userRow] = await pool.query('SELECT id, x_position, y_position FROM users WHERE id = ?', [userId]); socket.broadcast.emit('newPlayer', [userRow[0]]); } catch (error) { console.error(error); } }); // 修改playerMovement事件,按场景广播 socket.on('playerMovement', async (data) => { try { const { x, y } = data; await pool.query('UPDATE users SET x_position = ?, y_position = ? WHERE id = ?', [x, y, userId]); // 查询用户当前场景 const [rows] = await pool.query('SELECT location FROM users WHERE id = ?', [userId]); const location = rows[0].location; // 按场景广播对应移动事件 if (location === 1) { socket.broadcast.emit('playerMoved', { playerId: userId, x, y }); } else if (location === 2) { socket.broadcast.emit('playerMoved2', { playerId: userId, x, y }); } } catch (error) { console.error(error); } }); // 保留原有的createPlayer、createPlayer2等代码... } });
2. 客户端修复:修正场景切换逻辑与变量错误
修改点:
- 修复
addOtherPlayer函数的变量作用域问题 - 修正场景切换时的socket事件发送,调用服务端新增的切换事件
// 修复addOtherPlayer函数的变量作用域错误 function addOtherPlayer(self, players) { players.forEach((playerData) => { const existingPlayer = self.otherPlayers.getChildren().find((otherPlayer) => otherPlayer.playerId === playerData.id); if (!existingPlayer) { const otherPlayer = self.physics.add.sprite(playerData.x_position, playerData.y_position, 'player').setDisplaySize(100, 100); otherPlayer.playerId = playerData.id; self.otherPlayers.add(otherPlayer); } }); } // 修改FirstScene的场景切换触发逻辑 class FirstScene extends BaseScene { create() { super.create(); this.add.text(10, 10, 'LOCATION 1'); socket.emit('createPlayer'); socket.on('playerCreated', (playerData) => { addPlayer(this, playerData); this.trigger = this.add.rectangle(400, -12, 100, 100, 0xffffff).setDisplaySize(50, 50); this.physics.add.existing(this.trigger, true); this.physics.add.collider(this.player, this.trigger, () => { socket.emit('switchToScene2'); }); }); // 保留原有的playerMoved、newPlayer、TriggerFirstScene监听... } } // 修改SecondScene的场景切换触发逻辑 class SecondScene extends BaseScene { create() { super.create(); this.add.text(10, 10, 'LOCATION 2'); socket.emit('createPlayer2'); socket.on('playerCreated2', playerData => { addPlayer(this, playerData); this.trigger = this.add.rectangle(400, -12, 100, 100, 0xffffff).setDisplaySize(50, 50); this.physics.add.existing(this.trigger, true); this.physics.add.collider(this.player, this.trigger, () => { socket.emit('switchToScene1'); }); }); // 保留原有的playerMoved2、newPlayer2监听... } }
3. 可选优化:场景切换时清理旧玩家
在BaseScene的create方法中添加清理逻辑,避免跨场景玩家残留:
class BaseScene extends Phaser.Scene { constructor(key) { super({ key }); this.spawned = false; this.otherPlayers = {}; this.nicknames = {}; } create() { const self = this; this.cursors = this.input.keyboard.createCursorKeys(); // 清理之前场景的其他玩家 if (this.otherPlayers && this.otherPlayers.clear) { this.otherPlayers.clear(true, true); } this.otherPlayers = this.physics.add.group(); } // 保留原有的update方法... }
修复后逻辑说明
- 玩家切换场景时,客户端通知服务端更新数据库中的
location字段 - 服务端处理玩家移动时,先查询玩家当前场景,再广播对应场景的移动事件
- 客户端对应场景监听各自的移动事件,确保只接收当前场景玩家的移动消息
- 修复变量作用域错误,保证其他玩家能正确添加到场景中
内容的提问来源于stack exchange,提问作者Iya
相关产品推荐
相关产品推荐

