对战游戏

1 业务背景

H5游戏对战平台(app)具备基本的账号、玩家基本信息、匹配撮合能力,实时语音聊天能力,并通过提供给cp的js lib库,能够将这些能力开放给内嵌在该平台上运行的对战游戏。游戏cp只关注游戏的核心玩法,从js 接口获取匹配好的玩家信息,进行游戏,将游戏结果通知给对战平台即可。

业务场场景流程:

  1. 玩家登陆对战平台app。

  2. 选择需要对战的游戏,点击随机对手匹配。

  3. 对战平台按匹配条件规则匹配好对手,打开cp游戏界面。

  4. cp游戏启动,通过接口获取双方玩家信息,开始游戏。

  5. 游戏结束条件达成,上报游戏平台结果,一局游戏完成。

  6. 对战游戏平台app关闭cp游戏界面,显示结算界面。

  7. 玩家重新选择匹配新一局游戏。

2 基本概念

  • H5游戏对战平台是由安卓客户端App+H5游戏,服务端接入和匹配系统构成。

  • 服务端匹配系统根据匹配规则将玩家撮合分配到一起进行一局游戏,客户端拉起相应的H5游戏。

  • App 通过JS引擎消息管道,与H5游戏的JS 运行时进行异步交互。

  • 通过App提供给H5游戏相应的能力完成对战游戏逻辑的实现。(如:获取当前对局基本信息,提供游戏业务消息管道,提供游戏过程控制和事件侦听)

  • 平台提供JS lib给CP方进行H5游戏接入。

  • 对接入的H5游戏提供两种方式供选择:

    1. cp无游戏服务端的游戏:由对战平台提供对战双方游戏业务消息管道,通过该管道,使得单机游戏快速的具备了联机游戏的能力。

    2. cp自有游戏服务端的游戏: 游戏连接自有服务端进行联网对战,需在单局游戏开始和结束调用对战平台服务端API进行状态通知。

3 接入步骤

cp整个接入分为三个大的阶段步骤:

1.技术接入阶段

2.资源包提审阶段

3.测试与发布阶段

3.1 技术接入阶段

该阶段主要的目的是进行技术对接。由我方提供开发版对战大厅apk,用于cp技术层面接入和连调,需要向我方平台申请appKey,appSecret,cp提供产品包名(包名要求以.nearme.gamecenter结尾),通过配置开发版apk的配置文件(具体配置方式参见:4.2开发版配置说明),进行游戏功能连调,可采用url方式方便调试。

3.2 资源包提审阶段

开发版apk和游戏功能联调好后,进入提审阶段,将游戏按照文档中要求的方式(具体参见:8游戏资源包打包说明),放入manifest.json ,将游戏资源打包并加入签名,按审核流程要求填写游戏相关信息,并提交加签名后的游戏资源包,由官方人员进行审核通过。

审核附带美术资源,须按规范(详见:icon图片规范.png) 示意,提供三种规格icon图标。

示例包见 示例h5demo 文件夹下的gpk和zip

3.3 测试与发布阶段

审核通过后,进入游戏测试阶段,有bug,修改后重新通过提审进行提交。测试通过后,技术层面即可具备上线发布的条件,具体发布方式则由业务产品进行制定和操作。

3.4 其他接入要求

  1. 游戏逻辑需提供与机器人对战的能力。

  2. 选择两种接入方式之一进行接入。

4 开发调试

4.1 下载调试工具

点击下载

注意:真机调试时须要使用OPPO手机调试

4.2 配置说明

配置文件文件名: /sdcard/Android/data/com.nearme.play/files/debug_config.json

注意: /sdcard/Android/data/com.nearme.play/files在初次运行apk才会创建,拷贝进去配置后,需要杀进程重启才生效(启动时加载该配置)

