【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
简介 最近APP游戏化成为了一个新的风口把在游戏中一些好玩的、能吸引用户的娱乐方式或场景应用在应用当中以达到增加用户粘性提升DAU的效果成本较低。同时在一些需要对用户有引导性的场景游戏化还可以使用户更易于接受并完成引导性任务并通过激励的形式鼓励用户持续沉浸在任务当中形成良性循环。基于这个思路闲鱼开发了互动引擎Candy。
什么是Candy引擎
Candy 是闲鱼技术团队设计开发的一款引擎
APP嵌入式的、轻量级的、易于开发、性能稳定的互动引擎
绘制系统高度融合Flutter体系游戏场景和Flutter UI支持无缝混排
动画系统对主流格式的支持友好且易扩展。
本文讲解我们为什么要做这款引擎以及我们是如何设计这款引擎的。
缘起
目前APP内嵌小游戏一般采用H5小游戏的方式而这个方式存在一些隐患并不被很多应用商店推荐。因此我们需要寻找一种新的安全的方式来实现APP内嵌小游戏并且我们希望这个方式开发友好、性能稳定、功能齐全所以我们遵循这三点去寻找一种新的方式。
思考
我们主要通过下面三种思路来探讨APP内嵌小游戏
采用Native的游戏能力
目前Native开发游戏生态并不是特别成熟而且采用Native开发就必须面临双端两套代码的问题开发成本和后续维护成本都会比较高。
采用游戏引擎比如Cocos-2dx、Unity等
虽然游戏引擎目前非常成熟但是游戏引擎一般用于开发重度游戏所以引擎大小一般比较大引入游戏引擎会导致包大小增幅不小。而且游戏引擎比较复杂所以引擎启动耗时较多比较难做到游戏页面秒开游戏引擎加载进来后内存消耗都会比较大。游戏引擎和APP间的通信互动相对较为麻烦目前没有比较好的混合栈支持。游戏引擎的UI能力较弱无法胜任复杂的APP UI逻辑若采用游戏引擎开发内嵌小游戏无法融合小游戏页面内游戏场景和Feeds等UI。
采用Flutter的轻量级互动引擎
Flutter本身是基于Skia这个2D绘制引擎实现的跨端APP解决方案所以它天然具备2D绘制能力所以采用Flutter来实现App内嵌小游戏存在可能。目前Flutter存在一些轻量级游戏引擎比如Flame这款引擎支持简单游戏逻辑和动画能力同时整个游戏是以一个Widget的形式最终插入到APP中可以让小游戏页面中游戏部分和UI部分完美融合。
综上考虑我们决定采用Flutter的轻量级互动引擎。
Flame还是自主设计
Flame引擎目前是Flutter生态中比较不错的一款小游戏引擎但是依然存在很多问题
游戏系统不完善引擎只有Game和Componet没有Scene和GameObject概念这样会导致游戏对象嵌套复杂对多场景不友好。
引擎完全采用Canvas来实现游戏场景中无法实现局部刷新存在性能隐患。
缺少GUI系统场景内嵌套UI比较难。
缺少手势事件系统。
动画支持格式不主流骨骼动画是通过Flare支持的不支持DragonBones。粒子动画最近才上对主流格式支持也不太友好。
资源管理存在内存问题资源加载后一直不会释放。
缺少机型适配能力。
基于这些考虑我们决定重新设计一款Flutter互动引擎
对标集团的EVA引擎和业界的Unity引擎完善游戏系统。
复用Flutter局部刷新。
复用Flutter UI作为GUI。
复用Flutter手势管理。
实现支持主流格式的骨骼动画和粒子动画。
复用APP资源库(图片库)。
实现全局750适配。
其中2-4点本质上是将互动引擎的绘制系统融合入Flutter的绘制体系中本文下面按解决上面问题的思路依次介绍我们的引擎设计。
Candy引擎设计
框架设计
首先分析游戏化业务需要哪些能力分析我们的业务场景得出游戏化业务需要图4-1所示的能力
图4-1 游戏化业务能力需求
拆解后互动引擎需要有游戏系统、绘制系统、生命周期系统、GUI系统、物理系统、动画系统、资源系统、事件系统(手势管理)。
根据我们之前的定位互动游戏绘制融合到Flutter绘制体系中来基于这个思路我们可以复用Flutter的UI系统同时需要融合Flutter和游戏的手势管理。最终我们得出如图4-2所示的框架图
图4-2 互动引擎架构
整个互动引擎架构共分为四部分
接口层
对外暴露的游戏接口主要包含创建游戏、创建游戏对象、添加游戏组件等接口同时还封装了一些常用游戏对象、常用游戏组件的工厂接口。
游戏系统
游戏世界的管理系统主要管理Game、Scene、GameObject和Compoent间的组织关系还控制游戏子系统和绘制系统的启动与关闭。
游戏子系统
游戏化能力补充主要包含生命周期系统、物理系统、动画系统和资源系统被游戏系统调用。
绘制系统
负责游戏的绘制本引擎的绘制系统会高度和Flutter绘制逻辑融合所以兼容了GUI系统和事件系统(手势管理)。
游戏系统
对标Unity设计游戏系统有下列四大元素
Game游戏类负责整个游戏的管理Scene的加载管理以及各子系统管理与调度。
Scene游戏场景类负责游戏场景中各游戏对象的管理。
GameObject游戏对象类游戏世界中游戏对象的最小单位游戏世界中的任何物体都是GameObject。
Component游戏组件类表示游戏对象的能力属性比如SpriteComponent表示精灵组件表示绘制精灵的能力。
GameObject通过组合Component的形式来让自己拥有各种能力不同的组合让GameObject相互之间不一样。整个游戏系统的组织关系如图4-3所示
图4-3 游戏组织形式
生命周期
对标Unity和Flutter特性我们设计了如表4-1所示的生命周期共有八个回调基本可以满足互动游戏业务开发。
表4-1 生命周期
渲染系统
基于融合Flutter绘制体系思考我们就不能全盘用Canvas来做整个游戏的绘制管理我们需要将游戏对象和Flutter的绘制对象RenderObject结合起来如图4-4所示
图4-4 渲染映射
首先是Game的对象数和Flutter的三颗树有效融合所以每一个GameObject必须对应一个Widget、Element和RenderObject。
融合过程主要需要解决以下问题
游戏的坐标系与Flutter的布局转换融合。
动态添加和删除游戏对象的处理。
动态修改游戏绘制深度的处理。
Flutter Inspector对游戏对象的支持。
整个绘制融合相对复杂需要解决很多BadCase后续会另撰文详述互动引擎绘制融合Flutter绘制体系的过程本文不再赘述。
GUI系统
由于绘制已经融合到Flutter体系GameObject都会对应Widget所以我们可以设计一个特殊的GameObject支持插入一段Flutter Widget树这样我们就不需要另外实现GUI了复用Flutter UI作为GUI即可。这个逻辑和绘制融合思路比较一致将插入的Widget树作为GUIWidget的孩子即可在GUIRenderObject中打通layout、paint和hitTest逻辑即可。
这里给一段我们GUI的示例实例代码开发过程相对简单(阅读原文获取代码)