找回密码
 立即注册
查看: 724|回复: 1

苏打世界的流体灌装是如何实现的 – Liquidfun在Cocos2d-x ...

[复制链接]
发表于 2021-12-10 21:41 | 显示全部楼层 |阅读模式
题外话

新作「苏打世界」已经上架AppStore,并在首页被大屏推荐。上架伊始便颇受玩家喜爱,目前已经收获大量玩家的五星好评,欢迎大家前去下载试玩。
本文将介绍游戏内的灌装系统是如何实现,最后将附上参考资料以供读者们阅读和研究。以下将不会有具体代码,只讲思路和方法。
缘起

在「苏打世界」里,一个很重要的日常任务便是生产苏打。由于产品汪提姆绿需要尽可能的去模拟真实的苏打灌装,比如苏打灌满后溢出和未灌满时水面的波澜起伏等,这也导致用动画来模拟实现是不可能的。
所以便只能去寻找一个支持流体功能的2D物理引擎,并将其移植到我们开发采用的Cocos2d-x + Lua的游戏框架中。
LiquidFun

当接到这个需求后,我便联想到了Google的LiquidFun。
由于LiquidFun支持JavaScript,这也非常方便我们快速验证原型,即LiquidFun到底是否合适我们的游戏。
对LiquidFun的testbed修修改改后,我快速的建立一个灌汽水的网页版原型。同事们看完觉得还可以,便开始了将LiquidFun移植到游戏的工作。
怎么接入?

LiquidFun依赖于2D物理引擎Box2d,可以认为其是Box2d的加强版,比原先的Box2d增加了流体粒子功能。
我们游戏采用的是Cocos2d-x+Lua的框架,所以问题变成了:如何整合LiquidFun到Cocos2d-x中,并绑定其常用API到Lua中,使游戏逻辑可以操控汽水的灌装,隐藏,销毁和回收。
将这个复杂的任务分解后,大致如下:

  • 移植LiquidFun库到Cocos2d-x中,覆盖其原先的Box2d库
  • 在C++层跑通,使LiquidFun的流体粒子能在Cocos2d-x正常工作
  • 对LiquidFun做tolua绑定,使Lua中使用LiquidFun成为可能
  • 在Lua书写灌装的逻辑,实现一个灌装的DEMO
如何移植到Cocos2d-x

关于LiquidFun的移植工作,已经有先驱帮我们趟坑了。Cocos2d的作者Retro在其博客中详细阐述了:如何将LiquidFun移植到Cocos2d-x,以及如何利用metaballs技术来渲染粒子使其看起来更像流体。
读者不妨先去阅读以上的两篇文章,花点时间,搞懂每一步的目的和原因。
简而言之,Retro在Part1所做的工作是将LiquidFun的每个流体粒子在物理世界的坐标转换到Cocos2d-x的绘制坐标中,然后用GL_POINTS命令将粒子绘制成一个个的小点显示到屏幕上。
在Part1内,我们已经完成了LiquidFun对Cocos2d-x的C++层的移植工作。但是仅仅显示一个个白色的小点是不够的,因为这样看起来不像流体而比较像沙子。
接下来在Part2中,Retro引入了一张中间圆形实心,四周趋于透明的纹理代表一个粒子,利用一个透明度阀,将此透明度(例如0.01)以下的全部显示为全透明,而之上都显示为一个纯色。然后用一个RenderTexture去实现整个Shader的绘制,最后将其显示在屏幕上。当两个粒子很临近时,可以看出一个不规则的融合形状,这个技术就是最基础的metaballs。
C++绑定到Lua

由于Cocos2d-x没有对Box2d进行tolua绑定,所有绑定的工作需要从零开始一遍。
原先本想采用Cocos 3.x引入的ini格式的配置进行绑定,后来发现不太现实,因为有太多的结构体需要进行绑定到Lua。
所以只好回归Cocos 2.x时代的pkg绑定。关于如何进行pkg绑定的方法,不是本文关心的内容。因为基本都是把C++头文件按照指定的规则转译为pkg文件的体力活。
我曾经在2.x时代因为极度痛恨这种手工方式而写了一个Lua脚本来进行自动转译,这个脚本现放于Github中,年久失修,可能有坑需要手填,慎用!
这基本是个体力活,为了大家移植方便,不再趟坑,我已经将转译好的pkg文件和tolua后的C++文件上传到Github的仓库中,大家可按照MIT协议进行下载使用。
Lua逻辑实现


  • 构建好仓库和瓶子的物理形状
  • 填充好粒子系统到仓库中
  • 用按钮来控制仓库出口开关的位移
  • 生产按钮按下时,仓库出口开关移走,粒子以重力掉落到瓶子中
  • 生产按钮恢复时,仓库出口开关回原位,粒子将被其阻隔而不能下落
  • 当粒子掉到屏幕外时,销毁该粒子,并在仓库内重新创建一个新粒子
一张图让你明白,其实我们后面是真的在灌汽水!



性能优化

GPU


  • 尽可能只使用一个RenderTexture来渲染所有粒子,以避免重复绘制的浪费
  • 如果可能,限制用于渲染流体粒子RenderTexture的大小,避免全屏绘制,以降低绘制面积
  • 精简shader,移除没必要的变量和多余的if...else...分支判断
  • shader使用低精度浮点数即可:precision lowp float;
CPU


  • 将耗时操作放在C++层执行,以避免每次循环内调用tolua的开销。比如从C++层直接获取一个在屏幕外的粒子列表,而不是在Lua层对所有粒子循环判断其位置。因为每次粒子位置的获取都需要消耗tolua时间,粒子数一多,就容易积少成多拉低性能了。
  • 粒子对玩家不可见时,将粒子系统的更新暂停,直到下次被使用时再恢复,可以极大缓解设备发热和耗电量
  • 降低Box2d世界更新的步进值,以达到性能和效果的平衡
  • 在保证效果的情况下尽可能减少同屏共存的粒子数
  • 自己管理粒子的生命周期,以避免在每次粒子的步进更新中检测是否销毁
  • 使用release版,掩面逃)
参考资料


  • LiquidFun Programmer’s Guide – 官方文档
  • Integrating LiquidFun with Cocos2d-x: Part I – 在Cocos2d-x中显示流体粒子
  • Integrating LiquidFun with Cocos2d-x: Part II – 利用metaballs技术使粒子更像流体
  • Inside LiquidFun – LiquidFun技术原理
  • Make a Splash With Dynamic 2D Water Effects – 2D流体效果的实现原理
原文地址:苏打世界的流体灌装是如何实现的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-12-10 21:49 | 显示全部楼层
所以为什么这个游戏被鸽了(?)商城里已经找不到了呀
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-6-9 13:29 , Processed in 0.729829 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表