{
  "pkgName": "com.game.nearme.gamecenter",
  "appKey": "fasdfxdfe",
  "appSecret": "sdfesdfc",
  "resourceType": "1",
  "gameRes": "http://www.xxxxxx.com/gameres/index.html",
  "gpkMd5": "65f7b302e59f6cc9ee02c52cee0104b0",
  "gpkVerify": "0"
}
// 注意:此处如果 resourceType:2,则"gameRes":"com.game.nearme.gamecenter.gpk"
属性 类型 描述
pkgName String 游戏包名,为游戏大厅给游戏分配的指定参数,用来区分校验游戏
appKey String 为游戏大厅给游戏分配的指定参数,用来区分校验游戏
appSecret String 为游戏大厅给游戏分配的指定参数,用来区分校验游戏
resourceType String 资源类型,"1"或"2",填"1"时,表示使用链接的形式加载资源,填"2"时, gameRes表示使用gpk本地包的形式加载资源,放入相同路径/sdcard/Android/data/com.nearme.play/files/,配置对应的文件名到gameRes,如"gameRes":"game1.gpk"
gameRes String 取决于"resourceType",当resourceType="1"时,这里填游戏的url;当resourceType="2"时,这里填入的是gpk本地包的文件名,gpk的打包方法请参考游戏资源包打包说明
gpkMd5 String " "或游戏包的md5,取决于gpkVerfiy
gpkVerify String "0"不开启本地游戏资源包验证,"1"开启本地资源包验证,为正式环境下验证方式,需要游戏包打签名,并在gpkMd5下填写游戏包的md5

配置文件的以及gpk的存放路径:

/sdcard/Android/data/com.nearme.play/files/debug_config.json

/sdcard/Android/data/com.nearme.play/files/xxxxx.gpk

5 JS SDK接入

目前 js lib 最新版本号为version 2,历史版本见jslib 文件夹下的 各版本的BattlePlatform.js。

app与H5游戏之间通过 BattlePlatform.msgChannel 进行异步交互,参数为cmd和param,param2,发送和侦听接收事件均采用这2个参数。

接入方式:

1.在index.html中,加入下列一行

<script type = "text/javascript" src="https://cdofs.oppomobile.com/cdo-activity/201809/06/1809062158/v2/BattlePlatform.js"></script>

2.在游戏中引用BattlePlatform对象进行使用。

属性 类型 说明
objToJson Function json对象转为字符串,等同于JSON.stringify
jsonToObj Function 字符串转为json对象,等同于JSON.parse
msgChannel Object 用于控制命令发送和监听

msgChannel.send(cmd, param)
cmd: String 命令 data: String 参数

msgChannel.setRecvCallback(cmd, param1, param2)
cmd: String 命令 param1: String 参数1 param2: String 参数2

使用引导可以参考demo

6 SDK通用命令和事件

命令

  • lib初始化
cmd: "init"
param :
{
    libVer,        //int lib版本号,设置为  BattlePlatform.version
    mode,        //int 预留,填0
}
  • 查询本局信息
cmd: "infoReq"
param :
{
    appKey,        //string 分配给cp的鉴权key    
    appSecret, //string 分配给cp的鉴权secret
}

异步应答(1v1双人对战)

cmd : "infoRsp"
param : 
{
    code,        //int 返回码,0为成功,其他为错误    
    versionCode,//int 游戏大厅版本号(1002以下版本该字段为空,使用versionCode时需要判空)
    message,    //string 返回消息(预留字段)
    pkgName,    //string 游戏包名
    selfUid,    //自己的id,该id不是真是玩家uid
    tableId,    //string 分配的桌子id
    tableToken, //string 分配的桌子token
    public boolean isFirstEnterGame,    // 是否第一次进入游戏(1200以下版本该字段为空)
    players : //玩家列表
    [ 
        //第一个玩家是自己
        {
            uid,            //string 玩家uid, 该id不是真是玩家uid
            name,            //string 玩家昵称
            headIcon,        //string  玩家头像url
            sex,            //string 玩家性别 ,M为男性,F为女性
            micStatus,        //int  预留字段
            speakerStatus,     //int  预留字段
            tag,            //int  0:正常玩家, 1: ai机器人
        },
        {
            uid,
            name,
            headIcon,
            sex,
            micStatus,
            speakerStatus,
            tag,
        },
    ],        
}

