美文网首页
两款案例讲解一周搭建联机游戏

两款案例讲解一周搭建联机游戏

作者: 程序猿TODO | 来源:发表于2020-12-30 09:40 被阅读0次

    联机游戏
    1.前言
    联机游戏的社交属性强,玩家粘性高,但是相对单机游戏,联机游戏开发周期长、成本高,因此很多开发者选择开发单机游戏,然而投入大量开发时间和资源,单机游戏活跃度不温不火,玩家数量持续流失。本文利用两款小游戏案例介绍如何快速搭建联机玩法,帮助开发者短期低成本实现一款联机游戏。
    2.帧同步和状态同步
    联机游戏的通信方式主要为此帧同步和状态同步。

    • 帧同步过程为各客户端实时上传操作指令集;服务端保存这些操作指令集,并在下一帧将其广播给所有客户端;客户端收到指令集后分别按帧序执行指令集中的操作。同步的是玩家的操作指令,该方式多用于对实时性要求很高的网络游戏。
    • 状态同步过程为客户端上传操作到服务端,服务端收到后计算游戏行为的结果,即技能逻辑。战斗计算都由服务端运算,然后以广播的方式下发游戏中各种状态,客户端收到状态后,更新自己本地的动作状态、Buff 状态、位置等。同步的是游戏中的各种状态,该方式多用于回合制游戏。

    3.联机游戏种类
    联机游戏的种类大体可以分为以下四种:

    • 回合制多人游戏,常见的有棋牌游戏,打麻将、斗地主等,策略、角色扮演等回合制游戏。
    • 实时多人游戏,近几年大火的吃鸡游戏、MOBA、休闲对战,像《和平精英》、《王者荣耀》、《全球大作战》、《贪吃蛇》等。
    • 大型多人在线游戏,玩家在一个持续的空间里玩,比如《天龙八部》、《御龙在天》等国战类的游戏。
    • 社交游戏,休闲类偏多,像《海盗来了》、《猪来了》,还有很多年前流行的偷菜,都属于社交类游戏。
      本文主要利用两款社交游戏进行讲解。

    游戏联机对战引擎
    1.简介
    游戏联机对战引擎(Mobile Game Online Battle Engine,MGOBE)为游戏提供房间管理、队组管理、在线匹配、帧同步、状态同步等对战服务,帮助开发者快速搭建多人交互游戏。

    • 直接通过 SDK 调用后端服务,无需后台代码
    • 无需关心后台网络架构、网络通信技术、帧同步、服务器扩缩容、运维等复杂技术
    • 获得就近接入、低延迟、实时扩容的高性能对战服务,让玩家在网络上互通、对战、自由畅玩
    • 适用于回合制、策略类、实时会话(休闲对战、MOBA、FPS)等游戏。


    2.接口概览
    游戏联机对战引擎 MGOBE 客户端 SDK 的接口可以分为五类,包括房间管理、匹配、消息发送、帧同步、广播接口。

    • 房间管理类的接口主要是用于将不同玩家组成一个对局,这个过程中可以通过创建房间、邀请他人加入房间等方式将玩家聚合在一起。此外,还提供了如踢人、修改房间属性、查询房间信息等基本的房间管理方法。
    • 匹配类的接口主要是用于将不同玩家通过匹配的方式组成对局,开发者可以根据需要定制匹配规则,实现根据玩家等级、积分进行匹配。
    • 帧同步和消息发送接口可以用于玩家消息的交互,通过帧同步、状态同步方式实现玩家游戏逻辑的同步。
    • 广播类接口主要是用于处理上述接口调用产生的广播事件,比如玩家加房、退房广播、帧消息广播等等。

    3.客户端 SDK 主要接口

    客户端 SDK 使用方法

    1.使用流程
    客户端在使用SDK时的主要流程有4步:

    • (1)导入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;
    
    • (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) {
           // 初始化成功
           // 继续在此添加代码
           // ...
       }
    });
    
    • (3)实例化 Room 对象,加入到监听。
    const room = new Room();
    // 监听
    Listener.add(room);
    
    • (4)通过 room 实例调用方法,并处理广播回调。
    // 创建房间
    room.createRoom(para, callback);
    // 监听加房广播
    room.onJoinRoom = event => console.log("有玩家加入");
    

    2.房间管理

    在将各个玩家加到同一个房间形成对局的过程中,需要用到创建房间、踢人、修改房间信息等操作。以微信小戏平台邀请玩家为例,整个流程如下:

    其中,“生成邀请链接”、“分享”都是使用微信的接口实现,“创建房间”、“加入房间”使用 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;
        }
    });
    

    3.玩家匹配

    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);
            }
        });
    

    游戏案例简介
    1.帧同步游戏 - 猪猪对战
    猪猪对战demo是一款1V1的双人对战帧同步游戏,玩家可以通过邀请好友或者快速加房组成对局,然后使用帧同步实现不同玩家之间游戏逻辑的同步。demo包含四个页面,分别是授权页、首页、房间页、对战页。玩家进入首页后,点击“快速开始”或者“邀请好友”按钮进入房间页;双方点击房间页“准备按钮”后可以进入对战页面开始游戏。

    涉及到的MGOBE接口有房间匹配(matchRoom)、创建房间(createRoom)、加入房间(joinRoom)、查询房间信息(getRoomDetail)、退出房间(leaveRoom)、修改玩家状态(changeCustomPlayerStatus)、开始帧同步(startFrameSync)、帧同步广播(onRecvFrame)。

    2.状态同步游戏 - 题题对战
    题题对战戏是一款使用MGOBE实时服务器实现的状态同步的组队答题类游戏。玩家通过随机匹配组成对局,然后与实时服务器进行交互,获取游戏状态(题目信息、玩家信息)。demo包含六个页面:授权页、首页、匹配页、房间页、答题页、结算页。玩家在首页通过三种匹配方式(1V1、2V2、3V3)进入房间,玩家向实时服务器发送准备指令后会进入答题页。选择答案后提交到实时服务器,由实时服务器的逻辑判断答案的正误,并且下发新的游戏状态给每个玩家。

    涉及到的MGOBE接口有玩家匹配(matchPlayers)、查询指定房间信息(getRoomByRoomId)、退出房间(leaveRoom)、发送实时服务器消息(sendToGameSvr)、实时服务器广播(onRecvFromGameSvr)。
    3.游戏体验二维码


    帧同步应用

    帧同步需要使用 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();
    };
    

    通过这种方式,开发者可以把玩家的游戏输入全部发送给实时服务器,然后由实时服务器计算游戏状态,并且广播给每个客户端,实现游戏状态同步。

    参考文章
    游戏联机对战引擎官网文档:https://cloud.tencent.com/document/product/1038/33290

    引用

    游戏联机对战引擎控制台:https://console.cloud.tencent.com/minigamecloud
    帧同步游戏案例教程–《猪猪对战》:https://cloud.tencent.com/edu/learning/live-1521?ADTAG=yjsq&from=10680
    状态游戏案例教程–《题题对战》:https://cloud.tencent.com/edu/learning/live-1523?ADTAG=yjsq&from=10680

    相关文章

      网友评论

          本文标题:两款案例讲解一周搭建联机游戏

          本文链接:https://www.haomeiwen.com/subject/zheqoktx.html