騰訊雲大學大咖分享 |小遊戲聯機對戰引擎實踐

騰訊雲大學本期直播課程邀請到了騰訊雲Web前端工程師經過兩個小遊戲demo,講解了小遊戲聯機對戰引擎中幀同步和狀態同步兩種應用場景。「騰訊雲大學」聯合「雲加社區」爲你們整理了課程精彩乾貨!前端

實踐案例背景

  • 幀同步遊戲 - 豬豬對戰

豬豬對戰demo是一款1V1的雙人對戰幀同步遊戲,玩家能夠經過邀請好友或者快速加房組成對局,而後使用幀同步實現不一樣玩家之間遊戲邏輯的同步。demo包含四個頁面,分別是受權頁、首頁、房間頁、對戰頁。玩家進入首頁後,點擊「快速開始」或者「邀請好友」按鈕進入房間頁;雙方點擊房間頁「準備按鈕」後能夠進入對戰頁面開始遊戲。express

涉及到的MGOBE接口有房間匹配(matchRoom)、建立房間(createRoom)、加入房間(joinRoom)、查詢房間信息(getRoomDetail)、退出房間(leaveRoom)、修改玩家狀態(changeCustomPlayerStatus)、開始幀同步(startFrameSync)、幀同步廣播(onRecvFrame)。瀏覽器

  • 狀態同步遊戲 - 答題遊戲

答題遊戲是一款使用MGOBE實時服務器實現的狀態同步的組隊答題類遊戲。玩家經過隨機匹配組成對局,而後與實時服務器進行交互,獲取遊戲狀態(題目信息、玩家信息)。demo包含六個頁面:受權頁、首頁、匹配頁、房間頁、答題頁、結算頁。玩家在首頁經過三種匹配方式(1V一、2V二、3V3)進入房間,玩家向實時服務器發送準備指令後會進入答題頁。選擇答案後提交到實時服務器,由實時服務器的邏輯判斷答案的正誤,而且下發新的遊戲狀態給每一個玩家。服務器

涉及到的MGOBE接口有玩家匹配(matchPlayers)、查詢指定房間信息(getRoomByRoomId)、退出房間(leaveRoom)、發送實時服務器消息(sendToGameSvr)、實時服務器廣播(onRecvFromGameSvr)。微信

MGOBE 簡介

小遊戲聯機對戰引擎(Mini Game Online Battle Engine,MGOBE)主要爲小遊戲提供多人聯機對戰服務,幫助開發者快速搭建多人交互小遊戲。依託騰訊雲強大的網絡、硬件資源,開發者無需關注遊戲底層網絡架構、網絡通訊、服務器擴縮容、運維,只須要經過 SDK 調用 MGOBE 後臺服務,便可得到就近接入、低延遲、實時擴容的高性能聯機對戰服務。網絡

目前 MGOBE 具有了房間管理、玩家匹配、房間消息、幀同步、狀態同步、實時服務器等服務能力,開發者只須要在小遊戲中調用 SDK 接口,就能輕鬆接入聯機對戰,讓玩家在網絡上互通、對戰、自由暢玩。前端工程師

接口概覽

MGOBE 客戶端 SDK 的接口能夠分爲五類,包括房間管理、匹配、消息發送、幀同步、廣播接口。架構

房間管理類的接口主要是用於將不一樣玩家組成一個對局,這個過程當中能夠經過建立房間、邀請他人加入房間等方式將玩家聚合在一塊兒。此外,還提供瞭如踢人、修改房間屬性、查詢房間信息等基本的房間管理方法。運維

匹配類的接口主要是用於將不一樣玩家經過匹配的方式組成對局,開發者能夠根據須要定製匹配規則,實現根據玩家等級、積分進行匹配。dom

幀同步和消息發送接口能夠用於玩家消息的交互,經過幀同步、狀態同步方式實現玩家遊戲邏輯的同步。

廣播類接口主要是用於處理上述接口調用產生的廣播事件,好比玩家加房、退房廣播、幀消息廣播等等。

客戶端 SDK 使用流程

客戶端在使用SDK時的主要流程有4步,能夠參考官網文檔

  • 導入SDK,在微信小遊戲環境中可使用 import 或者 require 語法。
// 使用 import/from
import * as MGOBE from "./js/libs/MGOBE.js";
const { Room, Listener, ErrCode, ENUM, DebuggerLog } = MGOBE;
// 使用 require
const MGOBE = require("./js/libs/MGOBE.js");
const { Room, Listener, ErrCode, ENUM, DebuggerLog } = MGOBE;
  • 初始化 Listener 對象。