异步应答(多人对战随机组队模式)

cmd : "infoRsp"
param :
{
    code,            //int 返回码,0为成功,其他为错误    
    message,        //string 返回消息(预留字段)
    pkgName,        //string 游戏包名
    selfUid,        //自己的id,该id不是真是玩家uid
    tableId,        //string 分配的桌子id
    tableToken,        //string 分配的桌子token
    versionCode,    //int 游戏大厅版本号
    isFirstEnterGame,    // 是否第一次进入游戏
    camps : [ // 队伍列表
        {
            campId, 队伍Id
            players: // 玩家列表
            [
                {
                    uid,            //string 玩家uid, 该id不是真是玩家uid
                    name,            //string 玩家昵称
                    headIcon,        //string  玩家头像url
                    sex,            //string 玩家性别 ,M为男性,F为女性
                    micStatus,        //int  预留字段
                    speakerStatus,     //int  预留字段
                    tag,            //int  0:正常玩家, 1: ai机器人
                },
                {
                } ...
            ],            
        } ,
        {
        } ...
    ]
}

异步应答(多人对战随各自为战模式)

cmd : "infoRsp"
param :
{
    code,            //int 返回码,0为成功,其他为错误    
    message,        //string 返回消息(预留字段)
    pkgName,        //string 游戏包名
    selfUid,        //自己的id,该id不是真是玩家uid
    tableId,        //string 分配的桌子id
    tableToken,        //string 分配的桌子token
    versionCode,    //int 游戏大厅版本号
    isFirstEnterGame,    // 是否第一次进入游戏
    players : //玩家列表
    [ 
        //第一个玩家是自己
        {
            uid,            //string 玩家uid, 该id不是真是玩家uid
            name,            //string 玩家昵称
            headIcon,        //string  玩家头像url
            sex,            //string 玩家性别 ,M为男性,F为女性
            micStatus,        //int  预留字段
            speakerStatus,     //int  预留字段
            tag,            //int  0:正常玩家, 1: ai机器人
        } ...
    ],        
}
  • 强制退出游戏
cmd: "forceQuit"
param :
{
    reason,        //退出原因,0:正常退出, 1:异常退出,其他待定义
    message,     //退出信息
}
  • 数据白板,游戏写给app一些额外数据
cmd: "writeBlackboard"
param :
{
    key,        //string   
    value,        //string 
}

游戏结束时需要将双方玩家的得分传回给小游戏大厅显示:

其中key为PLAYER_ONE_SCORE表示自己,key为PLAYER_TWO_SCORE表示对方;value表示分数,必须为大于0的整数。

  • 设置加载挡板加载进度
支持的版本:versionCode >= 1200
cmd: "setLoadingProgress"
param: "50" // 0~100的整数

1200版本后的小游戏大厅增加了统一的载入面板,CP在准备自身资源的过程中(调用game.ready之前)需要调用该方法上传进度。

注:游戏收到onGameStart后会自动关闭挡板

  • 设置屏幕旋转方向
cmd: "setWebViewOrientation"
param : "landscape" // landscape 横屏; portrait 竖屏
  • 设置Appbar可见性(包括返回按钮,声音,麦克风按钮)
cmd: "setAppBarVisible"
param: "visible" // visible 可见;invisible 不可见
  • 设置麦克风是否启用
cmd: "setVoiceMicrophoneEnable"
param: "enable" // enable 启用; disable 禁用
  • 退出游戏
cmd: "activityQuitGame"
param: 无

事件

  • 麦克风状态变化
    cmd: "onMicStatusChanged"
    param :
    {
      uid,        //string 玩家uid
         status,        //int   0:关闭, 1: 打开
    }
    

