本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
Flutter&Flame 游戏开发系列前言:
该系列是 [张风捷特烈] 的 Flame 游戏开发教程。Flutter 作为 全平台 的 原生级 渲染框架,兼具 全端
跨平台和高性能的特点。目前官方对休闲游戏的宣传越来越多,以 Flame 游戏引擎为基础,Flutter 有游戏方向发展的前景。本系列教程旨在让更多的开发者了解 Flutter 游戏开发。
第一季:30 篇短文章,快速了解 Flame 基础。
[已完结]
第二季:从休闲游戏实践,进阶 Flutter&Flame 游戏开发。
两季知识是独立存在的,第二季 不需要 第一季作为基础。本系列教程源码地址在 【toly1994328/toly_game】,系列文章列表可在《文章总集》 或 【github 项目首页】 查看。
一、 粒子系统
粒子系统 ParticleSystemComponent 是 Flame 中提供的一类具有 生命时长 的构件。具有明确生命时长的大量个体称之为 Particle。粒子系统依赖 Particle 对象进行渲染与更新:
在第一季中已经对粒子系统的 使用方式
进行过全面的介绍。本篇将基于打砖块的案例,具体介绍粒子系统的应用。
1.砖块的爆炸效果
游戏是一种与用户高频交互的应用产品。用户的参与感,首要在于 游戏玩法
,其次在于音效、视觉反馈交互体验。比如说小球的打击感:
[1]
靠撞击时的 反弹 这种现实物理经验,让用户在感知上体验打击感。[2]
通过需求撞击时发出的音效,如用户在听觉上体验打击感。[3]
通过添加砖块爆炸效果,在视觉上进一步加强打击感。
如下所示,当撞击或者射击等方式使砖块消失时,通过序列帧动画展示爆炸效果,爆炸完后就会消失。所以,这是一种大量、具有生命时长的构件。可以通过粒子系统来完成:
撞击爆炸 | 射击爆炸 |
---|---|
128.gif | 127.gif |
Particle 的派生体系中,有 SpriteAnimationParticle
粒子可用于序列帧动画的播放。
之前硬币的序列帧动画,是通过一整张序列帧图片加载的资源:
这里来看一下,如何使用一张张的序列帧图片进行动画,如下所示,爆炸的序列帧是 14 张图片:
序列帧动画,主要是构建 SpriteAnimation
对象。可以通过 SpriteAnimation.spriteList
构造基于 Sprite
列表完成任务。其中 Sprite 列表可以根据文件名遍历得到:
注: 游戏启动时需要将图片先加载进 loader
中,extraImages
来收集零散的图片资源。
1 | dart复制代码---->[lib/bricks/07/bricks_game.dart]---- |
在世界中定义一个 showBoomParticle
方法,在指定的位置添加爆炸粒子。通过 add
方法加入 ParticleSystemComponent
组件。粒子系统构件会在lifespan
秒后自动移除,想要播放一次恰好移除,可以根据序列帧数量控制生命时长。
1 | dart复制代码void showBoomParticle(Vector2 position) { |
注:默认情况下,序列帧的 stepTime*数量
会对和 lifespan
对齐,源码中可以看出,会通过生命时长修改动画的 stepTime。如果不希望对齐 ,可以将alignAnimationTime
置为 false:
最后一步是何处触发 showBoomParticle 方法。其实添加爆炸效果的时机很明确,我们也在之前封装过砖块销毁后统一操作的入口 PlayWorld#onBrickWillRemove
:
1 | dart复制代码void onBrickWillRemove(Brick brick) { |
到这里,我们就基于 ParticleSystemComponent 实现了爆炸粒子的处理。下面继续看一下其他粒子的使用,进一步优化打砖块的视觉表现:
2. 小球的路径展示
接下来基于粒子系统,实现如下所示的小球轨迹的展示。思路其实很简单,在小球运行时不断生成圆形的粒子,在一定时长之后消失即可:
展示小球路径 | 两个小球 |
---|---|
126.gif | 125.gif |
运动路径的粒子在小球中产生,使用在 Ball 中增加一个 showPathParticle
方法,在当前小球的位置增加一个维持 1 秒的圆形粒子 CircleParticle
,作为 ParticleSystemComponent
中的粒子,加入到世界中:
1 | dart复制代码---->[lib/bricks/07/heroes/ball.dart]---- |
然后,只要在小球更新的回调中不断添加粒子即可。由于 update
方法更新的频率很高,可以通过 _timeRecord
记录一下经过的时间,来限制 showPathParticle
触发的频率:
1 | dart复制代码double _timeRecord = 0; |
3. 小球死亡场景优化
如下所示,底部增加闪电网的序列帧动画表示小球死亡的底线(如下左图)。另外小球死亡时,展示死亡粒子动画(如下右图)。这样可以避免小球死亡时突然消失和出现。
底部闪电网 | 小球死亡粒子动画 |
---|---|
115.gif | 129.gif |
底部的闪电网通过 DiedLine
组件展示:
[1]
. 它继承自 SpriteAnimationComponent 构建,展示序列帧动画。[2]
. 它混入CollisionCallbacks
支持碰撞检测,当 onCollisionStart 监听到碰撞者是小球时,将小球移除。
1 | dart复制代码--->[lib/bricks/07/heroes/died_line.dart]--- |
最后小球在死亡时开启粒子动画,这和砖块被击碎时类似。在小球死亡后,通过 showDieParticle
方法添加:
1 | dart复制代码--->[lib/bricks/07/heroes/ball.dart]--- |
二、Loading 界面与加载资源
一般游戏会在开始时先加载图片、配置数据数据等资源。展示 Loading 界面让玩家看到加载资源的进度,加载完成后才进入游戏。
Loading 20% | Loading 80% |
---|---|
image.png | image.png |
1.资源加载器
目前打砖块的资源加载主要在 BricksGame#onLoad
中,包括本地配置的初始化、加载关卡数据、加载图片的异步任务。我们可以将这些任务得到的数据,统一通过资源管理器来封装处理。
资源管理器将作为可持久化的数据资源仓库,BricksGame 依赖资源管理器访问数据。资源管理器由于在应用过程中始终存在,而且只需要单一实例,可以通过单例模式进行维护。如下所示,定义 ResManager
持有 GameConfigManager
、GoodsManager
、List<Level>
、TextureLoader
等需要异步加载的资源:
1 | dart复制代码class ResManager { |
2.异步任务的加载进度
包括图片加载在内,目前有非常多的加载任务,如何在定义进度加载规则,以及通知外界加载的进度变化。是资源管理器的要点。我们可以使用 Stream 在每个异步任务完成后,通过 Stream 通知外界进度变化。当加载完毕,该流完成任务,进行关闭:
1 | dart复制代码final StreamController<double> _progressCtrl = StreamController(); |
其中加载图片是确定个数的异步任务,我们可以通过回调函数来通知外界图片记载的进度变化。如下所示,定义 LoadProgressCallBack
函数类型进行表示:
1 | java复制代码typedef LoadProgressCallBack = void Function(int total, int cur); |
3.Loading 界面中加载进度使用
此时,应用打开后可以先展示 AssetsLoadingPage
界面。
在 AssetsLoadingPage
状态类初始化中触发资源管理器加载数据,并监听 loadStream
触发更新通知:
1 | dart复制代码class AssetsLoadingPage extends StatefulWidget { |
当监听到进度变化时,如果进度小于 1 ,更新进度值,触发界面更新,来展示当前进度值。当进度为 1 时,触发跳转到游戏主界面。
1 | dart复制代码void _onLoading(double progress) { |
到这里,打砖块游戏的内容就基本结束。虽然是个小游戏,但麻雀虽小五脏俱全,其中整合了商店、背包、道具、金币、关卡、设置等游戏的常见的模块。大家也可以在此基础上进行进一步地拓展。
三、各平台应用打包
最后,我们将把打砖块的这个游戏在各个平台进行打包,这样就可以分享给其他人玩耍。Flutter应用可以产出原生级的Andriod、iOS、Windows、MacOS、Linux、web 六大主流平台应用。游戏自然也可以一套代码,完成六大平台的应用构建。
1. 构建 web 应用
web 平台应用,本身也是可以在各个平台通过浏览器访问的。其特点是无需安装包,可以直接通过浏览器访问。
flutter build web
该命令构建出的产物在 build/web
文件夹下,可以把它部署到服务器中,index.html 是它的访问入口:
没有服务器的朋友,可以将其作为网站部署到 gitee page 或者 github page 中。如下所示:
如下是部署到的访问链接, web 中游戏的性能和设备本身有关。这里桌面端也可以轻松地跑到 120 FPS:
2. 构建 windows 应用
Flutter 可以将应用打包为 windows 平台的可执行文件,也就是 .exe
。
flutter build windows
该命令构建出的产物在 build/windows/runner/Release
文件夹下。将其压缩分享给其他人,就可以在 windows 操作系统中进行游戏。你也可以通过其他工具打包成安装文件,这点在以后单独介绍。
目前在我的小破本上可以跑到 140 + 的 FPS :
3. 构建 Macos 应用
Flutter 可以将应用打包为 MacOS 平台的可执行文件:
flutter build macos
该命令构建出的产物在 build/macos/Build/Products/Release
文件夹下。将其压缩分享给其他人,就可以在 Android 操作系统中安装进行游戏:
10年前的老 mac 本表示,我还能再战几年:也能维持在 60 FPS:
4. 构建 Android 应用
Flutter 可以将应用打包为 Android 平台的可执行文件,也就是 .apk
。下面是打包 android-arm64 架构的 apk 包命令:
flutter build apk –target-platform android-arm64 –split-per-abi
该命令构建出的产物在 build/app/outputs/flutter-apk
文件夹下。将其压缩分享给其他人,就可以在 Android 操作系统中安装进行游戏:
安装后,四年前的 Android 旧设备,也能轻松保持 60 FPS。这表示 Flutter & Flame 的性能还有很大的压榨空间。
最后 iOS 和 Linux 平台类似,目前没有相关设备,暂时就不打包了。
iOS 打包应用: flutter build ios
Linux 打包应用: flutter build linux
到这里,打砖块游戏就告一段落,我们也得到了相关的成果。接下来,我们将继续前进,去往下一类别的游戏,进一步探讨 Flutter 在游戏方面的潜能。敬请期待 ~
本文转载自: 掘金