兩款案例講解一周搭建聯(lián)機(jī)游戲

聯(lián)機(jī)游戲
1.前言
聯(lián)機(jī)游戲的社交屬性強(qiáng)康二,玩家粘性高沫勿,但是相對單機(jī)游戲产雹,聯(lián)機(jī)游戲開發(fā)周期長蔓挖、成本高怨绣,因此很多開發(fā)者選擇開發(fā)單機(jī)游戲篮撑,然而投入大量開發(fā)時(shí)間和資源咽扇,單機(jī)游戲活躍度不溫不火陕壹,玩家數(shù)量持續(xù)流失糠馆。本文利用兩款小游戲案例介紹如何快速搭建聯(lián)機(jī)玩法又碌,幫助開發(fā)者短期低成本實(shí)現(xiàn)一款聯(lián)機(jī)游戲铸鹰。
2.幀同步和狀態(tài)同步
聯(lián)機(jī)游戲的通信方式主要為此幀同步和狀態(tài)同步蹋笼。

  • 幀同步過程為各客戶端實(shí)時(shí)上傳操作指令集;服務(wù)端保存這些操作指令集逊谋,并在下一幀將其廣播給所有客戶端胶滋;客戶端收到指令集后分別按幀序執(zhí)行指令集中的操作镀钓。同步的是玩家的操作指令镀迂,該方式多用于對實(shí)時(shí)性要求很高的網(wǎng)絡(luò)游戲。
  • 狀態(tài)同步過程為客戶端上傳操作到服務(wù)端窟赏,服務(wù)端收到后計(jì)算游戲行為的結(jié)果棍掐,即技能邏輯。戰(zhàn)斗計(jì)算都由服務(wù)端運(yùn)算粟誓,然后以廣播的方式下發(fā)游戲中各種狀態(tài),客戶端收到狀態(tài)后悲酷,更新自己本地的動(dòng)作狀態(tài)、Buff 狀態(tài)亡嫌、位置等。同步的是游戲中的各種狀態(tài),該方式多用于回合制游戲控淡。

3.聯(lián)機(jī)游戲種類
聯(lián)機(jī)游戲的種類大體可以分為以下四種:

  • 回合制多人游戲,常見的有棋牌游戲,打麻將肤视、斗地主等邢滑,策略衬廷、角色扮演等回合制游戲泵督。
  • 實(shí)時(shí)多人游戲久窟,近幾年大火的吃雞游戲入问、MOBA、休閑對戰(zhàn),像《和平精英》颊糜、《王者榮耀》、《全球大作戰(zhàn)》、《貪吃蛇》等翠勉。
  • 大型多人在線游戲,玩家在一個(gè)持續(xù)的空間里玩朽们,比如《天龍八部》苍糠、《御龍?jiān)谔臁返葒鴳?zhàn)類的游戲拥娄。
  • 社交游戲姚炕,休閑類偏多些椒,像《海盜來了》痒给、《豬來了》尼斧,還有很多年前流行的偷菜,都屬于社交類游戲。
    本文主要利用兩款社交游戲進(jìn)行講解。

游戲聯(lián)機(jī)對戰(zhàn)引擎
1.簡介
游戲聯(lián)機(jī)對戰(zhàn)引擎(Mobile Game Online Battle Engine,MGOBE)為游戲提供房間管理、隊(duì)組管理、在線匹配、幀同步桐罕、狀態(tài)同步等對戰(zhàn)服務(wù)溅潜,幫助開發(fā)者快速搭建多人交互游戲设捐。

  • 直接通過 SDK 調(diào)用后端服務(wù)存捺,無需后臺代碼
  • 無需關(guān)心后臺網(wǎng)絡(luò)架構(gòu)纽窟、網(wǎng)絡(luò)通信技術(shù)周蹭、幀同步、服務(wù)器擴(kuò)縮容宛畦、運(yùn)維等復(fù)雜技術(shù)
  • 獲得就近接入、低延遲畅形、實(shí)時(shí)擴(kuò)容的高性能對戰(zhàn)服務(wù),讓玩家在網(wǎng)絡(luò)上互通、對戰(zhàn)、自由暢玩
  • 適用于回合制、策略類、實(shí)時(shí)會話(休閑對戰(zhàn)第献、MOBA飒赃、FPS)等游戲蔫慧。


