持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 12 天,点击查看活动详情
前言
这是一套 张风捷特烈 出品的 Flutter&Flame
系列教程,发布于掘金社区。如果你在其他平台看到本文,可以根据对于链接移步到掘金中查看。因为文章可能会更新、修正,一切以掘金文章版本为准。本系列文章一览:
- 【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.关于 Compoent 树
如下图场景,每个显示的物体都是 Component
,它们形成一个树形结构。代码见 【11/01】
各种角色通过 add
方法添加到树中,此时的树型结构如下:
现在有个问题:因为血条和血量是被加入到 Adventurer
构件中的,所以 Adventurer
的变换行为也会引起血条的变换。如下角色沿 Y 轴镜像,可以看到血条及文字也发生了镜像,这并不是我们所期望的。
那如何解决呢?思路很简单,既然 Adventurer
有单独镜像的需求,那就不能是血条的父级。将两者从父子关系变为兄弟关系即可,这里将血条封装为 LifeComponent
构建,和 Adventurer
一起存在于 HeroComponent
中:
2.角色移动中的镜像反转
现在想实现如下效果:如果触点在角色左侧,角色会镜像反转到左侧,反之,镜像反转到右侧。这样的目的是为了角色可以选择攻击的方向,比如面向左侧攻击左侧怪物:代码见 【11/02】
https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9726b9e1be1144f08df333a2117e8d5b~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
因为这里只有左右反转,在 HeroComponent
中定义一个 isLeft
的 bool
值用于记录状态。如果需要支持其他方向,比如上、下、左上、右下等,可以通过枚举来维护。
---->[HeroComponent]----
bool isLeft = true;
late Adventurer adventurer;
late LifeComponent lifeComponent;
复制代码
在点击屏幕时,触发 toTarget
方法,在开始可以通过 _checkFlip
方法来对 isLeft
属性进行维护,已经在需要反转是通过 flip
反转角色:
---->[HeroComponent#toTarget]----
void toTarget(Vector2 target) {
_checkFlip(target);
// 略同...
}
void _checkFlip(Vector2 target){
if (target.x < position.x) {
if (isLeft) {
flip();
isLeft = false;
}
}
if (target.x > position.x) {
if (!isLeft) {
flip();
isLeft = true;
}
}
}
复制代码
用于只想要让主角反转,所以在 flip
中,执行 adventurer.flip
即可。这样就不会影响血条的显示:
void flip({
bool x = false,
bool y = true,
}) {
adventurer.flip(x: x, y: y);
}
复制代码
代码语言:javascript复制---->[HeroComponent#flip]----
void flip({
bool x = false,
bool y = true,
}) {
adventurer.flip(x: x, y: y);
}
复制代码
另外关于反转,还需要注意子弹的发射方向。因为前面的子弹总是向右侧发射的,如果面朝左侧,应该向左运动,如下所示:
https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/51522ebe2fd64c8d9a016a1c7cdd69bf~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?
处理起来也比较简单,根据 isLeft
确实向左还是向右发射即可,如下tag1
---->[Bullet]----
@override
void update(double dt) {
super.update(dt);
Vector2 ds = Vector2(isLeft ? 1 : -1, 0) * speed * dt; // tag1
_length = ds.length;
position.add(ds);
if (_length > maxRange) {
_length = 0;
removeFromParent();
}
}
复制代码
3. 关于属性的维护
前面为了方便演示,对于角色的属性,写的比较零散,比如速度、攻击力等。在这里既然可以封装了 HeroComponent
来维护主角类。就可以定义一个 HeroAttr
类来维护主角的属性,如下所示:
class HeroAttr {
double life; // 生命值
double speed; // 速度
double attackSpeed; // 攻击速度
double attackRange; // 射程
double attack; // 攻击力
double crit; // 暴击率
double critDamage; // 暴击伤害
HeroAttr({
required this.life,
required this.speed,
required this.attackSpeed,
required this.attackRange,
required this.attack,
required this.crit,
required this.critDamage,
});
}
复制代码
这样在构建 HeroComponent
时,传入 HeroAttr
对象来确定该对象的属性信息。
---->[TolyGame#onLoad]----
final HeroAttr heroAttr = HeroAttr(
life: 3000,
speed: 100,
attackSpeed: 200,
attackRange: 200,
attack: 50,
crit: 0.75,
critDamage: 1.5,
);
player = HeroComponent(attr: heroAttr);
add(player);
复制代码
这样在怪物损失生命值,可以根据 HeroAttr
的属性进行计算:
---->[Liveable]----
void loss(HeroAttr attr) {
double point = attr.attack;
double crit = attr.crit;
double critDamage = attr.critDamage;
bool isCrit = _random.nextDouble() < crit;
if (isCrit) {
point = point * critDamage;
}
_damageText.addDamage(-point.toInt(), isCrit: isCrit);
}
复制代码
添加子弹时,可以根据 HeroAttr
的属性信息确定攻速和射程:
本篇,我们继续拓展了角色的功能,知道父级构件的变换会影响子级组件,所以在使用构件时需要注意构件间的关系。另外通过 HeroAttr
封装了角色信息,这样通过 HeroComponent
就可以添加多个主角节点,就可以双人模式打怪。
到这里,可以看到 TolyGame
中非常乱,下一章我来介绍一下,如何对多个角色和怪物进行管理,包括怪物的生成、发射子弹、命中主角等。那本文就到这里,明天见 ~
@张风捷特烈 2022.06.05 未允禁转
我的 掘金主页
: 张风捷特烈我的 B站主页
: 张风捷特烈我的 github 主页
: toly1994328