7 自有游戏服务端接入方式

前端命令和事件使用lib通用命令和事件。

游戏服务器需要调用平台后端2个API上报开始和结束。

7.1 游戏开始API

7.1.1 接口

http://play.open.oppomobile.com/instant-battle/gameapi/gameStart

7.1.2 请求方式

POST

7.1.3 入参列表

参数名称 参数类型 必填与否 样例取值 参数说明
pkgName string 必须 com.test.www 游戏包名
tableId string 必须 256 桌子ID
tableToken string 必须 cc1128ac63a6e808bdeb8da3ff96d39c 桌子token
playerList string 必须 {"playerlist":["1","2"]} 玩家列表,json字符串,
json字串说明:
playerlist(string数组):所有玩家id
timeStamp string 必须 1526304757000 时间戳,毫秒
sign string 必须 5eca48e0326e8e98a7800c537ae636ed 签名,生成方式参考文末
extension string 可选 拓展字段

7.1.4.出参列表

注意: 出参为json字符串(如:{ "data": "", "errorcode": "0", "errormsg": "ok" })

出参名称 出参类型 样例取值 参数说明
errorcode string 0 错误码
errormsg string ok 错误信息
data string 返回信息

7.2 1v1对战游戏结束API

V1.3版本战斗新增多人对战方式,其中多人对战中分为各自为战、随机组队两种模式,加上之前1v1游戏,目前对战游戏有三种类型。

其中游戏开始接口都是同一个接口,战斗结束,因为各个模式关注得点不一致,所以结束接口有所不同。其中多人对战结束关注是个人,随机组队结束得时候关注得是一个阵营。

7.2.1 1v1对战接口

http://play.open.oppomobile.com/instant-battle/gameapi/gameEnd

7.2.2 1v1对战请求方式

POST

7.2.3 1v1对战入参列表

参数名称 参数类型 必填与否 样例取值 参数说明
pkgName string 必须 com.test.www 游戏包名
tableId string 必须 256 桌子ID
tableToken string 必须 cc1128ac63a6e808bdeb8da3ff96d39c 桌子token
result string 必须 {"resultlist":[{"uid":"1","result":1},{"uid":"2","result":2}]} 对局结果列表,json字符串,
所有玩家在这局游戏的对应结果,一个json对象代表一个玩家的结果.
uid(string):玩家id
result(int):玩家输赢(1获胜,2失败,3平局)
timeStamp string 必须 1526304757000 时间戳,毫秒
sign string 必须 5eca48e0326e8e98a7800c537ae636ed 签名,生成方式参考文末
extension string 可选 拓展字段

7.2.4 1v1对战出参列表

注意: 出参为json字符串(如:{ "data": "", "errorcode": "0", "errormsg": "ok" })

出参名称 出参类型 样例取值 参数说明
errorcode string 0 错误码
errormsg string ok 错误信息
data string 返回信息

7.3多人对战 各自为战游戏结束API

7.3.1 接口

instant-battle/gameapi/settlement/manytomany/solo

7.3.2 请求方式

POST

7.3.3 入参列表

参数名称 参数类型 必填与否 样例取值 参数说明
pkgName string 必须 com.test.www 游戏包名
tableId string 必须 256 桌子ID
tableToken string 必须 cc1128ac63a6e808bdeb8da3ff96d39c 桌子token
result string 必须 {"resultlist":[{"playerId":"10000","score":111,"battleRet":1},{"playerId":"10001","score":222,"battleRet":2},{"playerId":"10002","score":333,"battleRet":3}]} 对战结果列表
timeStamp string 必须 1526304757000 时间戳,毫秒
sign string 必须 5eca48e0326e8e98a7800c537ae636ed 签名,生成方式参考文末
extension string 可选 拓展字段

7.3.4 对战结果列表参数