2.接口概覽
游戲聯(lián)機(jī)對戰(zhàn)引擎 MGOBE 客戶端 SDK 的接口可以分為五類肋联,包括房間管理、匹配、消息發(fā)送第晰、幀同步锁孟、廣播接口彬祖。

  • 房間管理類的接口主要是用于將不同玩家組成一個(gè)對局,這個(gè)過程中可以通過創(chuàng)建房間品抽、邀請他人加入房間等方式將玩家聚合在一起储笑。此外,還提供了如踢人圆恤、修改房間屬性突倍、查詢房間信息等基本的房間管理方法。
  • 匹配類的接口主要是用于將不同玩家通過匹配的方式組成對局盆昙,開發(fā)者可以根據(jù)需要定制匹配規(guī)則羽历,實(shí)現(xiàn)根據(jù)玩家等級、積分進(jìn)行匹配淡喜。
  • 幀同步和消息發(fā)送接口可以用于玩家消息的交互秕磷,通過幀同步、狀態(tài)同步方式實(shí)現(xiàn)玩家游戲邏輯的同步拆火。
  • 廣播類接口主要是用于處理上述接口調(diào)用產(chǎn)生的廣播事件跳夭,比如玩家加房、退房廣播们镜、幀消息廣播等等币叹。

3.客戶端 SDK 主要接口

客戶端 SDK 使用方法

1.使用流程
客戶端在使用SDK時(shí)的主要流程有4步:

  • (1)導(dǎo)入SDK,在微信小游戲環(huán)境中可以使用 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;
  • (2)初始化 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) {
       // 初始化成功
       // 繼續(xù)在此添加代碼
       // ...
   }
});
  • (3)實(shí)例化 Room 對象,加入到監(jiān)聽嚼鹉。
const room = new Room();
// 監(jiān)聽
Listener.add(room);
  • (4)通過 room 實(shí)例調(diào)用方法贩汉,并處理廣播回調(diào)。
// 創(chuàng)建房間
room.createRoom(para, callback);
// 監(jiān)聽加房廣播
room.onJoinRoom = event => console.log("有玩家加入");

2.房間管理

在將各個(gè)玩家加到同一個(gè)房間形成對局的過程中锚赤,需要用到創(chuàng)建房間匹舞、踢人、修改房間信息等操作线脚。以微信小戲平臺邀請玩家為例赐稽,整個(gè)流程如下:

其中,“生成邀請鏈接”浑侥、“分享”都是使用微信的接口實(shí)現(xiàn)姊舵,“創(chuàng)建房間”、“加入房間”使用 MGOBE 相應(yīng)接口實(shí)現(xiàn)寓落。在這個(gè)過程中括丁,房間信息可能會由于多次操作引起多次更新,比如玩家進(jìn)房伶选、退房史飞、修改狀態(tài)等尖昏。為了方便管理房間信息更新,可以使用 onUpdate 接口:

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

在處理應(yīng)用重啟的場景時(shí)会宪,需要在打開應(yīng)用時(shí)檢查玩家是否在房間中、是否在游戲中等信息蚯窥,可以通過 getRoomDetail 接口查詢:

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

3.玩家匹配

MGOBE 為開發(fā)者提供了兩種匹配方式:matchRoom 和 matchPlayers掸鹅,分別表示房間匹配和玩家匹配。

  • matchRoom

房間匹配是以 maxPlayers 和 roomType 為參數(shù)拦赠,尋找 maxPlayers巍沙、roomType 屬性值一致的房間,如果存在這種房間荷鼠,則將玩家加入句携,否為為玩家創(chuàng)建一個(gè)新房間。適合需要快速加房的場景允乐,用法如下:

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

