持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 22 天,点击查看活动详情
前言
这是一套 张风捷特烈 出品的 Flutter&Flame
系列教程,发布于掘金社区。如果你在其他平台看到本文,可以根据对于链接移步到掘金中查看。因为文章可能会更新、修正,一切以掘金文章版本为准。本系列源码于 【toly_game】 ,如果本系列对你有所帮助,希望点赞支持,本系列文章一览:
- 【Flutter&Flame 游戏 - 壹】开启新世界的大门
- 【Flutter&Flame 游戏 - 贰】操纵杆与角色移动
- 【Flutter&Flame 游戏 - 叁】键盘事件与手势操作
- 【Flutter&Flame 游戏 - 肆】精灵图片加载方式
- 【Flutter&Flame 游戏 - 伍】Canvas 参上 | 角色的血条
- 【Flutter&Flame 游戏 - 陆】暴击 Dash | 文字构件的使用
- 【Flutter&Flame 游戏 - 柒】人随指动 | 动画点触与移动
- 【Flutter&Flame 游戏 - 捌】装弹完毕 | 角色武器发射
- 【Flutter&Flame 游戏 - 玖】探索构件 | Component 是什么
- 【Flutter&Flame 游戏 - 拾】探索构件 | Component 生命周期回调
- 【Flutter&Flame 游戏 - 拾壹】探索构件 | Component 使用细节
- 【Flutter&Flame 游戏 - 拾贰】探索构件 | 角色管理
- 【Flutter&Flame 游戏 - 拾叁】碰撞检测 | CollisionCallbacks
- 【Flutter&Flame 游戏 - 拾肆】碰撞检测 | 之前代码优化
- 【Flutter&Flame 游戏 - 拾伍】粒子系统 | ParticleSystemComponent
- 【Flutter&Flame 游戏 - 拾陆】粒子系统 | 粒子的种类
- 【Flutter&Flame 游戏 - 拾柒】构件特效 | 了解 Effect 体系
- 【Flutter&Flame 游戏 - 拾捌】构件特效 | ComponentEffect 一族
- 【Flutter&Flame 游戏 - 拾玖】构件特效 | 了解 EffectController 体系
- 【Flutter&Flame 游戏 - 贰拾】构件特效 | 其他 EffectControler
- 【Flutter&Flame 游戏 - 贰壹】视差组件 | ParallaxComponent
- 【Flutter&Flame 游戏 - 贰贰】菜单、字体和浮层
未完待续
~
1. 什么是 Parallax
Parallax
译为 视差
。可以想想一下,在你做火车时,旁边的树会飞速向后退,而远处的云却在缓慢运动,这就是由于物体距观察者距离不同,而产生的 视差
。在某些游戏中我们也希望模拟这种视觉感受,这就是 ParallaxComponent
存在的意义。
首先 ParallaxComponent
的特点是会以某个基础速度 运动
,其次它支持多以不同速度运动的图层。没找到什么好的图片素材,Flame
官方的这个案例还不错,就直接拿来看了。如下选中的五张图片分别是从内向外依次是:
bg.png
:背景mountain-far.png
: 远山mountains.png
: 近山trees.png
:远树foreground-trees.png
: 近树
通过 ParallaxComponent
进行叠合运动,就可以产生如下的效果:远处的图层运动慢,近处的图层运动快:代码详见 【21/01】
https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9f7abb93f46c488fb87a76c8aa83b16f~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
如下是代码实现,通过 loadParallaxComponent
方法加载 ParallaxComponent
对象。其中需要传入图层对于的图片数据,索引靠后的图层在前方。另外 baseVelocity
是图层运动的基础速度;velocityMultiplierDelta
是前一层和后一层的速度之比,也就相当于视差的倍率。
class BasicParallaxExample extends FlameGame {
final _imageNames = [
ParallaxImageData('parallax/bg.png'),
ParallaxImageData('parallax/mountain-far.png'),
ParallaxImageData('parallax/mountains.png'),
ParallaxImageData('parallax/trees.png'),
ParallaxImageData('parallax/foreground-trees.png'),
];
@override
Future<void> onLoad() async {
final ParallaxComponent parallax = await loadParallaxComponent(
_imageNames,
baseVelocity: Vector2(20, 0),
velocityMultiplierDelta: Vector2(1.4, 1.0),
);
add(parallax);
}
}
复制代码
2. 指定某层视差速度
通过 loadParallaxComponent
直接加载多个层,有个缺点:每层间的速度比值是恒定的。如果想要动态指定每层的速度该怎么办呢?我们可以通过创建一个个的层来指定不同的速度比:代码见 【21/02】
https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7018c626b5c64a06a9b963310c1a387c~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
通过 loadParallaxLayer
方法,可以加载一个 ParallaxLayer
对象。如下通过 formLayerByMap
方法,把 Map
对象,转化成 ParallaxLayer
列表。
final _layersMeta = {
'parallax/bg.png': 1.0,
'parallax/mountain-far.png': 1.5,
'parallax/mountains.png': 2.3,
'parallax/trees.png': 3.8,
'parallax/foreground-trees.png': 6.6,
};
Future<List<ParallaxLayer>> formLayerByMap(Map<String,double> data) async{
List<ParallaxLayer> result = [];
for(String image in data.keys){
ParallaxLayer layer = await loadParallaxLayer(
ParallaxImageData(image),
velocityMultiplier: Vector2(data[image]!, 1.0),
);
result.add(layer);
}
return result;
}
复制代码
在 ParallaxComponent
组件中,传入 Parallax
对象,该对象构造时,需要指定 ParallaxLayer
列表。这样就可以指定不同层的速度比值,更精确地控制视差的效果。
@override
Future<void> onLoad() async {
List<ParallaxLayer> layers = await formLayerByMap(_layersMeta);
final parallax = ParallaxComponent(
parallax: Parallax(
layers,
baseVelocity: Vector2(20, 0),
),
);
add(parallax);
}
复制代码
3. 加载序列帧资源
如下在最外层添加一个序列帧动画,可以看出此时由于背景在向后运动,所以序列帧所在的层保持静止即可。在视觉上会有一种飞机在向前飞的错觉,这就是相对的参考系。代码见 【21/03】
https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/95e28c29eb8d4b00bc284bb9014c4674~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
如下是创建一个序列帧层的方式,使用 ParallaxAnimationData
加载。ParallaxLayer
创建完毕之后,添加到上面的 layers
列表中即可。
final ParallaxLayer airplaneLayer = await loadParallaxLayer(
ParallaxAnimationData(
'parallax/airplane.png',
SpriteAnimationData.sequenced(
amount: 4,
stepTime: 0.2,
textureSize: Vector2(320, 160),
),
),
repeat: ImageRepeat.noRepeat,
velocityMultiplier: Vector2.zero(),
fill: LayerFill.none,
alignment: Alignment.center,
);
复制代码
这里说明一下:只是介绍一下如何在 ParallaxComponent
中加入序列帧图层,像小人这种主角,一般还是作为一个 Component
加入游戏场景中的,这样方便操作。
4. 简单射击
结合前面学的知识,完成一个简单的设计场景应该不在话下,代码见 【21/04】
另外, ParallaxComponent
也可以抽离出来,单独作为一个构建来使用,没必要把太多逻辑写在 Game
实现类中。如下,通过 Background
构件加载 Parallax
,实现视差的背景效果。
接下来大家可以自己拓展一下,比如添加敌人、射击击中的检测、得分显示,和之前的小案例是一样的,这里就不过多引申了。其实对于游戏而言, UI 的资源也是一个很大的瓶颈。有些好想法,但由于设计素材缺乏,也很难实现。那本文就到这里,明天见 ~
番外: Flame 1.2.0 更新内容:
Falme 最近更新了一个版本,到了 1.2.0
,我们来看一下目前进行了哪些变化:
首先,Compoment
的一个属性发生了变化:
Compoment#shouldRemove ==> bullet.isRemoving
复制代码
对比 1.1.1
和 1.2.0
可以发现,新版本中对 text
进行了优化:之前文字通过一个 text.dart
文件进行实现,现在多了一个 text
的包,并且提供了 SpriteFontRenderer
来渲染精灵图字体。但目前源码看来并不是很好用,需要指定的参数非常麻烦,特别是 GlyphData
,感觉需要和特定的工具结合,加上解析才能用。
另外 1.2.0
中增加了 utils
包,其中有两个贝塞尔曲线相关的工具函数:
另外,对 Component
的事件支持做了优化,提供了 events
包:关于构件的事件通过 XXXCallback
进行处理,这是为了替换掉以前的 XXXable
,这点还是比较赞的。
effects
中提供了 AnchorEffect
可以对构件的锚点进行特效处理:
components/input
包中增加了 KeyboardListenerComponent
,这样监听键盘事件可以更方便了:
components/mixin
中增加了三个混入类 :
components
中增加了两个显示 fps
相关的构件:
最后 assets
包并入了 cache
包中:
@张风捷特烈 2022.06.16 未允禁转
我的 掘金主页
: 张风捷特烈我的 B站主页
: 张风捷特烈我的 github 主页
: toly1994328