【Flutter&Flame游戏 - 贰拾】构件特效 | 其他 EffectControler

2022-06-19 16:49:24 浏览数 (1)

持续创作,加速成长!这是我参与「掘金日新计划 · 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 的孩子,并指定 delay2 即可:

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 进行重复震荡。这样就可以完成震动、闪烁等特效,比如下面通过重复执行 5SineEffectController ,实现简单的左右震动:

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);
}
复制代码

InfiniteEffectControllerRepeatedEffectController 类似,都可以让子效果 重复运行 。只不过 Infinite 表示重复次数无限,Repeated 可以指定重复次数。比如上面的抖动如果使用 InfiniteEffectController ,就会一直不停抖动。

代码语言:javascript复制
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 身上的所有特效:

代码语言:javascript复制
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

0 人点赞