【Flutter&Flame游戏 - 拾贰】探索构件 角

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


前言

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

第一季完结,谢谢支持 ~


1. 管理怪兽

前面把 Monster 全写在 TolyGame 中,看起来很杂乱。一个场景中可能存在多个怪兽,比如下面六个小怪和一个 Boss 。我们可以通过自定义一个 MonsterManager 构件对这些怪兽进行管理:代码详见【12/01】


MonsterManager 中通过入参将小怪和 Boss 的序列帧传入,这样可以中使用时自定义序列帧:

1
2
3
4
5
6
7
dart复制代码class MonsterManager extends PositionComponent with HasGameRef {
final SpriteSheet bossSpriteSheet;
final SpriteSheet stoneSpriteSheet;
MonsterManager({
required this.bossSpriteSheet,
required this.stoneSpriteSheet,
}):super(anchor: Anchor.center);

onLoad 方法中,通过 createBoss 方法创建并添加 Boss 构件,然后通过 createStoneMonster 方法在左右分别遍历三个小怪。创建和添加 Monster 的方式和前面是一样的,这里就不赘述了,详见源码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dart复制代码@override
Future<void> onLoad() async {
createBoss();
int lineCount =3;
double step = gameRef.size.y/lineCount ;
for(int i=1;i<=lineCount;i++){
final double pY = i*step- 30;
final double pX = gameRef.size.x - 200;
createStoneMonster(Vector2(pX, pY));
}
for(int i=1;i<=lineCount;i++){
final double pY = i*step- 30;
final double pX = 150;
createStoneMonster(Vector2(pX, pY));
}
}

2. 怪兽发射子弹

现在怪物站在那傻乎乎的被打很不公平,下面看看如何让怪兽发射子弹。这里用来两个序列帧动画作为子弹的资源,如下图所示:代码详见【12/02】

其实本质上,怪物发射子弹和主角发射子弹本质上是一样的。不同点在于,主角子弹发送是用户控制的,怪物一般是定时发射子弹。另外,要区分一下子弹的类型,是怪物发射的,还是主角发射的。之前角色的弓箭是静态图片,这里可以定义一个 AnimBullet 来支持序列帧的子弹:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
dart复制代码enum BulletType{
hero,
monster
}

class AnimBullet extends SpriteAnimationComponent {
double speed = 200;
final double maxRange;
final BulletType type;
final bool isLeft;

AnimBullet({
required SpriteAnimation animation,
required this.maxRange,
required this.type,
required this.speed,
this.isLeft = true,
}) : super(animation : animation);

// 略同...

然后看一下如何通过 Timer 来定时不断发射子弹,这里的 TimerFlame 中封装的,不是 Flutter 自带的。如下 Monster 的各个生命周期中对 Timer 进行相关处理:onLoad 方法中初始化 _timer 对象,隔 3 s 钟触发一次 addBullet 方法添加子弹。onMount 方法中开启 _timeronRemove 中停止 _timer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
dart复制代码---->[Monster]----
late Timer _timer;

@override
Future<void> onLoad() async {
_timer = Timer(3, onTick: addBullet, repeat: true);
}

@override
void onMount() {
super.onMount();
_timer.start();
}

@override
void update(double dt) {
super.update(dt);
_timer.update(dt);
}

@override
void onRemove() {
super.onRemove();
_timer.stop();
}

如下是 addBullet 方法,和之前主角发射子弹的逻辑基本一致:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dart复制代码// 添加子弹
void addBullet() {
AnimBullet bullet = AnimBullet(
type: BulletType.monster,
animation: bulletSprite,
maxRange: attr.attackRange,
speed: attr.attackSpeed,
isLeft: isLeft,
);
bullet.size = bulletSize;
bullet.anchor = Anchor.center;
bullet.priority = 1;
priority = 2;
bullet.position = position - Vector2(0, size.y/2);
gameRef.add(bullet);
}

3.怪兽发射的命中

如下所示,在怪物发射的子弹命中主角时,主角也会受到伤害。生命值降低,并且显示伤害数值:代码详见【12/03】

目前仍是校验 矩形域中心点 的包含关系来判定是否命中。如下,在 update 中通过 _checkAttackHero 校验是否命中,命中时 player 触发 loss 方法掉血。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
dart复制代码---->[TolyGame#update]----
@override
void update(double dt) {
super.update(dt);
_checkAttackMonster();
_checkAttackHero();
}

void _checkAttackHero() {
final Iterable<AnimBullet> bullets = children
.whereType<AnimBullet>()
.where((AnimBullet e) => e.type == BulletType.monster);
for (AnimBullet bullet in bullets) {
if (bullet.shouldRemove) {
continue;
}
if (player.containsPoint(bullet.absoluteCenter) ||
bullet.containsPoint(player.absoluteCenter)) {
bullet.removeFromParent();
player.loss(bullet.attr);
break;
}
}
}

到这里,我们已经完成了 主角怪物 间的基本交互,也基本上对 Component 有了较深的理解。接下来将进一步探讨 碰撞检测 相关的知识,毕竟现在靠的是 矩形域中心点 的包含关系,并不是非常准确。那本文就到这里,明天见 ~

\

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%