1. 程式人生 > >[egret+pomelo]實時遊戲雜記(3)

[egret+pomelo]實時遊戲雜記(3)

登錄 地址 ram tor 需求 app cts 分配 ges

[egret+pomelo]學習筆記(1)

[egret+pomelo]學習筆記(2)

[egret+pomelo]學習筆記(3)

服務端的請求流程走完了一遍,下面就該看一下,在目前的服務端中,各服務端所提供的功能了。

Gate:game-server/app/servers/gate/handler/gateHandler.js

queryEntry(msg,session,next):註冊服務端,返回分配的connector服務端地址

Connector:game-server/app/servers/connector/handler/entryHandler.js

entry(msg, session, next):服務端註冊session信息 返回玩家playerId
onUserLeave(app, session, reason):用戶離開或關閉鏈接

Area:game-server/app/servers/area/handler/playerHandler.js

enterScene(msg, session, next):玩家申請加入遊戲場景
getAnimation(msg, session, next):獲取玩家動畫數據
changeStage(msg, session, next):更改玩家狀態
move(msg, session, next):玩家移動

這裏還涉及到一個玩家離開場景事的調用game-server/app/servers/area/remote/playerRemote.js

技術分享圖片

目前服務端的使用已經很清晰了,要開始摒棄示例,可以開始自己的遊戲邏輯了。第一步要做的,就是借助pomelo的撿寶項目,讓多個玩家站在同一個場景中並顯示。

整理egret代碼

根據當前的服務端結構,創建服務器信息管理類network.Servers

技術分享圖片
module network {

    /**
     * 服務端信息
     */
    export class Servers {
        public constructor() {
        }

        /**
         * 服務端事件
         * currServerDisConnect:當前服務端關閉
         */
        public static events = {
            currServerDisConnect: 
"DISCONNECT_SUCCEED" } /** * Gate模塊 */ public static GATE = { KEY: "Server_GATE", info: { ip: "", port: "" }, handler: { queryEntry: "gate.gateHandler.queryEntry" }, events: { succeed: "CONNECTION_GATE_SUCCEED", error: "CONNECTION_GATE_ERROR" } }; /** * Connect 模塊操作 */ public static CONNECTION = { KEY: "Server_CONNECTION", info: { ip: "", port: "" }, handler: { entry: "connector.entryHandler.entry", onUserLeave: "connector.entryHandler.onUserLeave" }, events: { succeed: "CONNECTION_CONNECT_SUCCEED", error: "CONNECTION_CONNECT_ERROR" } }; /** * 遊戲場景服務器 */ public static AREA = { KEY: "Server_AREA", info: { ip: "", port: "" }, handler: { enterScene: "area.playerHandler.enterScene", getAnimation: "area.playerHandler.getAnimation", changeStage: "area.playerHandler.changeStage", move: "area.playerHandler.move" }, events: { succeed: "CONNECTION_AREA_SUCCEED", error: "CONNECTION_AREA_ERROR" } }; /** * 獲取模塊 * targetName:模塊的名稱 info/handler/events * key:模塊的key */ public static GetTargetByKey(targetName: string, key: string) { var target; switch (key) { case Servers.GATE.KEY: target = Servers.GATE; break; case Servers.CONNECTION.KEY: target = Servers.CONNECTION; break; case Servers.AREA.KEY: target = Servers.AREA; break; default: console.log("發現未知服務端[network/servers/]"); break; } if (target) { switch (targetName) { case "info": return target.info; case "handler": return target.handler; case "events": return target.events; default: console.log("發現未知服務數據[network/servers/]"); break; } } } } }
View Code

完善socket鏈接類 network.GameSocket

技術分享圖片
module network {
    /**
     * webSocket for pomelo
     */
    export class GameSocket {
        public constructor() {
        }
        static instance: GameSocket = new GameSocket();
        /**
         * 單例模式
         */
        static getInstance(): GameSocket {
            return GameSocket.instance;
        }

        private pomelo: Pomelo;
        /**
         * 當前正在操作的是服務端
         */
        private currServer: Object;
        /**
         * 服務端狀態 是否開啟
         */
        private running: boolean = false;
        /**
         * 初始化
         */
        init() {
            if (this.pomelo == null) {
                this.pomelo = new Pomelo();

                this.pomelo.on(‘server_push_message‘, (msg) => {
                    var route = msg["route"];
                    //根據服務端返回派發事件
                    Global.dispatchEvent("PomeloServerEvents_" + route, msg);
                });

                this.pomelo.on(‘onKick‘, (msg) => {
                    trace("onKick");
                });

                this.pomelo.on(‘heartbeat_timeout‘, () => {
                    trace("heartbeat_timeout");
                });

                this.pomelo.on(‘close‘, (e: CloseEvent) => {
                    trace(e.currentTarget["url"] + "的鏈接被斷開");
                });
            }
        }

        /**
         * 打開服務端 
         * @param server:需要打開的服務端
         * @param host:ip
         * @param port:端口
         * @param callback:回調函數
         * @param log:是否啟用日誌
         */
        open(server, callback?: Function, log: boolean = true) {
            //獲取服務端的設置
            var targetEventsInfo = Servers.GetTargetByKey("events", server.KEY);
            //初始化服務端
            this.pomelo.init({ host: server.info.ip, port: server.info.port, log: log }, false, (succeedRes) => {
                this.currServer = server;
                this.running = true;
                //派發服務端啟動成功事件
                Global.dispatchEvent(targetEventsInfo.succeed);
            }, (errRES) => {
                //派發服務端發生錯誤事件
                Global.dispatchEvent(targetEventsInfo.error);
            }, (closeRes) => {
                trace("一個服務端關閉完成。");
            }, null);
        }