const gameInfo = {
    openId: 'xxxxxx',
    gameId: "xxxxxx",// 替換爲控制檯上的「遊戲ID」
    secretKey: 'xxxxxx',// 替換爲控制檯上的「密鑰」
};
const config = {
    url: 'xxx.wxlagame.com',// 替換爲控制檯上的「域名」
    reconnectMaxTimes: 5,
    reconnectInterval: 1000,
    resendInterval: 1000,
    resendTimeout: 10000,
};
Listener.init(gameInfo, config, event => {
    if (event.code === 0) {
        // 初始化成功
        // 繼續在此添加代碼
        // ...
    }
});
  • 實例化 Room 對象,加入到監聽。
const room = new Room();
// 監聽
Listener.add(room);
  • 經過 room 實例調用方法,並處理廣播回調。
// 建立房間
room.createRoom(para, callback);
// 監聽加房廣播
room.onJoinRoom = event => console.log("有玩家加入");

房間管理

在將各個玩家加到同一個房間造成對局的過程當中,須要用到建立房間、踢人、修改房間信息等操做。以微信小戲平臺**邀請玩家**爲例,整個流程以下:

其中,「生成邀請連接」、「分享」都是使用微信的接口實現,「建立房間」、「加入房間」使用 MGOBE 相應接口實現。在這個過程當中,房間信息可能會因爲屢次操做引發屢次更新,好比玩家進房、退房、修改狀態等。爲了方便管理房間信息更新,可使用 onUpdate 接口:

const room = new Room();
room.onUpdate = () => {
    console.log("房間信息已更新", room.roomInfo);
    // 渲染畫面
    // ...
};

在處理應用重啓的場景時,須要在打開應用時檢查玩家是否在房間中、是否在遊戲中等信息,能夠經過 getRoomDetail 接口查詢:

// 查詢玩家本身的房間
room.initRoom();
room.getRoomDetail(event => {
    if (event.code === 0) {
        console.log("玩家已在房間內:", event.data.roomInfo.name);
        // 繼續判斷玩家是否在遊戲中
        // ...
        return;
    }
    if (event.code === 20011) {
        console.log("玩家不在房間內");
        return;
    }
});

玩家匹配

MGOBE 爲開發者提供了兩種匹配方式:matchRoom 和 matchPlayers,分別表示房間匹配和玩家匹配。在兩次分享課程中分別以豬豬對戰答題遊戲爲例介紹了這兩種匹配方式的用法。

  • matchRoom

房間匹配是以 maxPlayers 和 roomType 爲參數,尋找 maxPlayers、roomType 屬性值一致的房間,若是存在這種房間,則將玩家加入,否爲爲玩家建立一個新房間。適合須要快速加房的場景,用法以下:

const playerInfo = {
        name: "Tom",
        customPlayerStatus: 1,
        customProfile: "https://xxx.com/icon.png",
    };
    const matchRoomPara = {
        playerInfo,
        maxPlayers: 5,
        roomType: "1",
    };
    room.matchRoom(matchRoomPara, event => {
        if (event.code !== 0) {
            console.log("匹配失敗", event.code);
        }
    });
  • matchPlayers

玩家匹配更加靈活,開發者須要在控制檯上建立匹配規則,獲得匹配Code做爲該接口參數。玩家觸發該接口後會與其餘玩家進行匹配,知足匹配規則的玩家會被匹配在一塊兒。

  • 示例1。四人隨機匹配:
{
    "version": "V1.0",
    "teams": [
        {
            "name": "4人房間",
            "maxPlayers": 4,
            "minPlayers": 4,
            "number": 1
        }
    ]
}
  • 示例2。3V3 根據玩家段位(level)進行匹配,而且玩家 level 屬性值在 1 ~ 100 內的不一樣玩家才能匹配在一塊兒,規則以下:
{
    "version": "V1.0",
    "teams": [
        {
            "name": "3v3",
            "maxPlayers": 3,
            "minPlayers": 3,
            "number": 2
        }
    ],
    "playerAttributes": [
        {
            "name": "level",
            "type": "number"
        }
    ],
    "rules": [
        {
            "type": "segment",
            "expression": "teams[i].players.level",
            "value": [
                [
                    1,
                    100
                ]
            ]
        }
    ]
}

客戶端 SDK 調用方法:

const playerInfo = {
        name: "Tom",
        customPlayerStatus: 1,
        customProfile: "https://xxx.com/icon.png",
        matchAttributes: [{
            name: "level",
            value: 99,
        }]
    };
    const matchPlayersPara = {
        playerInfo,
        // 匹配Code 須要從控制檯配置獲取
        matchCode: "match-xxx",
    };
    // 發起匹配
    room.matchPlayers(matchPlayersPara, event => {
        if (event.code === 0) {
            console.log("匹配成功", room.roomInfo);
        } else {
            console.log("匹配失敗", event.code);
        }
    });

幀同步應用

幀同步須要使用 sendFrame、onRecvFrame 進行發幀、處理幀廣播。客戶端邏輯依靠於 onRecvFrame 進行更新,遊戲狀態計算也是在客戶端完成。在幀同步以前須要調用 startFrameSync 觸發開始幀同步:

// 開始幀同步
    room.startFrameSync({}, event => {
        if (event.code === 0) {
            console.log("開始幀同步成功");
        }
    });
    // 開始幀同步廣播回調
    room.onStartFrameSync = event => console.log("開始幀同步");

開始幀同步成功以後玩家能夠向 MGOBE 後臺發送幀消息指令。以豬豬對戰爲例,玩家點擊屏幕後會向後臺發送一條 jump 指令。MGOBE 後臺會將所有玩家的消息指令組成一個幀廣播,而且定時下發(如每秒15次):

const frame = {cmd: "jump"};
    room.sendFrame({ data: frame }, event => console.log(event));
    // 處理幀廣播
    room.onRecvFrame = event => {
        console.log("幀廣播", event.data.frame);
        // 計算遊戲邏輯狀態
        // ...
    };

開發者在遊戲中每每會有同步隨機數的需求,好比」炸彈「的位置須要隨機出現、「傷害值」存在隨機性等。MGOBE 的每一個幀廣播都帶上了一個隨機種子,能夠結合 SDK 提供的隨機數工具來生成隨機數,而且能夠確保在不一樣客戶端生成的隨機數序列是一致的:

room.onRecvFrame = event => {

        console.log("幀廣播", event.data.frame);

        // 使用幀廣播隨機種子和幀ID組成新的隨機種子

        const seed = event.data.frame.ext.seed + event.data.frame.id;

        // 收到幀廣播後初始化隨機出工具

        MGOBE.RandomUtil.init(seed);

        // 生成隨機數

        const r1 = MGOBE.RandomUtil.random();

        const r2 = MGOBE.RandomUtil.random();

        const r3 = MGOBE.RandomUtil.random();

        // 利用隨機數執行相應邏輯

        // ...

    };

狀態同步應用

狀態同步類型聯機遊戲的特色是遊戲邏輯狀態在服務端計算。爲了實現狀態同步,MGOBE 爲開發者提供了實時服務器功能,開發者能夠上傳代碼部署到實時服務器上,而且與客戶端 SDK、房間服務進行交互。

實時服務器實現了對客戶端遊戲邏輯的擴展。玩家進入房間以後,對房間進行的任何操做,都會經過房間服務器同步給實時服務器,那這樣實時服務器上也能拿到最新的房間狀態,好比玩家進房、退房、掉線、開始幀同步等等。

客戶端能夠經過 sendToGameSvr請求接口、onRecvFromGameSvr廣播接口實現和實時服務器進行交互。

  • 客戶端代碼

// 發送消息給實時服務器
room.sendToGameSvr({data: { cmd: 1 }}, event => console.log(event));
// 接收實時服務器廣播
room.onRecvFromGameSvr = event => {
    console.log("新自定義服務消息", event);
    // 更新遊戲畫面
    // ...
}
  • 實時服務器代碼

// 接收客戶端消息
onRecvFromClient = args => {
    // 客戶端消息
    const data = args.actionData;
    // 計算遊戲狀態 gameData
    // ...
    // 發送遊戲狀態給客戶端
    args.SDK.sendData({ playerIdList: [], data: { gameData } });
    args.SDK.exitAction();
};

經過這種方式,開發者能夠把玩家的遊戲輸入所有發送給實時服務器,而後由實時服務器計算遊戲狀態,而且廣播給每一個客戶端,實現遊戲狀態同步。

常見問題

Q:createRoom、matchRoom、matchPlayers接口主要區別是什麼?
A:createRoom 建立房間而且加入到該房間。matchRoom 根據參數匹配到同樣的房間,而且進入。
若是沒有合適的房間,按照該參數建立新房間。matchPlayers 須要在控制檯上配置匹配規則,
拿到匹配code,以此爲參數進行匹配。匹配成功後進入房間。

Q:建立房間後須要調用joinRoom嗎?
A:不須要,調用 createRoom 後玩家會自動進入房間。
不須要,匹配成功玩家會自動進入房間。
開發者可能開通了實時服務器,可是沒有正常運行,好比沒有發佈代碼。
新版本即將支持 H5原生環境,能夠直接在瀏覽器中運行。
檢查 room 實例是否加入到 Listener。

Q:匹配成功後須要建立房間嗎?
A:建立房間或匹配的時候出現400十、40011錯誤

Q:如何在瀏覽器中進行調試?
A:SDK 沒有收到廣播

結語

MGOBE 能爲開發者快速實現遊戲房間管理、在線匹配、聯網對戰等功能,你們能夠到騰訊雲官網產品頁中搜索「MGOBE」進一步瞭解。也歡迎你們掃碼加入開發者羣交流。

騰訊雲大學是騰訊雲旗下,面向雲生態用戶的一站式學習成長平臺。騰訊雲大學大咖分享每週邀請內部技術大咖,爲你提供免費、專業、行業最新技術動態分享。

相關文章
相關標籤/搜索