大厅功能:修订间差异
Liuweichen(留言 | 贡献) |
Liuweichen(留言 | 贡献) |
||
(未显示同一用户的21个中间版本) | |||
第1行: | 第1行: | ||
== 泡饭工坊模板demo地址 == | |||
泡饭中,hall_test模板,有完整代码 | |||
* [[File:泡饭大厅工程.png]] | |||
下载模板 | |||
我的工程打开hall_test模板 | |||
编译&启动(大厅) | |||
== 网页试玩链接多人demo体验地址 == | |||
[试玩链接]( https://subgame.popx.com/popion/opendev.html) | |||
* 如果是新号,在PC端ctrl +6,打开特殊窗口,输入 “isover 1”,点击按钮,可直接跳过新手流程! | |||
* [[File:跳过引导.png]] | |||
* 在游戏界面游玩中,找到demox,点击进入即可 | |||
* [[File:Demo地址.png]] | |||
== 老项目升级环境配置 == | == 老项目升级环境配置 == | ||
如果本来的项目,是通过demox生成的,并没有大厅,需要按照如下的操作来升级。 | |||
如下的拷贝文件来源,是hall_test的项目 | |||
=== 添加src/hall/index.ts的大厅服务器入口文件 === | === 添加src/hall/index.ts的大厅服务器入口文件 === | ||
第35行: | 第58行: | ||
每个目录的代码文件入口都在各自的'''index.ts'''里 | 每个目录的代码文件入口都在各自的'''index.ts'''里 | ||
[[File:大厅文件结构.png]] | [[File:大厅文件结构.png]] | ||
第231行: | 第255行: | ||
=== 存储 === | === 存储 === | ||
<span style="color: red;">'''存储只能由hall或者host发起,两个服务器都有同名的存储接口'''</span> | <span style="color: red;">'''存储只能由hall或者host发起,两个服务器都有同名的存储接口'''</span> | ||
<span style="color: red;">'''该功能没有必要接入大厅,直接调用host中的代码接口也可以存储和读取'''</span> | |||
<span style="color: red;">'''调用该功能前,请务必根据自身gameid向我们内部申请一个对应的数字id来存盘使用'''</span> | |||
demo中,写在了hall里面,host里也可以写一份一样的,这样战斗和大厅的数据就都能存储了. | demo中,写在了hall里面,host里也可以写一份一样的,这样战斗和大厅的数据就都能存储了. | ||
第321行: | 第349行: | ||
* [[File:db存储结构.png]] | * [[File:db存储结构.png]] | ||
=== KeyValue数据存盘 === | |||
简单的物品类型并不足以支持复杂的游戏数据结构,我们也提供了和物品存储类似的数据结构存储 | |||
同样是在hall和host中都可以调用 | |||
监听的函数用'''onDbDataChange''' | |||
<pre> | |||
XPopManager.instance.xHostHall.onDbDataChange; | |||
XPopManager.instance.xHost.onDbDataChange; | |||
</pre> | |||
存储的函数用SetDbDatas | |||
<pre> | |||
// 存储设置自定义key-value | |||
ret = await this.hall.SetDbData() | |||
// 存储整个map的keyvalue合集 | |||
ret = await this.hall.SetDbDatas() | |||
</pre> | |||
* [[File:存盘复杂数据.png]] | |||
如函数参数中所示,存储的value是string类型, | |||
那么可以通过JSON.stringify(obj)和JSON.parse(str)来相互转换,从而存储复杂数据 | |||
* 注意:如上是hall的存储读取示例,如果想用host,接口类似,在如下的论坛帖子里有演示。 | |||
[host存储数据](https://bbs.popx.com/t/keyvalue-ondbdatachange/207/14?u=qc_jump) | |||
== 匹配逻辑 == | == 匹配逻辑 == | ||
第328行: | 第387行: | ||
=== 创建匹配规则 === | === 创建匹配规则 === | ||
匹配前,一定要创建至少一个匹配规则的名称,否则无法匹配 | |||
参考demo中,在hall代码的初始阶段就要设置 | |||
如下是添加了更加详细的注释代码,其中段位相关的规则可以先不添加 | |||
<pre> | <pre> | ||
第343行: | 第404行: | ||
rules.addMapName(this.matchMapName); | rules.addMapName(this.matchMapName); | ||
// | // 选填更复杂的段位规则,根据段位来设置规则,如果不添加,就会无规则随意匹配 | ||
{ | { | ||
let | for(let i =0;i<9;i++) | ||
{ | |||
let duanLevel = i+1; | |||
this.addRulesDuan(rules,duanLevel) | |||
} | |||
} | } | ||
// 调用添加matchRuleName为key的匹配规则,可以调用添加多个, | // 调用添加matchRuleName为key的匹配规则,可以调用添加多个, | ||
// 添加后,才可以通过this.hall.UserBeginMatch,根据matchRuleName进行匹配 | // 添加后,才可以通过this.hall.UserBeginMatch,根据matchRuleName进行匹配 | ||
第375行: | 第423行: | ||
*必须添加至少一条规则后,才可以通过this.hall.UserBeginMatch,<span style="color: red;">'''根据matchRuleName来映射到具体规则和地图列表,进行匹配'''</span> | *必须添加至少一条规则后,才可以通过this.hall.UserBeginMatch,<span style="color: red;">'''根据matchRuleName来映射到具体规则和地图列表,进行匹配'''</span> | ||
==== 详细段位规则 ==== | |||
上面的基础规则代码中,有一部分在添加段位规则,并且一个XMatchRule对应了多个段位规则 | |||
<pre> | |||
private addRulesDuan(rules: XMatchRule,duanLevel:number = 1):void | |||
{ | |||
let danRule = new XDanRule(); | |||
// 匹配分数区间,匹配时,根据传入的分数,来找到符合区间的duanRule,找不到那就没有规则 | |||
danRule.nMinScore = (duanLevel - 1) * 1000; | |||
danRule.nMaxScore = duanLevel * 1000; | |||
// 比如初始分数区间为1000-2000, | |||
// 玩家是1500分,玩家就匹配到了这个段的规则 | |||
// 每个匹配规则里,可以分成多个段位,比如青铜,王者,通过id来区分各个段位的匹配规则 | |||
danRule.nDanID = duanLevel; | |||
// 1阶段匹配时间 | |||
danRule.nMatchTime1 = 15; | |||
// 1阶段时,可以根据震荡区间来扩大搜索范围.比如本身是匹配1000-2000,添加后变成了900-2100 | |||
danRule.AddScore = 100; | |||
// 1阶段的时间结束,房间人还没满,会进入2阶段 | |||
// 2阶段匹配时间 | |||
danRule.nMatchTime2 = 15; | |||
// 2阶段时,可以根据震荡区间来扩大搜索范围.比如本身是匹配1000-2000,添加后变成了1800-2200 | |||
danRule.AddScoreMax = 200; | |||
// 匹配2阶段后,是否塞人机数量 | |||
// 已经实现了把人机的数据塞进战斗房间 | |||
// 比如XMatchRule里的nRoleNum = 8,nAINum = 2,那么当房间人数为6时,就会进入游戏(2阶段后) | |||
danRule.nAINum = Config.MatchNumMax - Config.MatchNumMin > 0 ? Config.MatchNumMax - Config.MatchNumMin : 0; | |||
rules.addDanRule(danRule); | |||
} | |||
</pre> | |||
<pre> | |||
// 可以通过接口来获取具体的玩家信息,玩家信息中有字段来标记是否为机器人 | |||
// host接口 | |||
XPopManager.instance.xHost.GetUserInfo(userid).isRobot | |||
// 前端接口 | |||
XPopManager.instance.xRemote.GetUserInfo(userid).isRobot | |||
</pre> | |||
=== 通过匹配规则匹配 === | === 通过匹配规则匹配 === | ||
*<span style="color: red;">'''matchRuleName'''</span>必须要先添加 | *<span style="color: red;">'''matchRuleName'''</span>必须要先添加 | ||
* | *rankScore对应匹配规则中的分数,根据实际开发的业务数据来,分数会对应到详细的段位规则里 | ||
*<span style="color: red;">'''ExtraData'''</span>是透传参数,可以在匹配成功进入战斗服中获取到 | *<span style="color: red;">'''ExtraData'''</span>是透传参数,可以在匹配成功进入战斗服中获取到 | ||
第437行: | 第532行: | ||
== 开房间 == | == 开房间 == | ||
开房间功能建议在试玩链接里体验,目前房间列表只在试玩里开放 | |||
=== 接入开房间组件 === | === 接入开房间组件 === | ||
参考demo中HallUI的代码,一行即可,在点击创建房间按钮后触发 | 参考demo中HallUI的代码,一行即可,在点击创建房间按钮后触发 | ||
<pre> | <pre> | ||
XPopManager.instance.advancedComponentMgr.addComponent("CreateRoomComponent"); | XPopManager.instance.advancedComponentMgr.addComponent("CreateRoomComponent"); | ||
</pre> | </pre> | ||
====房主在大厅内点击创建房间==== | |||
* [[File:创建房间.png]] | |||
创建房间可以选择地图,具体能选择的地图需要在审核后台配置 | |||
====其他人加入房间==== | |||
1.可以在房间界面内,接入邀请好友组件,拉取好友或者微信好友加入房间 | |||
<pre> | |||
/** | |||
* 组件--邀请 | |||
*/ | |||
private Component_Invitation(): void { | |||
let invitation = XPopManager.instance.advancedComponentMgr.addComponent('InvitationComponent'); | |||
invitation.top = 60; | |||
invitation.right = 10; | |||
invitation.left = null; | |||
invitation.panel.top = 120; | |||
invitation.panel.bottom = null; | |||
invitation.panel.right = 0; | |||
invitation.panel.bangAdapter = true; | |||
invitation.panel.tweenType = 'Right'; | |||
} | |||
</pre> | |||
2.其他人可以通过搜索房间列表加入房间 | |||
* [[File:创建房间2.png]] | |||
* [[File:创建房间3.png]] | |||
=== 房间内显示逻辑 === | === 房间内显示逻辑 === | ||
*<span style="color: red;">'''强调一个概念,开房间组件,相当于是在大厅里,忽略了匹配过程,直接把玩家拉到了host里面'''</span> | *<span style="color: red;">'''强调一个概念,开房间组件,相当于是在大厅里,忽略了匹配过程,直接把玩家拉到了host里面'''</span> | ||
*<span style="color: red;">'''被拉进该房间的玩家,会完整的处理进入hall以及host的各种流程,也就是说所有生命周期回调都会有反应,一定是先进hall再进host'''</span> | |||
*<span style="color: red;">'''在房主创建房间进入时,以及其他人在大厅找到房间进入时,都会触发host的onUserEnter'''</span> | *<span style="color: red;">'''在房主创建房间进入时,以及其他人在大厅找到房间进入时,都会触发host的onUserEnter'''</span> | ||
第462行: | 第590行: | ||
-- 战斗状态就进入战斗逻辑(其实都是战斗服务器里的逻辑) | -- 战斗状态就进入战斗逻辑(其实都是战斗服务器里的逻辑) | ||
-- 具体的状态管理可以参考demo代码,由开发者自己写状态机 | -- 具体的状态管理可以参考demo代码,由开发者自己写状态机 | ||
== 启动本地大厅 == | |||
本地调试时,登录界面,勾选本地大厅即可 | |||
* [[File:勾选本地大厅.png]] | |||
只要勾选一个本地大厅就可以了,另一个账号登录时也会进入此大厅 |
2025年3月12日 (三) 07:18的最新版本
泡饭工坊模板demo地址
泡饭中,hall_test模板,有完整代码
下载模板
我的工程打开hall_test模板
编译&启动(大厅)
网页试玩链接多人demo体验地址
[试玩链接]( https://subgame.popx.com/popion/opendev.html)
老项目升级环境配置
如果本来的项目,是通过demox生成的,并没有大厅,需要按照如下的操作来升级。
如下的拷贝文件来源,是hall_test的项目
添加src/hall/index.ts的大厅服务器入口文件
修改打包配置rollup
- rollup.config.js新增打包大厅index.js的配置
- rollup.config.js加一下服务类的白名单
修改html启动文件
- 拷贝覆盖index.html到你的项目中,拷贝hall.html本地大厅文件到同一文件夹下
审核后台勾选大厅
只有勾选了大厅后,登录流程才会走大厅的逻辑,否则是走的老的流程,直接进战斗房间
大厅游戏工作流说明
大厅工程相对于原来的client,server目录结构,多了一个hall目录,而且server实际上指的是host,
每个目录的代码文件入口都在各自的index.ts里
为了方便大家理解,我们用颜色来标记各个核心文件夹的工作流
client用橙色,代表前端显示,前端逻辑
hall用绿色,代表大厅,大厅服务器逻辑
host用蓝色,注意,为了不和开房间混淆,host代表的是战斗服务器逻辑,而不是和以前一样叫做房间
client的入口代码最早执行,在里面做各种监听,也就是说,大厅期间,各种前端界面UI就已经能自己处理了,可以调用大厅的数据
以下的流程,如果审核后台勾选了大厅,按照顺序执行,否则直接跳过大厅,到了《进入战斗》
游戏开始时
进大厅前预加载资源
client:XPopManager.onHallWait
--在进入大厅前,会有一个promise的异步接口供开发者使用去预加载资源,比如表格,比如读取文件配置等等。
必须在加载完成的回调中resolve
//预加载资源 XPopManager.onHallWait = new Promise((resolve)=>{ GameManager.instance.onPreLoadRes(()=>{ resolve("Resource loaded successfully hall"); }); });
进入大厅
client:XPopManager.onHallStart
--在大厅资源预加载完成后,会直接启动大厅服务器实例
hall:XPopManager.onHostHallStart
--src/hall/index.ts 中监听的代码入口
大厅期间操作
监听大厅内数据变化
大厅期间,hall的实例会监听各种玩家的事件,并且抛出回调,开发者可以在回调中处理hall的快照数据
hall的实例是指XPopManager.instance.xHostHall
hall:hall.onUserEnter
--大厅内有玩家进入
hall:hall.onUserLeave
--大厅内有玩家离开
hall:hall.onUserMatchChange
--大厅内匹配信息发生变化,主要是指倒计时的变化
hall:hall.onDbItemChange
--大厅内存盘的数据变化,在进入时就会调用一次,获取到账号DB数据,存盘后面再说
开始匹配
匹配内容后面单独讲
匹配成功
后面匹配内容会单独讲, 匹配成功后,分配到了某个房间的实例(host),并且会把匹配时的透传参数通知给host实例
进入战斗
host:XPopManager.onHostStart --src/server/index.ts 中监听的代码入口,去处理host实例的各种回调
战斗期间操作
监听host战斗服内数据变化
host的实例是指XPopManager.instance.xHost host:host.onUserEnter
--当战斗服务器内有玩家进入
host:host.onUserLeave
--当战斗服务器内有玩家离开
host:host.onUserMatchExtraDataReceived
--当战斗服务器收到玩家透传信息(匹配时传入的ExtraData)
host:host.onDbItemChange
--当战斗服务器收到存盘的数据变化,在进入时就会调用一次,获取到账号DB数据,存盘后面再说
战斗返回大厅
client:XPopManager.onGameLeave
--返回到大厅,大厅的数据还在快照中,可以做一些结算的处理
想要回到大厅,需要手动调用XPopManager.instance.xRemote.LeaveGame ,demo里有示例
XPopManager.instance.xRemote.LeaveGame(this, (code: number, ret: string) => { console.log('LeaveGame', code, ret); });
离开整个游戏
client:XPopManager.onExit
--在试玩的时候,点击官方左上角的退出,会进入此回调函数
--平时本地调试开发时,不需要去处理这个回调
--但是试玩时需要在此销毁场内资源,否则,退出后再次进入,会发现上一回的模型还在
XPopManager.onExit = () => { model.destroy(); }
前后端数据交互
交互只能client和hall,client和host之间互通信息,不能hall和host直接交互
client和hall的交互
所有的和大厅的数据交互,依赖于
client内部代码:this._remoteHall = XPopManager.instance.xRemote.hall
hall内部代码:this.hall = XPopManager.instance.xHostHall
具体代码位置在各自文件夹内
- 1.client向hall注册快照,并且监听快照变化
- 2.hall注册rcp请求的回调方法
- 3.client向hall发起rpc请求
- 4.hall处理rpc请求,hall修改快照
- 5.client监听快照变化的回调,处理显示逻辑
具体可以查看MessageManager中的代码
client注册快照
代码里有私有和共有快照,实际上本质上都是最基本的注册快照,只是在hall里面处理数据的方式不一样,具体可以看代码,不再赘述
this._remoteHall.RegisterSnapshot(`${Snap_HallData.tag}`, this._hallData);
client监听快照变化
this._hallData.notice.OnSet = (bReset) => { XTipManager.Instance.showTip(this._hallData.notice.value); }
hall注册rpc回调
this.hall.RegisterRpc('AddDbItem', this.onReceiveAddDbItem.bind(this));
client发起rpc请求
public async Hall_Request_AddItem(type:DBItemType, itemID:ItemNormalID, itemNum:number, callback?: Function): Promise<void> { let ret = await this._remoteHall.Request("AddDbItem", { type: type, actorID: this._userID, itemID: itemID, itemNum: itemNum }); console.log('requestAddDbItem', ret); callback && callback(ret); }
hall处理rpc请求,修改快照
private async onReceiveAddDbItem(call: ApiCall<ReqAddDbItem, ResAddDbItem>): Promise<void> { console.log('>>>>>>onReceiveAddDbItem'); // 修改某个快照,前端已经注册过处理函数 }
client和host的交互
所有的和战斗服的数据交互,依赖于
client内部代码:this._remoteBattle = XPopManager.instance.xRemote.game;
host内部代码(server文件夹):this.host = XPopManager.instance.xHost;
所有的流程和hall一样处理
数据存盘
数据存盘对应的是玩家登录时的账号id,调用存盘后,就有账号的长期数据可以记录和读取了
存储
存储只能由hall或者host发起,两个服务器都有同名的存储接口
该功能没有必要接入大厅,直接调用host中的代码接口也可以存储和读取
调用该功能前,请务必根据自身gameid向我们内部申请一个对应的数字id来存盘使用
demo中,写在了hall里面,host里也可以写一份一样的,这样战斗和大厅的数据就都能存储了.
如下示例代码的发起方是client通过rpc去通知hall发起的,实际上可以在服务器计算过程中自己发起
说几个关键的参数:
- dbID
-- 需要开发者在我们的审核后台,获取了游戏id之后,把游戏id的字符串给我们的内部人员, -- 然后我们帮开发者映射生成一个数字的id,专门来存储该游戏的数据, -- 以后存盘读盘时就走的这个数字id
- type
-- 存盘的时候还有个type,支持填写0到9,可以用于开发者处理不同类型的数据分类。 -- 比如0代表货币类型,1代表背包道具,2代表头像。。等等 -- 当然,全存在一个type里也没影响,因为可以根据唯一的itemID去读自己的表格
- itemID
-- 开发者存储时的自定义id,用于自己游戏内的道具表格映射,请保持id的唯一性,不要有同id的道具
private async onReceiveAddDbItem(call: ApiCall<ReqAddDbItem, ResAddDbItem>): Promise<void> { console.log('>>>>>>onReceiveAddDbItem'); let userdata = this._usersMap.get(call.req.actorID); if (!userdata) { return; } if(call.req.type == DBItemType.Normal && call.req.itemID == ItemNormalID.Gold){ let ret; if(userdata.goldCount.value == -1){ let item = new XDbItem(); item.nID = call.req.itemID; item.nCount = call.req.itemNum; ret = await this.hall.AddDbItem(this.dbID, call.req.actorID, call.req.type, call.req.itemID, item, this); }else{ ret = await this.hall.SetDbItemCount(this.dbID, call.req.actorID, call.req.type, call.req.itemID, call.req.itemNum+userdata.goldCount.value, this); } return call.succ({ ret: ret.ret }); }else{ return call.succ({ ret: '未实现' }); } }
读取
在hall和host中,都有一个监听函数
XPopManager.instance.xHostHall.onDbItemChange; XPopManager.instance.xHost.onDbItemChange;
每次当存盘的数据发生变化,都会进入该回调函数。 hall和host连接成功后,也会先进入一次,所以进游戏就能获得存盘数据
我们以hall里的代码举例
private onDbItemChange(type: number, key: number, value: XDbItem | null, iUserID: number, bReset: boolean):void{ if(type == DBItemType.Normal && key == ItemNormalID.Gold){ let userdata = this._usersMap.get(iUserID); if (!userdata) { return; } userdata.goldCount.value = value.nCount; } }
- type
-对应传入的type
- key
—对应存储的itemId
- value: XDbItem
其中,XDbItem的结构是我们DB中固定的格式,外部只需要关心nID和nCount即可
nID对应存储时传入的唯一itemId nCount对应DB中该物品的数量
KeyValue数据存盘
简单的物品类型并不足以支持复杂的游戏数据结构,我们也提供了和物品存储类似的数据结构存储
同样是在hall和host中都可以调用
监听的函数用onDbDataChange
XPopManager.instance.xHostHall.onDbDataChange; XPopManager.instance.xHost.onDbDataChange;
存储的函数用SetDbDatas
// 存储设置自定义key-value ret = await this.hall.SetDbData() // 存储整个map的keyvalue合集 ret = await this.hall.SetDbDatas()
如函数参数中所示,存储的value是string类型,
那么可以通过JSON.stringify(obj)和JSON.parse(str)来相互转换,从而存储复杂数据
- 注意:如上是hall的存储读取示例,如果想用host,接口类似,在如下的论坛帖子里有演示。
[host存储数据](https://bbs.popx.com/t/keyvalue-ondbdatachange/207/14?u=qc_jump)
匹配逻辑
匹配逻辑在hall中处理
创建匹配规则
匹配前,一定要创建至少一个匹配规则的名称,否则无法匹配
参考demo中,在hall代码的初始阶段就要设置
如下是添加了更加详细的注释代码,其中段位相关的规则可以先不添加
/** * 初始化匹配规则 */ private initMatchRule(): void { let rules = new XMatchRule(); // 需求人数 必填 rules.nRoleNum = Config.MatchNumMax; // 地图列表 - 匹配成功后,会从中随机创建一个地图 必填,如果填一张就是唯一一张图 rules.addMapName(this.matchMapName); // 选填更复杂的段位规则,根据段位来设置规则,如果不添加,就会无规则随意匹配 { for(let i =0;i<9;i++) { let duanLevel = i+1; this.addRulesDuan(rules,duanLevel) } } // 调用添加matchRuleName为key的匹配规则,可以调用添加多个, // 添加后,才可以通过this.hall.UserBeginMatch,根据matchRuleName进行匹配 this.hall.AddGameMatchRules(this.matchRuleName, rules, this); }
- 通过this.hall.AddGameMatchRules(this.matchRuleName, rules, this);来添加至少一条匹配规则,
- 其中matchRuleName为key,可以多次添加不同的key和rules
- 必须添加至少一条规则后,才可以通过this.hall.UserBeginMatch,根据matchRuleName来映射到具体规则和地图列表,进行匹配
详细段位规则
上面的基础规则代码中,有一部分在添加段位规则,并且一个XMatchRule对应了多个段位规则
private addRulesDuan(rules: XMatchRule,duanLevel:number = 1):void { let danRule = new XDanRule(); // 匹配分数区间,匹配时,根据传入的分数,来找到符合区间的duanRule,找不到那就没有规则 danRule.nMinScore = (duanLevel - 1) * 1000; danRule.nMaxScore = duanLevel * 1000; // 比如初始分数区间为1000-2000, // 玩家是1500分,玩家就匹配到了这个段的规则 // 每个匹配规则里,可以分成多个段位,比如青铜,王者,通过id来区分各个段位的匹配规则 danRule.nDanID = duanLevel; // 1阶段匹配时间 danRule.nMatchTime1 = 15; // 1阶段时,可以根据震荡区间来扩大搜索范围.比如本身是匹配1000-2000,添加后变成了900-2100 danRule.AddScore = 100; // 1阶段的时间结束,房间人还没满,会进入2阶段 // 2阶段匹配时间 danRule.nMatchTime2 = 15; // 2阶段时,可以根据震荡区间来扩大搜索范围.比如本身是匹配1000-2000,添加后变成了1800-2200 danRule.AddScoreMax = 200; // 匹配2阶段后,是否塞人机数量 // 已经实现了把人机的数据塞进战斗房间 // 比如XMatchRule里的nRoleNum = 8,nAINum = 2,那么当房间人数为6时,就会进入游戏(2阶段后) danRule.nAINum = Config.MatchNumMax - Config.MatchNumMin > 0 ? Config.MatchNumMax - Config.MatchNumMin : 0; rules.addDanRule(danRule); }
// 可以通过接口来获取具体的玩家信息,玩家信息中有字段来标记是否为机器人 // host接口 XPopManager.instance.xHost.GetUserInfo(userid).isRobot // 前端接口 XPopManager.instance.xRemote.GetUserInfo(userid).isRobot
通过匹配规则匹配
- matchRuleName必须要先添加
- rankScore对应匹配规则中的分数,根据实际开发的业务数据来,分数会对应到详细的段位规则里
- ExtraData是透传参数,可以在匹配成功进入战斗服中获取到
private async onReceiveStartMatch(call: ApiCall<ReqStartMatch, ResStartMatch>): Promise<void> { console.log('>>>>>>onReceiveAddDbItem'); let match = new XMatchRole(call.req.actorID); match.ruleName = this.matchRuleName; match.rankScore = 0; //匹配透传数据 match.ExtraData = JSON.stringify({heroID:101}); let ret = await this.hall.UserBeginMatch(call.req.actorID, match, this); return call.succ({ ret: ret.ret }); }
取消匹配
private async onReceiveCancelMatch(call: ApiCall<ReqCancelMatch, ResCancelMatch>): Promise<void> { let ret = await this.hall.UserCancelMatch(call.req.actorID, this) return call.succ({ ret: ret.ret }); }
匹配状态变化
开始匹配和取消匹配都会通过回调来通知给hall,
可以根据开始时间,来处理倒计时等显示的逻辑
// 绑定 this.hall.onUserMatchChange = this.onUserMatchChange.bind(this);
private onUserMatchChange(iUserID: number, ruleName: string, matchTime: number): void { let userdata = this._usersMap.get(iUserID); if (!userdata) { return; } userdata.matchTime.value = matchTime; console.log('onUserMatchChange', iUserID, ruleName, matchTime); }
匹配成功
匹配成功后会进入战斗服务器,host,上面的完整流程已经提过
并且会收到匹配时传入的透传参数ExtraData
this.host.onUserMatchExtraDataReceived = this.onUserMatchExtraDataReceived.bind(this);
开房间
开房间功能建议在试玩链接里体验,目前房间列表只在试玩里开放
接入开房间组件
参考demo中HallUI的代码,一行即可,在点击创建房间按钮后触发
XPopManager.instance.advancedComponentMgr.addComponent("CreateRoomComponent");
房主在大厅内点击创建房间
创建房间可以选择地图,具体能选择的地图需要在审核后台配置
其他人加入房间
1.可以在房间界面内,接入邀请好友组件,拉取好友或者微信好友加入房间
/** * 组件--邀请 */ private Component_Invitation(): void { let invitation = XPopManager.instance.advancedComponentMgr.addComponent('InvitationComponent'); invitation.top = 60; invitation.right = 10; invitation.left = null; invitation.panel.top = 120; invitation.panel.bottom = null; invitation.panel.right = 0; invitation.panel.bangAdapter = true; invitation.panel.tweenType = 'Right'; }
2.其他人可以通过搜索房间列表加入房间
房间内显示逻辑
- 强调一个概念,开房间组件,相当于是在大厅里,忽略了匹配过程,直接把玩家拉到了host里面
- 被拉进该房间的玩家,会完整的处理进入hall以及host的各种流程,也就是说所有生命周期回调都会有反应,一定是先进hall再进host
- 在房主创建房间进入时,以及其他人在大厅找到房间进入时,都会触发host的onUserEnter
- 匹配时,我们一直在强调匹配规则的key,在进入host时,我们可以根据是否存在匹配规则的key,来判断是匹配进入,还是房间组件进入
let ruleName: string = this.host.GetMatchRuleName();
- 此时,界面内的显示需要根据host是否是房间状态来处理
-- 房间状态就显示各种座位的人员信息 -- 战斗状态就进入战斗逻辑(其实都是战斗服务器里的逻辑) -- 具体的状态管理可以参考demo代码,由开发者自己写状态机
启动本地大厅
本地调试时,登录界面,勾选本地大厅即可
只要勾选一个本地大厅就可以了,另一个账号登录时也会进入此大厅