游戏开发:卡牌 GVG对抗玩法设计
赛季制团队对抗赛,赛季内进行若干轮次对战累计段位积分,赛季根据段位积分排行结算
单轮对战划分为若干阶段:预览期,报名期,匹配期,备战期,调整期,对战期,结算期
对战形式是 若干队 VS 若干队,卡牌单位对战
功能划分:
新增skynet单点节点负责玩法的公共逻辑:
- 排期管理模块 schedule
存在多个赛季同时进行的场景,抽象一个赛季阶段管理模块actManager,模块object管理指定赛季各阶段的相关逻辑,schedule负责管理actManager的object的生命周期并通过skynet.timeout定时驱动object的心跳检查;
- 赛季阶段管理模块 actManager 管理阶段切换以及各阶段业务逻辑
阶段切换:根据当前所在阶段和当前排期,判断是否需要切换阶段以及切换到哪个阶段,逻辑保证切换阶段总是有序地向下一阶段切换,直到到达期望所在的阶段。这里存在三种切换类型:轮次内阶段切换、跨轮次切换、赛季内阶段切换;
[预览期] 开放玩法入口,object提供赛季内相关数据的API;
[][][报名期] 提供报名状态查询API和团队报名逻辑处理;
[匹配期] 根据报名团队的属性进行分组,两两匹配,需要处理匹配不到对手时自动生成机器人团队,抽象一个对战管理模块pairManager,模块object管理一组对战(两个团队)的对抗逻辑;
- 对战管理模块 pairManager 管理团队对战业务逻辑
模块object负责单个对抗组的业务逻辑,公共进程同时进行中的对抗组数量则为object的数量,单个模块object占用的理论内存峰值为3.6MB,一个对抗组数据存放在单一document内,使用批量无状态的skynet service运行object逻辑;
单个object内驱动定时器心跳检查;object生命周期,由玩家的请求惰性load起,闲置超过指定时间后自动销毁,以平衡内存占用。
- 排行榜模块 rank
使用单skynet service运行,加载排行榜集合数据,内存内构建zset排序,提供对外查询API;
- 战报模块 report
使用单skynet service运行,加载对抗组document数据,构建战报缓存。
设计要点:
-
处理高并发;
登录、跨天、阶段切换,认为是高并发动作;设计原则是,并发热点处只做必要的事情,同时做好性能削峰。
登录需要下发玩法排期相关的信息(请求schedule),这里避免请求对战object内的数据。登录需要获取团队匹配到的分组ID(查询mongodb),这里处理并发热点;
对战object数据对应玩法界面内数据,由玩家通过请求回应触发(enter scene),可以认为非并发热点,enter scene会触发排行榜db的查询,报名表db的查询。
阶段切换需要对当前在线玩家进行刷新,这里避免做全服广播,实现为客户端在当前阶段结束时间(排期信息携带)到达后,定期请求新的排期信息直到请求到新的阶段信息。
- 关键的执行流程需要支持异常中断时的重入;
匹配:匹配流程对报名期所有团队进行两两匹配,并为每个匹配组(group)生成匹配doc进行写库,匹配完成后玩家可以查库获取groupID,load起pair object。这里对流程的重入设计:
1)增加匹配中标记,控制匹配未完成时玩家无法获取到groupID加载起pair object(这时候的object是无效的,数据可能不完整)、以及无法切换到下一阶段(存在进行中标记说明匹配未完成,无法切换阶段);
2)新增gm接口,接口执行【设置匹配中标记,drop掉原匹配数据,重入执行原匹配接口,强制销毁当前已存在的pair object,取消匹配中标记】;重入匹配逻辑时,原匹配可能是匹配异常中断,也可能是已经匹配完成,匹配完成的情况下,此时已经有活跃的pair object,drop掉匹配数据会导致pair object的逻辑无效(比如定期存盘),这里提供一个gm接口,强制销毁这些无效的object;
结算:
- 优化频繁重度的跨user访问;
业务需要支持查看所有队友对战队伍的阵容详情,对战界面需要展示对手的阵容详情,阵容数据量较大,频繁重度的跨进程调用,带宽、序列化、消息队列都可能是瓶颈问题,这里在公共进程中做cache,团队中玩家将阵容信息缓存在团队对应的pair object中,队友和对手直接通过访问object获取阵容数据,数据实现超时更新,超过时间load起玩家进行收集更新;
- 资源及性能评估;
1)单个pair object管理一组对战,对战数据使用单个document存储,GVG对抗,峰值数据量为:单个队友数据峰值 * 对抗赛出战最高人数 * 2(两个团队) + 杂项数据,单组理论峰值占用为3.6M,远小于mongodb单个document存储上限值16M,方案可行;
2)使用无状态的skynet service池,用于承载pair object的运行,这里评估预开启的service数量。玩法为内存占用型,CPU占用不高,这里主要评估内存指标。玩法上线报名团队数量700+,匹配组为700/2=350,理论峰值占用内存为350*3.6=1260,约为1.2G,单个service占用100M认为是安全合理的,这里将service定为12。
3)使用单独的skynet service用于公共进程内数据库读写访问操作—— db服务。服务内需要维护database connect池,为每个数据库请求分配一个connect进行处理(多连接并发处理,提高服务业务处理能力,提高吞吐量),多连接会提高数据库利用率,结合数据库机器评估初始化连接的数量为12。
本文来自博客园,作者:linxx-,转载请注明原文链接:https://www.cnblogs.com/linxx-/p/18892224
浙公网安备 33010602011771号