玩家匹配更加靈活矮嫉,開發(fā)者需要在控制臺上創(chuàng)建匹配規(guī)則,得到匹配Code作為該接口參數(shù)牍疏。玩家觸發(fā)該接口后會與其他玩家進(jìn)行匹配蠢笋,滿足匹配規(guī)則的玩家會被匹配在一起。

  • 示例1鳞陨。四人隨機(jī)匹配:
{
    "version": "V1.0",
    "teams": [
        {
            "name": "4人房間",
            "maxPlayers": 4,
            "minPlayers": 4,
            "number": 1
        }
    ]
}
  • 示例2昨寞。3V3 根據(jù)玩家段位(level)進(jìn)行匹配,并且玩家 level 屬性值在 1 ~ 100 內(nèi)的不同玩家才能匹配在一起厦滤,規(guī)則如下:
{
    "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 調(diào)用方法:

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

游戲案例簡介
1.幀同步游戲 - 豬豬對戰(zhàn)
豬豬對戰(zhàn)demo是一款1V1的雙人對戰(zhàn)幀同步游戲援岩,玩家可以通過邀請好友或者快速加房組成對局,然后使用幀同步實(shí)現(xiàn)不同玩家之間游戲邏輯的同步掏导。demo包含四個(gè)頁面享怀,分別是授權(quán)頁、首頁趟咆、房間頁添瓷、對戰(zhàn)頁。玩家進(jìn)入首頁后忍啸,點(diǎn)擊“快速開始”或者“邀請好友”按鈕進(jìn)入房間頁仰坦;雙方點(diǎn)擊房間頁“準(zhǔn)備按鈕”后可以進(jìn)入對戰(zhàn)頁面開始游戲履植。

涉及到的MGOBE接口有房間匹配(matchRoom)计雌、創(chuàng)建房間(createRoom)、加入房間(joinRoom)玫霎、查詢房間信息(getRoomDetail)凿滤、退出房間(leaveRoom)妈橄、修改玩家狀態(tài)(changeCustomPlayerStatus)、開始幀同步(startFrameSync)翁脆、幀同步廣播(onRecvFrame)眷蚓。

2.狀態(tài)同步游戲 - 題題對戰(zhàn)
題題對戰(zhàn)戲是一款使用MGOBE實(shí)時(shí)服務(wù)器實(shí)現(xiàn)的狀態(tài)同步的組隊(duì)答題類游戲。玩家通過隨機(jī)匹配組成對局反番,然后與實(shí)時(shí)服務(wù)器進(jìn)行交互沙热,獲取游戲狀態(tài)(題目信息、玩家信息)罢缸。demo包含六個(gè)頁面:授權(quán)頁篙贸、首頁、匹配頁枫疆、房間頁爵川、答題頁、結(jié)算頁息楔。玩家在首頁通過三種匹配方式(1V1寝贡、2V2、3V3)進(jìn)入房間值依,玩家向?qū)崟r(shí)服務(wù)器發(fā)送準(zhǔn)備指令后會進(jìn)入答題頁圃泡。選擇答案后提交到實(shí)時(shí)服務(wù)器,由實(shí)時(shí)服務(wù)器的邏輯判斷答案的正誤鳞滨,并且下發(fā)新的游戲狀態(tài)給每個(gè)玩家洞焙。

涉及到的MGOBE接口有玩家匹配(matchPlayers)、查詢指定房間信息(getRoomByRoomId)拯啦、退出房間(leaveRoom)澡匪、發(fā)送實(shí)時(shí)服務(wù)器消息(sendToGameSvr)、實(shí)時(shí)服務(wù)器廣播(onRecvFromGameSvr)褒链。
3.游戲體驗(yàn)二維碼


幀同步應(yīng)用

幀同步需要使用 sendFrame唁情、onRecvFrame 進(jìn)行發(fā)幀、處理幀廣播甫匹〉槟瘢客戶端邏輯依靠于 onRecvFrame 進(jìn)行更新,游戲狀態(tài)計(jì)算也是在客戶端完成兵迅。在幀同步之前需要調(diào)用 startFrameSync 觸發(fā)開始幀同步:

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

開始幀同步成功之后玩家可以向 MGOBE 后臺發(fā)送幀消息指令抢韭。以游戲案例豬豬對戰(zhàn)為例,玩家點(diǎn)擊屏幕后會向后臺發(fā)送一條 jump 指令恍箭。MGOBE 后臺會將全部玩家的消息指令組成一個(gè)幀廣播刻恭,并且定時(shí)下發(fā)(如每秒15次):

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

開發(fā)者在游戲中往往會有同步隨機(jī)數(shù)的需求,比如”炸彈“的位置需要隨機(jī)出現(xiàn)、“傷害值”存在隨機(jī)性等鳍贾。MGOBE 的每個(gè)幀廣播都帶上了一個(gè)隨機(jī)種子鞍匾,可以結(jié)合 SDK 提供的隨機(jī)數(shù)工具來生成隨機(jī)數(shù),并且可以確保在不同客戶端生成的隨機(jī)數(shù)序列是一致的:

room.onRecvFrame = event => {

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

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

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

        // 收到幀廣播后初始化隨機(jī)出工具

        MGOBE.RandomUtil.init(seed);

        // 生成隨機(jī)數(shù)

        const r1 = MGOBE.RandomUtil.random();

        const r2 = MGOBE.RandomUtil.random();

        const r3 = MGOBE.RandomUtil.random();

        // 利用隨機(jī)數(shù)執(zhí)行相應(yīng)邏輯

        // ...

    };

狀態(tài)同步應(yīng)用

