游戏互动是淘宝内容化建设的重要一环,其实自研的淘宝斗地主满足了部分人群的简单娱乐需求。本文主要介绍了淘宝斗地主新推出的残局玩法从0到1是如何实现的,笔者针对游戏链路到设计方案和可能出现的问题做了比较细致的介绍,供大家参考交流。
项目介绍
当前互联网应用很重要的一点就是内容建设,通过内容吸引用户。对我们来说就是成为吸引用户每天点开淘宝的动力。期望用户能够每天点开淘宝看看——我现在没事,那打开淘宝领取一下淘金币,去淘宝人生看看,打个斗地主,玩个麻将,看看淘宝乐园的小游戏等等。
笔者本次拿斗地主举例,其作为棋牌游戏面向人群广泛,即时满足性强,两分钟一局,通勤、食堂、洗手间等碎片时间来一局,此类互动类内容建设为淘宝在用户增长和用户使用时长方面带来了一定的收益。
相信每个人都知道斗地主的玩法和规则,这里就不花笔墨叙述了,淘宝斗地主目前有经典玩法、炸弹房、实物大奖赛、好友对战等游戏模式,也形成了任务中心、钻石一分兑、道具商城的运营体系。但是游戏要想持续吸引住玩家,必须要不断推陈出新。
因此在经典玩法基础上我们需要探索出的新的玩法,就像9月份爆火的《羊了个羊》游戏一样,诸如此类的解密闯关类,我们做了斗地主的残局玩法,你可以想象和象棋的残局一样,双方能够看到对方的手牌,并且其中玩家方的胜利路线是唯一的。玩家从复杂的敌我手牌中,面对永不出错的AI,在重重险阻中找到获胜的途径,获得战胜AI的成就感。残局作为承接斗地主部分玩家的双十一活动,为玩家尤其是高玩提供了新颖的游戏体验,后期作为外投的“钩子”,期望吸引到更多感兴趣的玩家,拉新并转化。
残局目前作为活动投放,每天的关卡都是不同的,欢迎大家每天都来挑战~
项目分析
经典模式的斗地主分了以下几个阶段:
匹配->发牌->叫抢地主->加倍阶段->打牌阶段->结算
功能上分为几大模块:实时在线匹配,牌局推进与更新、托管与守护、消息的推拉结合。由于本文主要讲述的是残局,对于经典玩法是如何实现的就不展开了,主要想对比一下残局玩法和经典玩法的区别:
业务思考
首先是定义我们的斗地主残局是什么,以及如何保证对局的挑战性和趣味性。
根据运营策略,AB、人群、来源等判断是否触发活动,再请求当日牌局信息。
牌局要求:玩家必有获胜机会,但是仅有一种出牌方式能获胜;要求生产的牌局一定要保证某一步是唯一解,既不能出现用户随便出都能赢AI,也不能出现无论怎么出都无法赢AI的牌局。
进入对局后,只有玩家与AI对手两个角色,并且双方手牌都直接展示。
开局后直接进入出牌环节,玩家为先出的一方,对局过程中,玩家侧不设定倒计时,每一步没有超时时间,可无限等待下去。
每当玩家出牌,AI方将有5S的倒计时出牌时间,AI的每次出牌会随机在1~5S间隔
当玩家出牌并在“获胜”的路径上时,AI需要尽量确保后续的出牌也只有1种策略【AI不能认为要输了就摆烂】
当玩家出牌并非“获胜”路径时,AI需要使用合理的牌序策略将玩家击败【只要玩家出错就必败】
直到双方有一方将手牌打光,即为牌局结束,AI出完用户失败,反之则胜利。
当用户击败AI后,可以获得相应关卡的奖励(一般是斗地主的道具或豆子钻石),吸引用户在其他对局中使用,进而拉长用户的游戏时长
玩家的牌局缓存会保存一定时长,中途退出后,牌局不会被自动托管,现场被保存下来,用户当天再次挑战会从上次结束地方继续,除非用户手动点击重开或本局进入到结算。
要求用户短时间(30天)内不能遇到重复的牌局;
半夜十二点玩游戏用户很多,因此将每日关卡改到凌晨5点刷新
技术方案及思考
1、用户触发活动 2、获得今日关卡 3、用户和AI对局 4、结算和发奖
一般的存储方式:
由于牌局更新频繁,而且在线玩家越多,并发越大,对RT和性能就越敏感,而牌局的具体过程系统不需要详细记录下来,也不需要使用永久性的存储方式。综合考虑之后基于Redis的缓存是当前比较合适的方式。
残局场景涉及到两个缓存信息:
一、十局牌局信息同时也作为触发标志
存储包括挑战进度,十局残局对应的信息(gameId;用户手牌;AI手牌)
二、用户当日正在挑战局的牌局信息
用户在进入斗地主主页的时候,会去校验该用户是否能够触发活动,如果在触发活动范围内,会判断疲劳度决定是否出现活动弹窗,引导用户进入残局玩法。下面展示的是当用户进入首页时,校验触发逻辑:
这里在设计的时候用了两个开关,一是总的活动开关,二是新用户触发开关;考虑当出问题的时候能够提供一键降级的能力,另外给运营提供了关闭新用户触发的入口。
每一个用户每日十局挑战的关卡并不相同,用户点击开始挑战会进入当天的挑战进度中,此时会判断当前是否有未完成且是当日的牌局,如果有的话,直接恢复至玩家上次离开时的状态。如果发现没有一局缓存或此关卡已结束,那么利用十局缓存中的数据和进度信息初始化牌局,并写入到一局缓存中,用户开始本关卡挑战。
值得注意的是请求用户今日的十关挑战是放在每天第一次进入第一关挑战时,避免在前一步判断触发时调用算法而造成大量无用请求;为什么在这里统一请求,而不是每一关都请求算法:是为了能够分发不同的牌局策略,算法侧的同学会根据不同的策略筛选和分发牌局,例如A桶投放前5关简单,B桶投放奇数关简单等;并且会尽量将牌局打散以获得更多真实用户挑战记录,以供后期数据分析。
前文提到的如何让用户一个月内不会请求到同样的牌局,一开始想的解决方案是通过布隆过滤器实现,后来简化了一个方案,将所有牌局分成31个区,每个自然天请求不同分区内的牌局即可。
下方的框图展示了玩家的出牌逻辑,在调用算法接口获得AI出牌信息之前,会对用户出牌进行前置判断。由于斗地主涉及到多种异常信息,因此需要做很多对异常信息的判断和处理,哪一些异常需要透给用户,例如:牌型不符合要求(不是单张、对子、三带、顺子、炸弹等),是否能够压过上家牌,是否能跳过(对面不要时玩家不可跳过),出的牌是否是玩家手牌(防止直接刷接口) 等等。
在检验没有问题之后,会将玩家本轮出的牌、玩家剩余手牌、AI剩的牌组装,并封装请求,RPC请求算法获得AI此轮出牌,拿到AI出牌后更新牌局信息,再判断是否走到结算,如果此时有一方手牌已为空,则本关结算;否则更新牌局信息缓存,玩家继续下一轮次的出牌动作。
结算逻辑:
由于残局对算法侧依赖很大,如果请求算法出现问题,拿不到今日牌局,或者玩家出牌后拿不到AI出牌信息等,会导致牌局无法正常进行,阻塞玩家流程。实际联调时发现调用时候会出现算法侧返回报错或者RPC超时等问题的,另外也本着不信任依赖的原则,需要有兜底。面对这些问题,设计了以下解决方案:
一、配置监控报警,监控调用算法时长和成功率的指标,当出现抖动时及时报警
二、设计兜底方案:
斗地主此类游戏场景和一般的请求有不同,要求端上渲染信息和服务端存储的信息必须一致,但是在交互过程中有可能出现的异常有:
端上网络问题:
服务端依赖的下游出现问题
上面说的问题会有一个表现:用户出了一手牌之后,前端没有拿到这次请求的结果,或者拿到了包装的异常,此时本轮出牌渲染出现问题。
如果说此次请求服务端真的失败,其实倒也没什么问题,用户重新出牌就好了;但是麻烦的是服务端走了业务逻辑,更新了缓存,但是端上因为各种各样的原因没能正常渲染,此时玩家再出牌时候就会抛本张手牌已出的异常了,此时是会阻塞用户的。因此设计了以下解决方案:
这里涉及了两个缓存,理论上这两个缓存要求数据一致性,但是Redis并没有传统说的事务特性,想要做到两者状态强一致性几乎是不可能的,因此笔者在设计上考虑以下方案保证玩家不会因为数据不一致而阻塞或损失权益:
当一局牌局结束的时候(结算或用户选择重开),会将本局玩家和AI出牌的记录、玩家挑战次数、本关挑战时长、进度等等信息打印到日志中,并通过日志同步到数据平台中,联合算法侧对不同玩家的发牌策略表join,来判断什么样的分发策略能够提升用户时长和留存,也用来分析不同的残局难度应该如何衡量,为之后固定关卡的牌局选择沉淀信息。
总结
残局玩法是淘宝斗地主上线的全新玩法,用户的状态流转和设计思路上倒并不多难,主要集中在业务逻辑上判断比较多,针对各种异常链路要有完整的思考理解。残局玩法上线后获得了不少用户的积极反馈,同时作为双十一活动承接了部分用户,对斗地主用户游戏时长有一定提升。我们会设计一些简单而巧妙的牌局,看起来很容易赢,但是怎么出都会被AI击败,往往需要某一妙手比如拆一个对子才能获胜。除此以外我们已经在迭代通过做任务获得胜利路径提示等功能,进一步提升玩法的完整性,希望能尽快够给大家呈上一个更完美的残局,更丝滑的斗地主。
作者:刘家成(悟学)
来源:微信公众号:大淘宝技术
出处:https://mp.weixin.qq.com/s/JRgXV-yakS5c71Dxoluaeg