结果以一个玩家为主,需要传所有玩家在这局游戏的对应结果, 一个json对象代表一个玩家的结果。游戏如果以积分结算,则必须传入积分,如果以胜负结算,必须传入胜负结果。如若传入结果与结算方式不对应,则会调用失败。

参数 类型 参数说明 是否必须
playerId String 玩家id 必须
battleRet Integer 玩家输赢(1获胜,2失败,3平局) 可选
score Integer 游戏业务积分。积分将会再客户端显示 可选

7.3.5 出参列表

注意: 出参为json字符串(如:{ "data": "", "errorcode": "0", "errormsg": "ok" })

出参名称 出参类型 样例取值 参数说明
errorcode string 0 错误码
errormsg string ok 错误信息
data string 返回信息

7.4多人对战 随机组队游戏结束API

7.4.1 接口

/instant-battle/gameapi//settlement/manytomany/teamrandom

7.4.2 请求方式

POST

7.4.3 入参列表

参数名称 参数类型 样例取值 必填与否 参数说明
pkgName string com.test.www 必须 游戏包名
tableId string 256 必须 桌子ID
tableToken string cc1128ac63a6e808bdeb8da3ff96d39c 必须 桌子token
result string {"resultlist":[{"campId":"1","battleRet":1, "score": 100},{"campId":"2","battleRet":2, "score": 133},{"campId":"3","battleRet":3, "score":220}]}} 必须 对局结果列表
timeStamp string 1526304757000 必须 时间戳,毫秒
sign string 5eca48e0326e8e98a7800c537ae636ed 必须 签名,生成方式参考文末
extension string 可选 拓展字段

7.4.4 对战结果列表

结果以一个阵营为主,需要传所有玩家在这局游戏的对应结果, 一个json对象代表一个玩家的结果。游戏如果以积分结算,则必须传入积分,如果以胜负结算,必须传入胜负结果。如若传入结果与结算方式不对应,则会调用失败。

参数 类型 参数说明 是否必须
campId String 阵营id 必须
battleRet Integet 玩家输赢(1获胜,2失败,3平局) 可选
score Integer 游戏业务积分。积分将会再客户端显示 可选

7.4.5 出参列表

注意: 出参为json字符串(如:{ "data": "", "errorcode": "0", "errormsg": "ok" })

出参名称 出参类型 样例取值 参数说明
errorcode string 0 错误码
errormsg string ok 错误信息
data string 返回信息

7.5 错误码列表

errorcode errormsg 描述
0 ok 请求成功
10001 parameter is error 参数错误
10002 sign is error 签名错误
20001 system error 系统错误
30001 table not exist 桌子不存在
30002 Inconsistent player list 玩家列表不一致
30003 table info error 桌子信息错误
30004 tableToken is error 桌子token错误
30005 tableId is error 桌子ID错误
40001 game error 游戏错误
40002 game pkgName is error 游戏包错误

7.6 签名生成

Step 1 构造源串

  • 构造源串所需参数
    • pkgName(游戏包名)
    • appKey(游戏上架时分配的Key)
    • appSecret(游戏上架时分配的密钥)
    • tableToken(桌子token)
    • tableId(桌子ID)
    • timeStamp(时间戳)
  • 将参数按照字典序排序,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串。
  • 注意:
    • 参数名区分大小写
  • 示例
    str = "appKey=11&appSecret=22&pkgName=com.oppo.testgame&tableId=969&tableToken=33&timeStamp=15281"
    

Step 2 生成sign值

  • 使用 md5 算法对构造的源串进行加密,将得到的字符串所有字符转换为大写
  • 示例
    7224B81F66699C774B4AF6A8E4837E62
    

7.7 游戏流程

1.游戏调用init初始化lib。

2.游戏调用infoReq 查询本局信息。

3.游戏连接自己的服务器,开始游戏 ,游戏服调用游戏开始API通知平台。

4.游戏结束,客户端调用writeBlackboard写入结算信息字符串(key见前文api描述),游戏服调用游戏结束API通知平台。

