持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 21 天,点击查看活动详情
前言
这是一套 张风捷特烈 出品的 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. 延迟特效控制器: DelayedEffectController
上一篇中,介绍了 DurationEffectController
一族的特效控制器,本节我们继续来认识一下其他的六种控制器。如下两侧的六个控制器有一个共同的特点,它们都会持有 子控制器
,也就是说它们是在一个控制器的基础上,再施加的变化。本文代码均在 【20/01】
如下是 DelayedEffectController
的构造方法,其中必须传入 child
控制器,另外需要指定延时的秒数。以此达到:子控制器延时 delay
秒开始动画的效果。
如下案例,通过 DelayedEffectController
效果控制器, 让 Curved
效果延时 2s
触发。主需要将 Curved
效果作为 DelayedEffectController
的孩子,并指定 delay
为 2
即可:
https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b51a964ac80340f0973c4e3de0a7a72d~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
代码语言:javascript复制void delayedEffectController(){
EffectController child = CurvedEffectController(2,Curves.ease);
EffectController ctrl = DelayedEffectController(child,delay: 2);
Effect effect = MoveByEffect(
Vector2(0, -100),
ctrl,
);
player.add(effect);
复制代码
2. 重复控制器:Repeated 和 无限控制器 Infinite
顾名思义,RepeatedEffectController
可以让子效果的动画重复执行 repeatCount
次。
上一节介绍了几个震荡型变化的效果,可以结合 RepeatedEffectController
进行重复震荡。这样就可以完成震动、闪烁等特效,比如下面通过重复执行 5
次 SineEffectController
,实现简单的左右震动:
https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/77d99a50093b44abac79cf7943094ff5~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
代码语言:javascript复制void repeatedEffectController(){
EffectController child = SineEffectController(period: 0.1);
EffectController ctrl2 = RepeatedEffectController(child,5);
Effect effect = MoveByEffect(
Vector2(-2, 0),
ctrl2,
);
player.add(effect);
}
复制代码
InfiniteEffectController
和 RepeatedEffectController
类似,都可以让子效果 重复运行
。只不过 Infinite
表示重复次数无限,Repeated
可以指定重复次数。比如上面的抖动如果使用 InfiniteEffectController
,就会一直不停抖动。
void infiniteEffectController(){
EffectController child = SineEffectController(period: 0.1);
EffectController ctrl2 = InfiniteEffectController(child);
Effect effect = MoveByEffect(
Vector2(-2, 0),
ctrl2,
);
player.add(effect);
}
复制代码
这时可能会有人疑问,那如何停止呢?Effect
本身是附在加角色之上的 构建
,只要移除 Effect
,特效就会消失。这样可插拔的设计,正是特效的优势,比如下面代码可以移除 player
身上的所有特效:
player.removeAll(player.children.whereType<Effect>());
复制代码
3.随机效果控制器: RandomEffectController
这里的随机值得是 时长随机
,其中的 child
子效果必须是 DurationEffectController
一族的。而且,使用 RandomEffectController
后,子级设置的时长会被无效。
处理普通构造方法外,RandomEffectController
有两个 factory
构造,其中 uniform
使用的是 _UniformRandomVariable
随机数构造器。它是用于是生成在 min ~ max
之间的随机数:
通过源码很容易看出 _UniformRandomVariable
生成随机数的方式:
另外一个是 exponential
构造,随机数生成器是 _ExponentialRandomVariable
,其中传入一个 double
类型的 beta
小数:
源码中可以看出,其对随机数处理的逻辑。其中 log
函数是以 e
为底 。 1-_random.nextDouble()
小于 1
,log(x) 的定义域取值范围是 0~1
,值域是 -无穷 ~ 0
。这里是 -logx * beta
,所以取值范围是 0 ~ 无穷
, beta
起到放大效果。
另外吐槽一下,这里命名使用的是 exponential (指数)
,但从逻辑来看这里使用的是 logarithm (对数)
,感觉不怎么严谨。
另外如果有需要,我们也可以自定义 RandomVariable
实现特定的随机数生成器。
4. 速度效果控制器: SpeedEffectController
同样,SpeedEffectController
中的 child
子效果必须是 DurationEffectController
一族,且子级设置的时长会被无效。构造时需要传入 double
型的 speed
参数,表示 每秒的变化量
。
如下案例,向上移动 100
,速度是 10
,就表示 10 s
移动到目的地。仔细思考一下,这个特效对于子弹来说是比较有用的,可以结合 Curve
和 沿曲线运动
来实现一些更好玩的子弹。
https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ddeceb4a0bd14ea9a423177c99099ff4~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
代码语言:javascript复制void speedEffectController(){
DurationEffectController child = LinearEffectController(2);
EffectController ctrl = SpeedEffectController(child,speed: 10);
Effect effect = MoveByEffect(
Vector2(0, -100),
ctrl,
);
player.add(effect);
}
复制代码
5. 控制器序列:SequenceEffectController
SequenceEffectController
中可以传入控制器列表,注意这个序列是顺序的序列,不是各个控制器数值进行叠加。也就是说,会这些控制器会 依次
执行动画。
比如下面是 SequenceEffectController
中放入了三个控制器,角色会依次执行各个控制器的动画:
代码语言:javascript复制void sequenceEffectController(){
DurationEffectController child1 = LinearEffectController(2);
EffectController child2 = ZigzagEffectController(period: 2);
EffectController child3 = CurvedEffectController(2,Curves.ease);
EffectController ctrl = SequenceEffectController([
child1,child2,child3
]);
Effect effect = MoveByEffect(
Vector2(0, -100),
ctrl,
);
player.add(effect);
}
复制代码
6. EffectController 构造
虽然 EffectController
是抽象类,但它有一个 factory
构造,集成了若干参数。仔细看一下就能发现,这些其实都是前面介绍的各个实现类中需要的属性,也就是说 EffectController
通过了一个大杂烩的构造,来减缓控制器的使用。
瞄一下源码就可以看出,本质上就是利用这些参数来实例化实现类进行返回而已。前面的知识理解后, EffectController
的构造方法可以说是迎刃而解。
到这里,通过四篇内容,介绍完了所以的 Effect
和所有的 EffectController
。这里只是针对每个实现类举个小例子,实际中,我们可以结合若干个效果或者控制器来实现一些组合特效。甚至去封装一些特定场景下的特效,以便复用。那本文就到这里,明天见 ~
@张风捷特烈 2022.06.15 未允禁转
我的 掘金主页
: 张风捷特烈我的 B站主页
: 张风捷特烈我的 github 主页
: toly1994328