        /**
         * 發起請求
         * @param route: 路由 (服務端處理函數)
         * @param msg:內容
         * @param callback:回調函數
         * @param thisArg:參數
         */
        request(route: string, msg: any, callback: Function, thisArg?: any): void {
            this.pomelo.request(route, msg, (response) => {
                callback.call(thisArg, response);
            });
        }

        /**
         * 通知
         */
        notify(route: string, msg: any): void {
            this.pomelo.notify(route, msg);
        }

        /**
         * 關閉當前服務
         */
        disconnect() {
            this.pomelo.disconnect();
            this.running = false;
            Global.dispatchEvent(Servers.events.currServerDisConnect, { currServer: this.currServer });
        }

        /**
         * 獲取當前的服務端
         */
        getCurrServer() {
            return this.currServer;
        }
        /**
         * 獲取當前的服務端狀態
         */
        isRunning(): boolean {
            return this.running;
        }
    }
}
View Code

之前例子中的PomeloTest變成

技術分享圖片
class PomeloTest {
    public constructor() {
        Global.addEventListener(network.Servers.GATE.events.succeed, this.onGateSucceed, this);
        Global.addEventListener(network.Servers.GATE.events.error, this.onGateError, this);
        Global.addEventListener(network.Servers.CONNECTION.events.succeed, this.onConnectSucceed, this);
        Global.addEventListener(network.Servers.CONNECTION.events.error, this.onConnectError, this);
    }

    connectGate() {
        network.GameSocket.getInstance().init();
        network.GameSocket.getInstance().open(network.Servers.GATE);
    }

    private onGateSucceed() {
        Global.addEventListener(network.Servers.events.currServerDisConnect, this.onGateClosed, this);

        network.GameSocket.getInstance().request("gate.gateHandler.queryEntry", { uid: "" }, this.onGateMsg);

        trace("Gate服務端鏈接成功");
    }

    private onGateError() {
        trace("Gate服務端鏈接失敗");
    }

    private onGateMsg(gate_data) {
        network.Servers.CONNECTION.info.ip=gate_data.host;
        network.Servers.CONNECTION.info.port=gate_data.port;
        network.GameSocket.getInstance().disconnect();
        trace("正在嘗試鏈接connect服務端...");
        network.GameSocket.getInstance().open(network.Servers.CONNECTION);
    }

    private onGateClosed() {
        trace("Gate服務端成功斷開鏈接");
        // trace("正在嘗試鏈接connect服務端...");
        // config.global.pomelo.open(network.PomeloService.CONNECTION, this.connectIp, this.connectPort);
    }

    private onConnectSucceed() {
        trace("CONNECT服務端鏈接成功");
        trace("開始註冊服務端信息...");
        network.GameSocket.getInstance().request(‘connector.entryHandler.entry‘, { name: "" }, this.onEntryMsg);
    }

    private onConnectError() {
        trace("CONNECT服務端鏈接失敗...");
    }

    private onEntryMsg(entry_data) {
        if (entry_data.code === 200) {
            trace("註冊信息成功");
            trace("開始申請進入遊戲...");
            network.GameSocket.getInstance().request(‘area.playerHandler.enterScene‘, { name: "", playerId: entry_data.playerId }, (respose) => {
                //Global.dispatchEvent(events.PomeloServerEvents.MAPMSG, respose);
                trace("進入遊戲成功");
                trace("開始解析地圖信息");
            });
        } else {
            trace("註冊服務端信息出現問題,請檢查提交信息");
        }
    }

    move(x: number, y: number, targetId: string) {
        network.GameSocket.getInstance().notify(‘area.playerHandler.move‘, { targetPos: { x: x, y: y }, target: targetId });
    }

    changeStage(s: string) {
        network.GameSocket.getInstance().notify(‘area.playerHandler.changeStage‘, { S: s });
    }
}
View Code

因為服務端中多玩家的功能已經實現,這裏不再繼續贅述。只要找到對應的服務端方法 就可以進行服務端的邏輯代碼修改。

egret例子下載

例子中已經實現遊戲的登錄和進入服務端,下面來看一下服務端中關於遊戲數據的返回值處理。

首先在遊戲場景中申請遊戲場景數據

                    network.GameSocket.getInstance().request(network.Servers.AREA.handler.enterScene, { name: this.txt_playerName.text, playerId: entry_data.playerId }, (respose) => {
                        self.lbl_info.text = "進入遊戲成功";
                        self.lbl_info.text = "開始解析地圖信息";

                        console.log(respose);

                    });

在服務端經過

技術分享圖片

在客戶端console出來的結果 便是散落在地上的裝備 數據

技術分享圖片

客戶端的顯示和玩家的移動通知處理,暫時不去做,因為和自己想要做的邏輯未必相同。至此已經大體了解pomelo的工作流程,和使用哪些處理器處理相關的業務邏輯,下節就要根據自己的需求設計遊戲,遇見什麽問題解決什麽問題。

[egret+pomelo]實時遊戲雜記(3)