【Flutter&Flame 游戏 - 陆】暴击 Dash | 文字构件的使用

本文是Flutter & Flame游戏开发系列教程的一部分,讲解如何在游戏中使用TextComponent显示角色生命值和伤害信息。通过TextComponent展示了文字在游戏中的重要性,包括创建、定位、更新文字内容以及实现伤害数值的动态显示和消失效果。同时,文章还介绍了如何处理连续伤害的显示,避免遮挡问题。通过 DamageText 构件实现了暴击伤害的特殊显示。
摘要由CSDN通过智能技术生成

theme: cyanosis

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


前言

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

第一季完结,谢谢支持 ~


1. 文字的价值

无论是应用也好、游戏也好,文字图片 是永恒的显示主体。人类文明是依赖于文字进行传承的,文字的最大价值在于传递信息。如下是阴阳师的战斗截图,其中角色的伤害、当前的成绩、鬼火数量、是否暴击、式神存活状态等,都依赖于文字来显示,向玩家反馈交互的信息。


这里先显示在血条上显示一下血量信息,如下所示:


2. 文字构件 - TextComponent

Flame 中,使用 TextComponent 构件显示文字。我们知道 Flutter 的绘制中通过 TextPainter 类可以绘制文字,其实 TextComponent 构建本质上就是对 TextPainter 的一层封装而已。提供了一个 TextPaint 类进行使用。


如下是 Liveable 中的处理,只需要创建一个 TextComponent 对象,然后使用 add 方法添加即可。另外任何构件都可以通过 add(RectangleHitbox) 来显示边框信息,方便查看所占区域。代码详见:【06/01】

```dart final TextStyle _defaultTextStyle = const TextStyle(fontSize: 10, color: Colors.white); late final TextComponent _text;

void initPaint({ required double lifePoint, Color lifeColor = Colors.red, Color outlineColor = Colors.white, }) { // 略... // 添加生命值文字 text = TextComponent(textRenderer: TextPaint(style: _defaultTextStyle)); _updateLifeText(); // 添加外框信息 _text.add(RectangleHitbox()..debugMode = true); add(text); }

void updateLifeText(){ _text.text = 'Hp ${currentLife.toInt()}'; } ```

如下可见,默认情况下 TextComponent 会与父区域的左上角对齐。另外 TextComponent 也是 PositionComponent 一族的构件,我们可以对其进行平移、缩放、旋转等操作。


比如下面的 tag1 处通过指定 _textposition 进行定位,左侧和血条对齐,并在血条上方:

dart // 添加生命值文字 _text = TextComponent(textRenderer: TextPaint(style: _defaultTextStyle)); _updateLifeText(); double y = -(offsetY+_text.height+2); double x = (size.x/2)*(1-widthRadio); _text.position = Vector2(x, y); // tag1 add(_text);

去掉信息框后如下所示,在点击时减少生命,它是通过 _updateLifeText 更新文字显示即可:


3.显示伤害数据

在怪物受到攻击时,一般会显示造成伤害的数据,来让操作者有更直观的体验。现在期望在当怪兽受伤时,左侧显示伤害量,另外伤害量维持 1s 之后自动消失。如下所示:代码见 【06/02】

伤害数据是在 Liveable 中维护的,虽然可以直接在 Liveable 中添加文字。但这样的话会使得 Liveable 的职能过于复杂,也不利于后续的拓展。我们可以单独定义一个 DamageText 构件,来维护伤害数值的显示逻辑。
如下代码所示,在 Liveable 中添加一个 addDamage 的方法,在 tag1 处添加 damageText 文字。然后使用 Future.delayed 方法,延迟 1s 中,调用 damageText.removeFromParent 方法即可移除。

```dart class DamageText extends PositionComponent{

final TextStyle _damageTextStyle = const TextStyle( fontSize: 14, color: Colors.white, fontFamily: 'Menlo', shadows: [ Shadow(color: Colors.red, offset: Offset(1, 1), blurRadius: 1), ]);

Future addDamage(int damage) async { TextComponent damageText = TextComponent(textRenderer: TextPaint(style: _damageTextStyle)); damageText.text = damage.toString(); damageText.position = Vector2(-30, 0); add(damageText); // tag1 await Future.delayed(const Duration(seconds: 1)); damageText.removeFromParent(); }

} ```


