稀土掘金 稀土掘金

【Flutter&Flame 游戏 - 壹】开启新世界的大门

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


一、 新的可能性

Google I/O 2022 对于 Flutter 而言,将 休闲游戏 带入了大众的视野。让 Flutter 除了应用开发之外,有了新的可能性。其中作为游戏开发引擎的 Flame ,也为更多人所知晓。说实话,之前我并不怎么看得上 Flame ,无论是官网还是文档,内容都很少,感觉非常小众。我期待着官方可以出一个游戏引擎,但现在看来,官方也倾向于使用 Flame 引擎来开发休闲的 2D 游戏,那我无需再等,开摆 。

  • 【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 游戏 - 贰贰】菜单、字体和浮层
  • 【Flutter&Flame 游戏 - 贰叁】 资源管理与国际化
  • 【Flutter&Flame 游戏 - 贰肆】pinball 源码分析 - 项目结构介绍
  • 【Flutter&Flame 游戏 - 贰伍】pinball 源码分析 - 资源加载与 Loading
  • 【Flutter&Flame 游戏 - 贰陆】pinball 源码分析 - 游戏主菜单界面
  • 【Flutter&Flame 游戏 - 贰柒】pinball 源码分析 - 角色选择与玩法面板
  • 【Flutter&Flame 游戏 - 贰捌】pinball 源码分析 - 游戏主场景的构成
  • 【Flutter&Flame 游戏 - 贰玖】pinball 源码分析 - 视口与相机

第一季完结,谢谢支持 ~


1. 弹球开源弹球游戏 pinball

I/O 2022 中, 官方用 Flutter 写的弹球小游戏,确实让我眼前一亮,开源地址在: 【pinball】。这说明基本的碰撞、音乐、动画没有什么问题,用来做休闲小游戏是足够的,我也就没什么好担心的了。

所以,接下来将开启一个系列,研究 Flutter&Flame 的游戏 2D 休闲游戏开发。另外,为了录屏、截图方便,这里主要在 macOS 平台上运行,实现桌面版的 Flutter 游戏。


2. 本文目标

本文作为 Flame 最简使用,相当于一个 Hello World 级别的案例。

  • 项目搭建与资源配置
  • 播放背景音乐
  • 显示如下的人物动作


二、项目搭建

1. 依赖与资源配置

首先在 pubspec.yaml 中引入 flameflame_audio 包。

---->[]----
dependencies:
  #...
  flame: ^1.1.1
  flame_audio: ^1.0.2

然后在根目录下创建 assets 目录,其中图片放在 images 文件夹下,音乐放在 audio 下,并在 pubspec.yaml 中配置对应的文件夹。这里的背景音乐,取自 【pinball】 中,图片资源在网上找的。


2. 最简代码

这里先实现一下静态图片的展示 + 背景音乐播放:代码 【tag1-1】

目前 lib 代码结构如下:

├── lib
│   ├── component.dart
│   └── main.dart

main.dart 里,runApp 方法传入 GameWidget 组件,其中 game 入参对象是自定义的 TolyGame 。继承自 FlameGame ,并重写 onLoad 方法,添加一个自定义的 HeroComponent 。另外通过 FlameAudio.play 方法播放音乐。

---->[main.dart]----
main() {
  runApp(GameWidget(game: TolyGame()));
  FlameAudio.play('background.mp3');
}
​
​
class TolyGame extends FlameGame {
  @override
  Future<void> onLoad() async {
    await add(HeroComponent());
  }
}

component.dart 中,HeroComponent 继承自 SpriteComponent 。在 super 构造中指定 sizeanchor 参数。覆写 onLoad 方法,为 sprite 成员实例化。在 onGameResize 中将位置居中,这样运行项目,就可以得到如下的效果:

---->[component.dart]----
class HeroComponent extends SpriteComponent {
​
  HeroComponent() : super(size: Vector2(50,37), anchor: Anchor.center);
​
  @override
  Future<void> onLoad() async {
    sprite = await Sprite.load('adventurer/adventurer-bow-00.png');
  }
​
  @override
  void onGameResize(Vector2 gameSize) {
    super.onGameResize(gameSize);
    position = gameSize / 2;
  }
}

3. 初步分析

在自定义的 HeroComponent 中,我们操作了两个没有声明的对象,这说明肯定是在父类中声明过了。其中sprite 成员定义在 SpriteComponent 中,position 成员定义在 PositionComponent 中。