5.其他游戏异常,调用 forceQuit 命令强制退出。

8 无服务端接入方式

无游戏服务端方式下,通过大厅对战服来打通双方客户端的消息管道,前端需要使用到更多的命令和事件

8.1 命令API

8.1.1 对战接口

  • 游戏初始化完毕,准备
cmd: "game.ready"
param :
{
    param,        //string 游戏业务附带数据
}
  • 发送游戏消息请求

    V1版本

cmd: "game.broadcast"
param :
{
    msg,            //string 游戏消息 ,注: 游戏协议需cp自定义协议需自行进行序列化为string类型
    excptSelf,        //int 是否排除自己,0:不排除,1:排除
}
param2 : msg

V2版本

cmd: "game.broadcast"
param :
{
    excptSelf,        //int 是否排除自己,0:不排除,1:排除
}
param2 : msg         //string 游戏消息 ,注: 游戏协议需cp自定义协议需自行进行序列化为string类型
  • 游戏结束请求(有胜负)
cmd: "game.finish"
param :
{
    winner, //string 胜利者uid
}
  • 游戏结束请求(平局)
    版本需求:versionCode >= 1002
    
cmd: "game.finishDraw"
param : {}

8.1.2 多人对战接口(1.3.0)

以下接口为1.3.0后新增的多人对战接口

  • 组内广播消息

向同一小组内的所有玩家广播消息。(仅限于多人对战的随机组队类型的游戏)

版本需求:versionCode >= 1300
cmd: "game.teamBroadcast"
param: 
{
    excptSelf,    //int 是否排除自己,0:不排除,1:排除
}
param2 : msg    //string 游戏消息 ,注: 游戏协议需cp自定义协议需自行进行序列化为string类型
  • 指定玩家发送消息

向指定的玩家发送消息。

版本需求:versionCode >= 1300
cmd: "game.sendMsgToPlayers"
param:
{
    playerIds,    // string array 需要发送的玩家id数组
}
param2 : msg    //string 游戏消息 ,注: 游戏协议需cp自定义协议需自行进行序列化为string类型

8.2 事件

8.2.1 对战接口

  • 游戏正式开始事件
cmd: "game.onStart"
param :
{
    param,        //string 游戏业务附带数据
}
  • 游戏结束事件

    cmd: "game.onEnd"
    param : {}
    
  • 收到游戏消息事件

    V1版本

    cmd: "game.onRecvMsg"
    param :
    {
      uid,     //string 发送者uidf
      msg,    //string 游戏消息
    }
    

    V2版本

cmd: "game.onRecvMsg"
param :
{
    uid,     //string 发送者uid
}
param2 : msg   //string 游戏消息

8.1.2 多人对战接口(1.3.0)

  • 收到组内广播的消息(仅限于多人对战的随机组队类型的游戏)
版本需求:versionCode >= 1300
cmd: "game.onRecvTeamMsg"
param :
{
    campId,    // String 
    uid        //string 发送者uid
}
param2 : msg   //string 游戏消息
  • 收到其他玩家向指定玩家发送的消息
版本需求:versionCode >= 1300
cmd: "game.onRecvPlayerMsg"
param :
{
    uid,        //string 发送者uid
}
param2 : msg    //string 游戏消息
  • 收到玩家离开时的消息
版本需求:versionCode >= 1300
cmd: "game.onUserEscape"
param : 
{
    uIdList :    // array 离开的玩家的id数组
}

8.3 游戏流程

1.游戏调用init初始化lib。

2.游戏调用infoReq 查询本局信息。

3.游戏初始化,调用game.ready

4.游戏收到game.onStart,开始执行对局玩法。

5.游戏调用game.broadcast发送业务消息给其他玩家。

6.游戏调用game.finish 上报游戏结束请求。

7.游戏收到game.onEnd , 本局对局结束,写入游戏客户端调用writeBlackboard写入结算信息字符串。(key见前文api描述)

