【Flutter&Flame游戏 - 玖】探索构件 | Component 是什么


theme: cyanosis

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 10 天,点击查看活动详情


前言

这是一套 张风捷特烈 出品的 Flutter&Flame 系列教程,发布于掘金社区。如果你在其他平台看到本文,可以根据对于链接移步到掘金中查看。因为文章可能会更新、修正,一切以掘金文章版本为准。本系列文章一览:

> 第一季完结,谢谢支持 ~

1. Component 的树形结构

通过前面八篇的尝鲜,或说预热,我们可以感知到无论是主角、怪兽、文字、子弹、触点都是 Component 。它是游戏的基本构建模块,可以表示任何需要被渲染、更新的内容。


下面是 Component 类的部分结构,可以看出 Component 是一个普通类。其本身会持有父级构件,以及子级构件集合。也就是说 Component 本身是一个树形结构的节点类,认识到这一点至关重要。


正是由于树形结构的特点,Component 类有添加移除 构件的能力。如下所示,可以通过 add 方法添加子级构件,也可以通过 addToParent 方法,将自身添加到父级构件中。


前面介绍过子弹、怪物消失,使用的是 removeFromParent 方法。如下源码中可以看出,是调用父级构件 _parent 的移除方法,把当前构件对象从父级节点上移除:

dart ---->[Component#removeFromParent]---- /// Remove the component from its parent in the next tick. void removeFromParent() { _parent?.remove(this); }


2. Component 生命周期状态

Component 中有一个 _state 属性,其类型为 LifecycleState 枚举,用于表示构件的状态:

其中有如下 6 种状态,初始状态是 uninitialized ,表示未初始化,也就是构件实例化时的默认状态。前面知道构件中有个 onLoad 的异步方法用于加载资源,在执行异步方法的前一刻就是 loading 状态。该状态会持续到异步方法执行完毕,变成 loaded 状态。

dart enum LifecycleState { uninitialized, loading, loaded, mounted, removing, removed, }

Component 是树形结构的节点,当某个 Component 添加到父节点上后,就会变成 mounted 状态。相关代码如下所示:


另外当父级执行 remove 方法时,入参的子构件非 removing 状态时,会被加入到 lifecycle._removals 列表中,等待下帧触发时移除。此时该子构件的状态为 removing 。当构件被从父节点上移除后,其状态为 removed ,就变成了孤魂野鬼,等待被 GC 回收。

如下图是六种状态的转换示意图,其实还是比较清晰的。了解这六种状态,在下篇介绍 Component 生命周期方法时,就会更好理解。


另外 Component 中关于生命周期状态有三个 get 方法,这里介绍一下:

  • isLoaded:非 uninitialized 且非 loading 状态,表示异步加载任务是否已经完成。
  • isMounted: mountedremoving 状态,表示构件依然在树上。
  • shouldRemove: removing 状态,表示构件已被收集到移除列表中,将在下一帧中被移除。

```dart ---->[Component]---- bool get isLoaded { return (state != LifecycleState.uninitialized) && (state != LifecycleState.loading); }

bool get isMounted { return (state == LifecycleState.mounted) || (state == LifecycleState.removing); }

bool get shouldRemove => _state == LifecycleState.removing; ```


3. Component 的衍生类

Flamecomponents 包中的文件,是对 Component 的衍生。其中一些 mixin ,比如 DraggableHoverableTappable 等都是依赖于 Component ,情理上来说也算是 Component 的衍生产物。


Component 大致可分为三大类,支持定位和变换的 PositionComponent 、附加效果的 Effect 、以及直接继承自 Component 的少数构建。

其中群体最庞大的是 PositionComponent ,这一族引入了 尺寸锚点位置旋转缩放 等属性,决定了该族构件将非常实用:

我们之前用的 SpriteComponentTextComponentSpriteAnimationComponent 等都是 PositionComponent 一族的。另外,自定义的子弹、主角、怪兽,也都是 PositionComponent


另外,Effect 一族定义在 effects 包中,我们在前面用到的 MoveEffect 就是这类的构件。在之后的学习中我们再深入认识其他的效果,或者自定义 Effects


4. 自定义 Component

前面的案例中我们也尝试过自定义 Component ,比如 AdventurerMonsterTouchIndicator 等。其实自定义 ComponentFlutter 中自定义 Widget 的功效类似,都是为了把一些通用的构成逻辑进行封装,以便复用和管理。

比如通过下面的 Monster 类,可以生成多个怪兽对象:可以定义不同的帧序列和生命值,它们对于玩家来说就是两个不同的怪兽。对于编程者而言它们都是通过 Monster 构建类实例化的对象,本质没有什么区别。代码详见 【09/01】

2022年06月02日15-17-12.gif

```dart class Monster extends SpriteAnimationComponent with Liveable { final double life; Monster({ required SpriteAnimation animation, required Vector2 size, required Vector2 position, this.life = 4000, }) : super( animation: animation, size: size, position: position, anchor: Anchor.center, );

@override void onDied() { removeFromParent(); }

@override Future onLoad() async { initPaint(lifePoint: life); }

void move(Vector2 ds) { position.add(ds); } } ```


另外,通过自定义构件类,可以覆写 Component 的相关回调方法,监听相关状态,处理逻辑。这里先对 Component 认识到这里,下一章我们将信息探讨一下 Component 的生命周期回调。那时你就会对 Component 有一个更深的认知,那么本文就到这里,明天见 ~

\

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值