Phaser3多人游戏开发:如何跨文件监听WebSocket的onmessage事件?
如何在Phaser 3的mainScene.js中获取Socket.js里WebSocket接收的数据
你已经在Socket.js中实现了WebSocket的基础连接和消息接收逻辑,下面提供几种实用的方式,让你能在mainScene.js中获取并处理这些收到的数据:
方法一:通过回调函数注册消息处理器
这种方式简单直接,允许你在mainScene中自定义消息处理逻辑,Socket.js收到消息后直接调用该逻辑。
修改Socket.js:
let websocket; const url = "wss://abc/dev"; // 存储外部注册的消息回调函数 let messageCallback = null; export const socketInit = () => { websocket = new WebSocket(url); websocket.onopen = (evt) => onOpen(evt); websocket.onclose = (evt) => onClose(evt); websocket.onmessage = (evt) => onMessage(evt); websocket.onerror = (evt) => onError(evt); }; // 新增:允许外部注册消息处理回调 export const registerMessageCallback = (callback) => { messageCallback = callback; }; export const sendMessage = (message) => { console.log("SENT: " + JSON.stringify(message)); websocket.send(JSON.stringify(message)); }; const onOpen = (evt) => { if (websocket.readyState === 1) { console.log("WEBSOCKET CONNECTED"); } }; const onClose = (evt) => { console.log("CLOSE", evt); }; const onMessage = (evt) => { console.log(evt.data); // 若有注册的回调,直接传递数据 if (messageCallback) { try { // 解析JSON格式消息(适配多数服务端返回格式) const parsedData = JSON.parse(evt.data); messageCallback(parsedData); } catch (err) { // 处理非JSON格式的原始消息 messageCallback(evt.data); } } }; const onError = (evt) => { console.log("Error", evt); websocket.close(); };
在mainScene.js中使用:
import { socketInit, registerMessageCallback, sendMessage } from './Socket.js'; export default class MainScene extends Phaser.Scene { constructor() { super('MainScene'); } preload() { // 初始化WebSocket连接 socketInit(); // 注册消息处理回调 registerMessageCallback((data) => { console.log('MainScene收到WebSocket消息:', data); // 调用自定义逻辑处理消息 this.handleSocketData(data); }); } handleSocketData(data) { // 根据消息类型处理游戏逻辑 switch(data.type) { case 'playerMove': // 更新其他玩家位置 break; case 'gameStart': // 触发游戏开始流程 break; // 其他消息类型的处理逻辑 } } // 示例:发送游戏消息到服务端 sendPlayerPosition(x, y) { sendMessage({ type: 'playerMove', x: x, y: y }); } }
方法二:使用Phaser事件发射器(贴合Phaser生态)
利用Phaser内置的EventEmitter,让Socket.js作为事件发布者,mainScene作为订阅者,这种方式更符合Phaser的开发习惯,解耦效果更好。
修改Socket.js:
import Phaser from 'phaser'; let websocket; const url = "wss://abc/dev"; // 创建事件发射器实例,供外部订阅 export const socketEmitter = new Phaser.Events.EventEmitter(); export const socketInit = () => { websocket = new WebSocket(url); websocket.onopen = (evt) => onOpen(evt); websocket.onclose = (evt) => onClose(evt); websocket.onmessage = (evt) => onMessage(evt); websocket.onerror = (evt) => onError(evt); }; export const sendMessage = (message) => { console.log("SENT: " + JSON.stringify(message)); websocket.send(JSON.stringify(message)); }; const onOpen = (evt) => { if (websocket.readyState === 1) { console.log("WEBSOCKET CONNECTED"); // 触发连接成功事件 socketEmitter.emit('socket-connected'); } }; const onClose = (evt) => { console.log("CLOSE", evt); socketEmitter.emit('socket-closed', evt); }; const onMessage = (evt) => { console.log(evt.data); try { const parsedData = JSON.parse(evt.data); // 触发消息事件,携带解析后的数据 socketEmitter.emit('socket-message', parsedData); } catch (err) { socketEmitter.emit('socket-message', evt.data); } }; const onError = (evt) => { console.log("Error", evt); socketEmitter.emit('socket-error', evt); websocket.close(); };
在mainScene.js中使用:
import { socketInit, socketEmitter, sendMessage } from './Socket.js'; export default class MainScene extends Phaser.Scene { constructor() { super('MainScene'); } preload() { socketInit(); // 订阅WebSocket消息事件 socketEmitter.on('socket-message', (data) => { console.log('MainScene收到消息:', data); this.handleSocketData(data); }); // 可选:订阅连接状态相关事件 socketEmitter.on('socket-connected', () => { console.log('WebSocket连接成功,启动游戏逻辑'); }); socketEmitter.on('socket-error', (err) => { console.error('WebSocket出错:', err); }); } handleSocketData(data) { if (data.type === 'playerJoin') { // 添加新玩家到游戏场景 } } // 场景销毁时移除事件监听,避免内存泄漏 destroy() { socketEmitter.off('socket-message'); socketEmitter.off('socket-connected'); socketEmitter.off('socket-error'); super.destroy(); } }
方法三:直接导出WebSocket实例(不推荐)
这种方式虽然简单,但会破坏Socket层的封装性,仅适合小型测试项目:
修改Socket.js:
// 将websocket改为export export let websocket; const url = "wss://abc/dev"; export const socketInit = () => { websocket = new WebSocket(url); // 其他原有逻辑保持不变 }; // 其他函数代码不变
在mainScene.js中使用:
import { socketInit, websocket } from './Socket.js'; export default class MainScene extends Phaser.Scene { preload() { socketInit(); // 等待连接建立后监听消息 websocket.onopen = () => { websocket.onmessage = (evt) => { const data = JSON.parse(evt.data); console.log('收到消息:', data); // 处理游戏逻辑 }; }; } }
总结
优先推荐方法二(Phaser事件发射器),它既符合Phaser的开发模式,又能很好地解耦Socket层与游戏场景层,便于后续维护和扩展;方法一适合小型项目,实现成本低;方法三仅适合快速测试,不推荐用于正式项目。
内容的提问来源于stack exchange,提问作者Ratandeep Arunkumar
相关产品推荐
相关产品推荐