---->[源码-sprite_component.dart]----
class SpriteComponent extends PositionComponent with HasPaint {
  Sprite? sprite;
  
---->[源码-position_component.dart]----
@override
set position(Vector2 position) => transform.position = position;

简单瞄一下源码可以看到继承关系,所以在子类中可直接使用这两个属性。positionVector2 对象,可以确定位置,spriteSprite 对象,可以确定资源。

PositionComponent
    |--- SpriteComponent
        |--- HeroComponent (自定义)

从这里可以简单感知到,在 FlameComponent 是一个比较重要的概念,它可以决定显示。为了避免和 Flutter 中的 Widget 组件 语义冲突, 这里称 Component构件


三、多图人物的帧动画

上面简单地实现了展示一张图片,下面来看一下多帧的图片如何显示:代码 【tag1-2】


1. 代码实现

之所以看到射手在动,是因为在不断播放,如下文件夹是不同帧对应的图片,adventurer-bow9 帧。


实现起来也非常简单,单图有 SpriteComponent 构件,多图也有对应的 SpriteAnimationComponent 构件。该类中内置声明了SpriteAnimation 类型的 animation 对象,所以在 onLoad 中初始化即可。其中 stepTime 用于控制运动的速度,这里 0.15 比较正常,数值越小,运动越快。

class HeroComponent extends SpriteAnimationComponent {
  HeroComponent() : super(size: Vector2(50,37), anchor: Anchor.center);
  
  @override
  Future<void> onLoad() async {
    List<Sprite> sprites = [];
    for(int i=0;i<=8;i++){
      sprites.add(await Sprite.load('adventurer/adventurer-bow-0$i.png'));
    }
    animation = SpriteAnimation.spriteList(sprites, stepTime: 0.15);
  }
  
  @override
  void onGameResize(Vector2 gameSize) {
    super.onGameResize(gameSize);
    position = gameSize / 2;
  }
}

2. 本文小结

通过这个小案例,我们见到了几个类,这里来梳理一下。其中 GameWidget 是继承自 GameWidget 的组件,构造时必须传入 Game 类型的 game 入参。

class GameWidget<T extends Game> extends StatefulWidget {
    final T game;
  
    const GameWidget({
    Key? key,
    required this.game, 

另外, FlameGame 类继承自 Component 并且混入 Game ,这也是为什么 FlameGame 子类可以作为 game 参数的原因。

class FlameGame extends Component with Game {

最后,最重要的莫过于 Component 构件,可以看出我们当前的代码都是围绕 Component 一族展开的。我们自定义类中覆写的 onLoadonGameResize 方法,都是定义在 Component 中的。另外 add 方法,可以添加一个 Component 对象,这是很明显的组合设计模式。

---->[源码-component.dart]----
Future<void>? onLoad() => null;

@mustCallSuper
void onGameResize(Vector2 size) => handleResize(size);

 Future<void>? add(Component component) => component.addToParent(this);

在后面我们应该还会遇到功能各异的 Component ,或也可能自定义一个 Component 来实现某种特殊的功能。本文作为一个简单的引子,想介绍的就这么多,那就到这里,明天见 ~


  • @张风捷特烈 2022.05.26 未允禁转
  • 我的 公众号: 编程之王
  • 我的 掘金主页 : 张风捷特烈
  • 我的 B站主页 : 张风捷特烈
  • 我的 github 主页 : toly1994328

\

玻璃钢生产厂家重庆佛像玻璃钢雕塑价位玻璃钢动物雕塑供应商海棠湾玻璃钢雕塑厂家北京周年庆典商场美陈价钱南昌玻璃钢雕塑报价多少潮汕玻璃钢海螺雕塑郑州玻璃钢艺术雕塑厂家订制福建玻璃钢雕塑介绍贵州玻璃钢卡通雕塑供应河南常见商场美陈研发包头卡通人像玻璃钢雕塑阜阳市玻璃钢雕塑开远玻璃钢牛雕塑商场美陈布置制作公司电话玻璃钢雕塑主要材质是什么金华学校玻璃钢雕塑制作深圳做商场美陈河北玻璃钢雕塑摆件哪家好黑色玻璃钢鹿雕塑河池商场美陈雕塑广东玻璃钢装饰雕塑厂家绥化玻璃钢雕塑制作厂家玻璃钢雕塑翻新用什么油漆梅州玻璃钢卡通雕塑产品介绍菏泽花朵玻璃钢雕塑厂家任丘玻璃钢雕塑玻璃钢花盆手绘素材北京动物雕塑玻璃钢建邺商场新春美陈武威城市玻璃钢雕塑安装香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化