前端视角支持游戏开发
November 12, 2019
最近实现了一个天天领钱 H5 游戏,一期基础场景如下
在做果园之前,我们和其他部门专职做游戏的同学充分的进行了沟通,得到很多宝贵的经验: 框架层面:了解到他们使用的是 cocos creator 框架,但是提到 cocos 框架是 c++迁移到 js 的,所以本身就有诸多小问题,所以新的游戏他们都使用的是 laya 框架,也推荐我们来使用。 通讯层面:后端交互使用的是 websocket 实现的,通讯相关的复杂度很高,因为后端是有状态服务,前端要做 request event 和 response event 之间的关联。所以建议我们还是用短连接。
回来后深入学习了下 laya 框架,也玩了一些同类的游戏,发现其实这类游戏与其说是游戏还不如说是一个运营活动。其实技术上游戏元素很少,只是玩法上是类似游戏的交互。所以未必真的需要上 laya 框架另外:
- 团队技术储备都是偏向小程序/H5 游戏类的都没什么经验,产品侧给的时间比较短风险也大
- 游戏本身很简单(交互性很低),判断不需要太复杂的游戏框架
架构分析
那么基于这样的一个限制,思考了一个新的做法:
- 美术同学做好果园需要的骨骼动画,
- 前端通过某种方式当用户点击的时候播放对应动画即可
剩下所有功能都使用前端技术(React)去做。
关于骨骼动画目前其实三部分:
- 树的点击,成长,升级;
- 水壶的浇水;
- 奖励的弹窗
- 领水滴动画
所以其实就是四个动画文件,在合适的时机去播放合适的动画就行了。调研了一圈,最后选择使用 pixi.js V5 来做这游戏的画布,封装了 pixi-dragonbones 进行龙骨的播放。
所以我们的整个架构就变成了下面这样三层的结构,底层就是主场景的绘制,主要动画的执行,中间层就是各种业务弹层,上层是动画弹层
游戏引擎篇
最开始的时候,只是单纯的封装了三层架构到一个 Game 类里面,然后游戏精灵的创建还是使用的类似 JQuery 的方式进行的。所以一旦有数据层面的变动,必须直接找到对应的精灵实例进行操作,比如坐标变化。这样其实有一些倒退。写的过程中也很不爽,后面就思考了下响应式的做法,有两个办法
- 基于 RXJS+对象
- 类似 react 的方式声明对象,数据变化导致精灵属性的变化由框架维护
因为之前写过一些 RXJS 的项目,了解里面的复杂度,再团队内推很可能导致较大的延期风险,毕竟很多 RXJS 配套的运行时都没有研发。所以潜意识里就第一时间放弃这个做法(也是目前最后悔的地方,应该用的,后面再聊),而为了方便现有开发,将已有的 react 资产集成进来开始考虑如何用 react 的方式进行游戏开发,第一反应就是实现一个 ReactPiXi (对标 ReactDom),所以快速写了一个 ReactPiXi 验证了一下发现果然可行。 继续完善的过程中,查资料偶然发现一个开源的方案 @inlet/react-pixi ,大部分都实现了,但是遇到点小问题,提了 pr 也很快合入了,最后就选定了这个库,至此游戏精灵对象和 dom 对象两层就在逻辑上合并为一层了。 游戏精灵的 react 写法 这样游戏对象和数据流就可以通过声明的方式进行关联了。至此整体开发就完全变成前端最熟悉的开发模式,和游戏就没有太多关系了。后续这方面的工作就和 RN 一样,要使用 react 组件的方式封装一些原生的精灵对象即可。
数据流篇
数据流选用了 mobx,这是目前复盘看比较失败的地方。mobx 的优势最大的就是响应式编程,当时使用 mobx 是想的当数据变化的时候,直接响应的回调操作游戏精灵,类似下面的代码
autorun(()=>{
const sprite = new Sprite();
sprite.y = store.tree.x;
sprite.x = store.tree.y;
})
这样只有在tree的x或者y属性变化的时候才会执行这个回调,能有效的进行数据和对象的绑定,但是后面换成react架构之后,绑定关系在render函数中就实现了,所以根本不需要这么写。当时考虑到mobx和react也能很好的集成,所以我们就没有进行数据源的更换,还是沿用了mobx。
在正常业务开发的时候mobx没有太多的问题,但是当进行多个动画对象联动的时候mobx就出现了比较大的麻烦。比如浇水动画播放到2s的时候播放进度条动画,等服务端返回的时候播放数升级动画同时更新主场景,然后升级2s的时候出弹层动画。整个流程使用mobx就比较难以描述,还是要在业务层代码写很多离散的逻辑。而这些正好是rxjs比较擅长解决的问题,会把同步的异步的推拉两种架构都汇总到同一个流的模式上完成,其实是最契合目前的场景的。
另外发现一个问题,mobx 的开发者工具没有 redux 的好用,仅仅支持简单的数据流变化,这种变化监听是牺牲了易用性完成的,及必须将每个 state 的操作都通过 action 进行才可以。而这么写在开发角度看就回退到了 redux 的模式。另外 mobx 对数据没有一个很好的管理方案,store 是离散的,所以没办法对 store 做很好的镜像上报,不容易排查问题。
目前实践下来 Mobx 目前比较好的点就是不需要关注更新位置,只有变更的组件才会更新,不需要写 memo 之类的函数进行处理。
资源管理篇
资源管理的诉求
- 支持换肤,动态换肤/静态换肤
- 支持自动图集(雪碧图)
- 支持自动有损压缩
- 支持webp
- 最好能做到设计自行传图片,应用后线上自动生效,不需要研发介入
针对上面的诉求资源管理最开始希望做一个托管的网站进行管理,解耦设计和研发之间的依赖。但是发现流程和版本控制上比较复杂,几经讨论就暂时搁置了这个方案,需要进一步探索
新的方案暂时不满足第五点,满足前四点就只需要提供一个本地的构建工具即可,我们按照目录进行了约定,将游戏内使用的资源分为三类:
- 文案资源
- 颜色资源
- 静态文件资源(json动画文件,图片文件等)
目录结构:
所有主题默认继承base,如果存在同名的就覆盖base里面的配置,其中比较特殊的是files下有sprites目录,这个目录下面每个文件夹都会被自动打包成一张图片,最后处理完所有资源后会生成d.ts和json两个文件。项目中实现了一个资源替换的模块统一处理了游戏内皮肤替换和H5皮肤替换
至此,一个使用 react 开发前端营销游戏的架子就完整的搭建起来了。基本满足我们的诉求
- 团队成员没有游戏开发经验如何快速上手开发游戏
- 已有前端资产如何和游戏打通
- 能支撑业务长期迭代
文档
https://juejin.im/post/5c563a4ef265da2ddb293ba3#heading-2 https://github.com/Zainking/LearningPixi#takingitfurther https://reactpixi.org/components/container#props
Written by xi ming You should follow him on Github