聯(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