简单分享下在前司做的一个有意思的项目
如果是喜欢 DNF 且喜欢混迹游戏社区(DNF助手) 薅羊毛的同学,可能玩过这个项目。印象中应该是叫 DNF Lite,在助手的侧边栏。
简单来说这个游戏主要内容如下:
- 大富翁式探索(摇骰子探索地图,类似于蚂蚁森林巡护保护区)
- 抽卡(卡牌游戏的必备项目,重复角色升星、不同卡池)
- 战斗(回合制,有暴击之类的特殊效果)
- 养成(获得装备与角色提升数值、能降低探索难度)
- 随机事件(除了Boss战之外,有各种增益状态)
当然这个游戏已经下线了,并且我也离职了(没有竞业),咱也不想招惹南山必胜客
背景
当时 DNF 手游准备上线,于是决定搞一波预热,所以打算做个小游戏提升用户活跃。(结果由于版号的原因没能上)
由于部门内在探索 node ,拓展前端边界,加上 Server 人力不足,所以这个项目的:前端、后端、运维都有参与(拿着不如宇宙条实习生的工资干三个正职的活)
运维部分主要是:
- 申请机器资源
- 资源接入CI/CD
可以忽略,就不讲了
这个项目主要有意思的地方在于 server 部分,前端部分就是做了一些动画(外包出去)、调试角色在地图上的移动等等体力活。
架构
技术选型为:
-
FE
- react
- umi(react 框架)
-
Sever
- node
- egg(node框架)
- redis
- mongo
- mongoose(ORM)
- 消息队列(内部自研)
-
运维
- K8S
- Dockers
问题
由于并不是专业server大家看看乐子就行~
用户状态
一般来说,用户状态都是存在数据库的,但是游戏场景不同,需要频繁读写。如果将数据落库,那么会对数据库造成较大的压力,一个服务实例挂了还好,也就影响这个实例上的用户,如果数据库挂了直接凉凉。所以直接落库不太可行,得想办法。
可以在 redis 进行缓存,等用户交互完再落库。
那么这就有一个问题,怎么知道什么时候用户操作完了呢?
一般来说上长连接能解决这个问题,但是上长连接对服务器的开销太大,并且本质上来说这并不是一个真正的游戏,数据交互没有那么频繁(角色移动、战斗实时操作等)所以采用的还是 Http 请求。
这里用了一个折中的办法,设置一个活动时间,超出这个时间没有这个用户的请求进来,就认为该用户已经“断开链接”,将数据落库。(类似于防抖)
奖池抽奖
众所周知,卡牌游戏的核心就是抽奖。
理所当然,奖池里有各种等级的奖励,每种等级的概率不同。每个等级的奖励里面有多种物品,每个物品的概率应该相等。
这里有两种情况:
- 不用限制总数,保持整体概率就行
- 限制产出,概率低的同时还有数量上限
第一种情况问题不大,直接随机生成一个 0 ~ 10000 的整数,将这个数除以100,获得的结果用于判断抽中了什么等级的物品。
比如生成的数字是 1111, 计算后为 11.11,最低一档的奖品概率为 50%, 11.11小于50所以是最低的一档,以此类推。如果概率最低的是三位小数,那就生成一个 100000 以内的数。
获得抽中奖品的档次后,再生成一个这个档次物品总数以内的随机数,这样就选中了最终结果。如果是有什么物品概率 up ,那就把这些物品按比例求最小公倍数,然后在公倍数的范围内随机。
麻烦的在于限制产出的情况,比如有一个隐藏角色一周内只能产出200个,如果按前面的做法计算,有可能在一个小时内这些角色就没了(欧皇多的情况),也可能一周过去了 200 个一个都没抽走(全是非酋)
这里想了一个相对公平一点的方法,即过固定时间就往奖池里塞一个。 比如一周产出7个那就一天塞一个,也就是一周的数量最多7个,可以少不能多(总不能到最后看着池子里还有直接塞给最后抽的人吧)
战斗计算
由于有暴击之类的设定,最开始进行战斗的时候都是每回合进行一次计算。测试的时候发现如果请求量上来了,很有可能这回合的动画放完了,下回合的结果还没返回,流程就卡住了。
后来想到这个项目战斗时不能操作,也就是进入游戏后,结果就已经注定了,那干脆在加载时就把每回合的数据生成,返回一个数组,前端直接按这个数组播放动画就行。还节省了服务开销,美滋滋~
结语
本文是大概介绍,具体技术细节太多就不展开了(感兴趣的同学可以留言),虽然本职是前端,但偶尔搞搞其它东西还是挺有意思的~
原文链接:https://juejin.cn/post/7216895561608216633 作者:tomhyluo