9 游戏资源包打包说明

将游戏打包为签名包,采用jdk自带的keytool 和 jarsigner工具,为标准的jar打签名包方式。

  1. 用keytool 生成keystore,如有keystore则跳过该步骤。

  2. 在h5资源包中需增加 manifest.json文件(建议utf-8 无bom格式),与index.html同级目录,内容如下

    package: 为包唯一标示,

    name:为外显名称,

    icon:暂时预留

    versionName : 外显版本

    versionCode : 游戏版本号,必须为整数

    minPlatformVersion : 对战平台最低能力版本号

{
  "package": "com.company.unit",
  "name": "游戏1",
  "icon": "",
  "versionName": "1.0",    
  "versionCode": 1,
  "minPlatformVersion": 1
}
  1. 用zip工具打包,保证manifest.json等资源为根一级。

  2. 使用jarsigner 将zip包和keystore打为签名包,扩展名由zip改为gpk,提交审核。

    目录结构参考 可参考示例: 示例h5demo.

生成keystore示例

keytool -genkey -keystore testkeypair.keystore -alias testkeypair -keyalg RSA -keysize 2048 -sigalg MD5withRSA -validity 99999

jarsigner 打签名示例

jarsigner -verbose -keystore testkeypair.keystore -signedjar signed.zip unsigned.zip -digestalg SHA1 -sigalg MD5withRSA testkeypair

10 挡板的使用

(游戏必须接入挡板,不接入挡板,将导致游戏加载时,进度条丢失,无法通过测试审核)

对战游戏的加载挡板功能怎么兼容?

通过命令infoRsp获取到的大厅版本号进行判断,从而进一步做兼容性处理。
若大厅版本号小于1200,则使用自己开发的挡板能力。
若大厅版本号大于等于1200,则使用大厅提供的挡板能力。通过setLoadingProgress命令设置进度,在游戏收到onGameStart后会自动关闭挡板。

    var t = 0;
    var interval = setInterval(function() {
    // 模拟加载

    console.log("setLoadingProgress " + t)
    // gameInfo 对象的获取请参考对战游戏的Demo
    if (gameInfo.versionCode && gameInfo.versionCode > 1200) {
        msgChannel.send("setLoadingProgress", t)
    } else {
        // 请添加兼容老版本大厅的展示自定义挡板逻辑
    }

    t += 20;
    if (t > 100) {
        clearInterval(interval)
        interval = null

        // 请添加兼容老版本大厅的关闭自定义挡板逻辑代码

        //5. game ready
        msgChannel.send("game.ready","{}");
    }

    }, 1000)

11 Demo

自有服务端接入方式

"use strict"

var gameInfo = {}        //查询到的对局信息
var appKey = "xyz";    //cp app key
var appSecret = "xyz";    //cp secret key
var msgChannel = BattlePlatform.msgChannel;

//-----------game logic-----------------

//初始化lib库
function init(mode){
    var data = {"libVer":BattlePlatform.version,"mode":mode};
    msgChannel.send("init",BattlePlatform.objToJson(data));
}

//获取对局信息请求
function infoReq(appKey, appSecret){
    msgChannel.send("infoReq",BattlePlatform.objToJson({"appKey":appKey, "appSecret":appSecret}));
}

//强制退出
function forceQuit(reason,message){
    var data = {};
    data.reason = reason;
    data.message = message;
    var json = BattlePlatform.objToJson(data);
    msgChannel.send("forceQuit",json);
}

//写数据白板
function writeBlackboard(key,value){
    var data = {};
    data.key = key;
    data.value = value;
    var json = BattlePlatform.objToJson(data);
    msgChannel.send("writeBlackboard",json);
}


//---------------game init -----------------------------

function gameInit(){
    console.log("game init!");
}