这样在 Liveable 中就不必处理具体添加伤害文字的逻辑,只需要通过 DamageText 来管理即可。比如在 loss 方法中,当角色受到伤害,通过 _damageText.addDamage 来添加伤害文字,这样处理就非常方便。想要对伤害文字进行显示进行修改或拓展,直接在 DamageText 处理即可,这就是职责的分离。

```dart final DamageText _damageText = DamageText();

void initPaint({ required double lifePoint, Color lifeColor = Colors.red, Color outlineColor = Colors.white, }) { // 略... add(_damageText); }

void loss(double point) { _damageText.addDamage(-point.toInt()); // 略... } ```


4. 暴击伤害

这里来模拟一下产生暴击的情况:如下图所示,伤害时有一定概率产生暴击,此时使用另一种文字样式。并给出 暴击 的字样提示:代码见 【06/03】

实现也比较简单,在 addDamage 中,传入 isCrit 的入参,区分是否暴击。如果是暴击,使用 _addCritDamage 进行处理,添加黄色伤害和暴击字样即可。

```dart ---->[DamageText]---- void addDamage(int damage,{bool isCrit = false}) { if(!isCrit){ _addWhiteDamage(damage); }else{ _addCritDamage(damage); } }

Future _addCritDamage(int damage) async { TextComponent damageText = TextComponent(textRenderer: TextPaint(style: _critDamageTextStyle)); damageText.text = damage.toString(); damageText.position = Vector2(-30, 0); TextStyle style = _critDamageTextStyle.copyWith(fontSize: 10); TextComponent infoText = TextComponent(textRenderer: TextPaint(style:style )); infoText.text = '暴击'; infoText.position = Vector2(-30+damageText.width-infoText.width/2, -infoText.height/2); add(infoText); add(damageText); await Future.delayed(const Duration(seconds: 1)); infoText.removeFromParent(); damageText.removeFromParent(); } ```


暴击和爆伤,本应是角色的属性,这里暂时不搞这么复杂,在 Liveableloss 方法中,用 75% 暴击和 165% 爆伤进行简单的测试,代码如下:

```dart ---->[Liveable]---- final Random _random = Random();

void loss(double point) { double crit = 0.75; double critDamage = 1.65; bool isCrit = _random.nextDouble() < crit; if (isCrit) { point = point * critDamage; } _damageText.addDamage(-point.toInt(),isCrit: isCrit); // 略... } ```


5.多次伤害

伤害是在 1s 后消失,当连续伤害在一秒之内,或者在一次伤害中附加多段伤害,就会产生遮挡。所以需要对多次伤害进行一下偏移处理,效果如下:代码见 【06/04】


这里利用了 Component 的一个特性,每个 Component 都有 children 属性,表示子构件集合。在 addDamage 中,只需要根据集合情况,获取最后一个元素,来确定添加文字的偏移即可:

dart void addDamage(int damage,{bool isCrit = false}) { Vector2 offset = Vector2(-30, 0); if(children.isNotEmpty){ final PositionComponent last; if(children.last is PositionComponent){ last = children.last as PositionComponent; offset = last.position + Vector2(5, last.height); } } if(!isCrit){ _addWhiteDamage(damage,offset); }else{ _addCritDamage(damage,offset); } }


文字本身比较简单,但与文字相关的数据维护和逻辑处理还是非常复杂的。本文通过显示角色的生命值伤害值 ,简单说明了一下文字的使用方式。一般游戏中,都是使用图片作为文字,比如阴阳师的伤害数字。记得应该有图片形成字体的工具,比如 6000 的字符串,会对应字体中相关的图片。不过感觉 flame 框架太简单了,应该没有支持。

那本文就介绍到这里,明天见 ~


\

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值