狀態(tài)同步類型聯(lián)機(jī)游戲的特點(diǎn)是游戲邏輯狀態(tài)在服務(wù)端計(jì)算骑科。為了實(shí)現(xiàn)狀態(tài)同步橡淑,MGOBE 為開發(fā)者提供了實(shí)時(shí)服務(wù)器功能,開發(fā)者可以上傳代碼部署到實(shí)時(shí)服務(wù)器上咆爽,并且與客戶端 SDK梁棠、房間服務(wù)進(jìn)行交互。


實(shí)時(shí)服務(wù)器實(shí)現(xiàn)了對客戶端游戲邏輯的擴(kuò)展斗埂。玩家進(jìn)入房間之后掰茶,對房間進(jìn)行的任何操作,都會通過房間服務(wù)器同步給實(shí)時(shí)服務(wù)器蜜笤,那這樣實(shí)時(shí)服務(wù)器上也能拿到最新的房間狀態(tài)濒蒋,比如玩家進(jìn)房、退房把兔、掉線沪伙、開始幀同步等等。

客戶端可以通過 sendToGameSvr請求接口县好、onRecvFromGameSvr廣播接口實(shí)現(xiàn)和實(shí)時(shí)服務(wù)器進(jìn)行交互围橡。

  • 客戶端代碼
// 發(fā)送消息給實(shí)時(shí)服務(wù)器
room.sendToGameSvr({data: { cmd: 1 }}, event => console.log(event));
// 接收實(shí)時(shí)服務(wù)器廣播
room.onRecvFromGameSvr = event => {
    console.log("新自定義服務(wù)消息", event);
    // 更新游戲畫面
    // ...
}
  • 實(shí)時(shí)服務(wù)器代碼
// 接收客戶端消息
onRecvFromClient = args => {
    // 客戶端消息
    const data = args.actionData;
    // 計(jì)算游戲狀態(tài) gameData
    // ...
    // 發(fā)送游戲狀態(tài)給客戶端
    args.SDK.sendData({ playerIdList: [], data: { gameData } });
    args.SDK.exitAction();
};

通過這種方式,開發(fā)者可以把玩家的游戲輸入全部發(fā)送給實(shí)時(shí)服務(wù)器缕贡,然后由實(shí)時(shí)服務(wù)器計(jì)算游戲狀態(tài)翁授,并且廣播給每個(gè)客戶端,實(shí)現(xiàn)游戲狀態(tài)同步晾咪。

參考文章
游戲聯(lián)機(jī)對戰(zhàn)引擎官網(wǎng)文檔:https://cloud.tencent.com/document/product/1038/33290

引用

游戲聯(lián)機(jī)對戰(zhàn)引擎控制臺:https://console.cloud.tencent.com/minigamecloud
幀同步游戲案例教程–《豬豬對戰(zhàn)》:https://cloud.tencent.com/edu/learning/live-1521?ADTAG=yjsq&from=10680
狀態(tài)游戲案例教程–《題題對戰(zhàn)》:https://cloud.tencent.com/edu/learning/live-1523?ADTAG=yjsq&from=10680

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末收擦,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谍倦,更是在濱河造成了極大的恐慌塞赂,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昼蛀,死亡現(xiàn)場離奇詭異宴猾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)叼旋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門仇哆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人夫植,你說我怎么就攤上這事讹剔。” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵辟拷,是天一觀的道長。 經(jīng)常有香客問我阐斜,道長衫冻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任谒出,我火速辦了婚禮隅俘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘笤喳。我一直安慰自己为居,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布杀狡。 她就那樣靜靜地躺著蒙畴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呜象。 梳的紋絲不亂的頭發(fā)上膳凝,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音恭陡,去河邊找鬼蹬音。 笑死,一個(gè)胖子當(dāng)著我的面吹牛休玩,可吹牛的內(nèi)容都是我干的著淆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼拴疤,長吁一口氣:“原來是場噩夢啊……” “哼永部!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呐矾,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤扬舒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后凫佛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讲坎,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年愧薛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晨炕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毫炉,死狀恐怖瓮栗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤费奸,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布弥激,位于F島的核電站,受9級特大地震影響愿阐,放射性物質(zhì)發(fā)生泄漏微服。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一缨历、第九天 我趴在偏房一處隱蔽的房頂上張望以蕴。 院中可真熱鬧,春花似錦辛孵、人聲如沸丛肮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宝与。三九已至,卻和暖如春冶匹,著一層夾襖步出監(jiān)牢的瞬間伴鳖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工徙硅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留榜聂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓嗓蘑,卻偏偏與公主長得像须肆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子桩皿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容