console.log("game js loaded!");
//1. 设置管道回调
msgChannel.setRecvCallback(function(cmd,param){
    console.log("java cmd:"+cmd);

    if(cmd == "infoRsp"){
        gameInfo = BattlePlatform.jsonToObj(param);
        //4.init game
        gameInit();
        //cp 后续游戏逻辑
    }
})

//2. 初始化lib库
init(0);

//3.获取对局数据
infoReq(appKey, appSecret);

非自有服务端接入方式

"use strict"


var gameInfo = {}        //查询到的对局信息
var appKey = "xyz";    //cp app key
var appSecret = "xyz";    //cp secret key
var msgChannel = BattlePlatform.msgChannel;

//-----------game logic--------------

function init(mode){
    var data = {"libVer":BattlePlatform.version,"mode":mode};
    msgChannel.send("init",BattlePlatform.objToJson(data));
}

function infoReq(appKey, appSecret){
    msgChannel.send("infoReq",BattlePlatform.objToJson({"appKey":appKey, "appSecret":appSecret}));
}

function forceQuit(reason,message){
    var data = {};
    data.reason = reason;
    data.message = message;
    var json = BattlePlatform.objToJson(data);
    msgChannel.send("forceQuit",json);
}

function writeBlackboard(key,value){
    var data = {};
    data.key = key;
    data.value = value;
    var json = BattlePlatform.objToJson(data);
    msgChannel.send("writeBlackboard",json);
}

//游戏准备请求
function setReady(param){
     var data = {};
     data.param = param;
     var json = BattlePlatform.objToJson(data);
     msgChannel.send("game.ready",json);
}

//游戏结束请求
function setFinish(winner){
    var data = {};
    data.winner = winner;
    var json = BattlePlatform.objToJson(data);
    msgChannel.send("game.finish",json);
}

//发送游戏协议广播
function broadcast(msg,excptSelf){
    var data = {};
    data.excptSelf = 1;
    if(excptSelf){
        data.excptSelf = excptSelf;
    }
    var json = BattlePlatform.objToJson(data);
    msgChannel.send2("game.broadcast",json,msg);
}

//收到游戏协议
function onRecvGameMsg(uid,param,param2){
    var data = BattlePlatform.jsonToObj(param);
    var uid = data.uid;
    var msg = param2;
}

//游戏开始通知
function onGameStart(param){
    console.log("game start!");
    var data = BattlePlatform.jsonToObj(param);
    //cp 游戏开始
}

//游戏结束通知
function onGameEnd(param){
    console.log("game end!");
    var data = BattlePlatform.jsonToObj(param);
    //cp 游戏结束
}

//---------------game init ------------------------------
function gameInit(){
    console.log("game init!");
    //cp todo...
}

console.log("game js loaded!!!");
//1. 设置回调
msgChannel.setRecvCallback(function(cmd,param,param2){
    console.log("java cmd:"+cmd);
    if(cmd == "infoRsp"){
        gameInfo = BattlePlatform.jsonToObj(param);
        //4.初始化工作
        gameInit();
        //5. 游戏开始准备请求
        setReady("{}");
    }

    if(cmd == "game.onStart"){
        //6. 游戏正式开始
        onGameStart(param);
    }

    if(cmd == "game.onEnd"){
        //7. 游戏结束
        onGameEnd(param);
    }

    if(cmd == "game.onRecvMsg") {
        onRecvGameMsg(uid,param,param2);
    }
})

//2. 初始化lib库
init(0);

//3.获取游戏对局数据
infoReq(appKey, appSecret);

12 注意事项

  • 若对战游戏上过线,后续在本地调试时,需要更新下 versionCode 版本号,才能访问到最新的游戏代码
  • 对战游戏需要把 rpk 包和配置文件 debug_config.json 一起放到 /sdcard/Android/data/com.nearme.play/files/ 目录下,若期间清除过调试器缓存,则 /sdcard/Android/data/com.nearme.play/files/ 目录也会一起被清除
  • appKey 和 appSecret 需要联系商务申请获取

results matching ""

    No results matching ""