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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 03:40:35