前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Flutter&Flame 游戏 - 贰贰】菜单、字体和浮层

【Flutter&Flame 游戏 - 贰贰】菜单、字体和浮层

作者头像
张风捷特烈
发布2022-06-19 16:55:43
1.4K0
发布2022-06-19 16:55:43
举报

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


前言

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


1.在游戏中添加菜单组件

一般来说,休闲游戏并不会打开时立即进入游戏。会有一个菜单界面,让用户选择开始游戏,或通过设置按钮来打开配置界面,对游戏进行设置。而我们知道,Flame“世界” 是通过 Ticker 不断触发更新的,但往往菜单是 静态 的,不需要一直更新。所以可以使用 Flutter 原生的组件来做菜单,再加上界面跳转也需要原生的路由。

其实本质上来说,Flame 所呈现的游戏界面也只是一个 Widget 而已,我们可以一视同仁。比如下面定义两个 GameWorld 组件,来表示游戏世界: 【22/01】

代码语言:javascript
复制
class GameWorld extends StatelessWidget {
  const GameWorld({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GameWidget(game: TolyGame());
  }
}
复制代码

由于需要界面路由跳转,所以这里使用 MaterialApp ,其内部集成了路由体系。并且这里使用 navigatorKey ,便于在无上下文的情况下,获取导航状态。

代码语言:javascript
复制
class GameApp extends StatelessWidget {
  const GameApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
      debugShowCheckedModeBanner: false,
      navigatorKey: Keys.navKey,
      themeMode: ThemeMode.dark,
      darkTheme: ThemeData(brightness: Brightness.dark),
      home: const MainMenu(),
    );
  }
}

class Keys {
  Keys._();
  static GlobalKey<NavigatorState> navKey = GlobalKey(debugLabel: 'navKey');

  static NavigatorState? get navigator => navKey.currentState;
}
复制代码

比如现在先给个简单的菜单界面,如下所示,一个名字文本,两个按钮:

如下所示,定义一个 Flutter 常规的 MainMenu 组件,对内容进行展示即可,代码如下。其中 开始 按钮通过 Keys 中的 navKey 获取导航栏状态,通过 pushReplacement 方法,跳转到 GameWorld 游戏界面,并将当前的 MainMenu 界面弹栈。

代码语言:javascript
复制
class MainMenu extends StatelessWidget {
  const MainMenu({Key? key}) : super(key: key);

  final TextStyle shadowStyle = const TextStyle(
      fontSize: 30, 
      shadows: [Shadow(color: Colors.white,blurRadius: 10)]
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Wrap(
          spacing: 20,
          direction: Axis.vertical,
          crossAxisAlignment: WrapCrossAlignment.center,
          children: [
            Text('Adventurer', style: shadowStyle,),
            ElevatedButton(onPressed: _doPlay, child: const Text('开 始')),
            ElevatedButton(onPressed: _toOptions, child: const Text('设 置'))
          ],
        ),
      ),
    );
  }

  void _doPlay() {
    Keys.navigator?.pushReplacement(
      MaterialPageRoute(builder: (ctx) => const GameWorld()),
    );
  }

  void _toOptions() {}
}
复制代码

2. 字体下载

有人觉得默认字体可能并不是很好看,想要引入别的字体,但很多字体不可以商用。其实google_fonts 中提供了大量可以商用的字体,我们可以在 fonts.google.com/ 中进行挑选。


在某个字体的 License 中,可以瞄一眼,比如 Ma Shan Zheng 是允许在- 项目-印刷或数字,商业或其他场景使用的。


点击下载,在 OFL 中也可以看到,字体证书是 STL ,允许商用:


你可以通过 线上本地 两种方式来加载字体。线上加载,可以使用 google_fonts 的字体库,所有的字体样式都可以通过 GoogleFonts 类通过静态方法获取,使用时会自动下载字体。

线上的缺点是必须依赖网络,而且需要下载时间,对于很大的字体,首次下载时间比较长,突然的字体改变,体验并不是很好。可以把字体下载到本地,这样就没有延迟的风险,而且在没有网络的情况下也能使用,缺点是会增加应用体积,大家可以酌情选择。本地字体使用也非常方便,只需要引入,在 pubspec.yamlfonts 节点下引入即可:

如果想要指定全局字体,可以在主题数据 ThemeData ,指定对应的 fontFamily

代码语言:javascript
复制
class GameApp extends StatelessWidget {
  const GameApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return  MaterialApp(
      debugShowCheckedModeBanner: false,
      themeMode: ThemeMode.dark,
      darkTheme: ThemeData(
        brightness: Brightness.dark,
        fontFamily: 'ZCOOLKuaiLe' //<--- 指定字体
      ),
      home: const MainMenu(),
    );
  }
}
复制代码

这样就可以对应用的 Text 组件的字体进行统一设置,效果如下:


3. 游戏的暂停和恢复

我们知道 Falme 中通过 GameLoop 维护一个持续触发的 Ticker 用于游戏的渲染更新。当然,游戏中也需要要有暂停和恢复的方法,如下案例中,通过按下空格键来切换游戏状态:

https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bf40900125e6480ca6334a7e09089adf~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

Game 类中提供了 resumeEnginepauseEngine 两个方法,用于恢复和暂停游戏。此外 paused 属性可以得知游戏是否已经停止。由于 FlameGame 混入了 Game ,所以它有这些方法,如果在其他的构件中希望暂停或恢复游戏,可以通过混入 HasGameRef ,来得到 gameRef 对象触发这些方法。

代码语言:javascript
复制
void toggleGameState(){
  if(paused){
    resumeEngine();
  }else{
    pauseEngine();
  }
}
复制代码

4. 在 Flame 中展示浮层

有时我们有显示浮层的需求,比如暂停游戏时,显示暂停面板。不然用户不小心碰到了暂停键,有可能不知所措,显示一个浮层界面可以更好的引导交互。如下所示,在点击空格键时,显示浮层:代码详见 【22/02】


使用浮层需要三步:

  • 1.创建浮层中的内容组件

这里和开始菜单类似,就不贴代码了,详见源码。在其中定义了 Game 成员,在构造方法中初始化,这是为了方便在 PauseMenu 的继续按钮触发时,调用引擎的相关方法,继续游戏。当然,你也可以把事件回调出去,让使用者处理,其实都差不多,酌情考量即可。

另外,定义了一个 menuId 的静态常量,为了方便标识这个菜单,而不是在每处使用时,都写一个死的字符串。


  • 2.通过 GameWidgetoverlayBuilderMap 参数指定 浮层id组件内容 的映射关系:


  • 3.通过 浮层id 开启或隐藏浮层,其中 overlaysGame 中的公开成员:


本文介绍了,如何在 Flame 游戏中,让 Flutter 原生的组件发挥价值。其实 Flame 是在 Flutter 中的,你可以随时随地,使用 Flutter 中的任何知识。并没有必要把 FlameFlutter 进行割裂,Flutter 的基础设施仍然可以使用,比如国际化、主题切换、状态管理等等。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1.在游戏中添加菜单组件
  • 2. 字体下载
  • 3. 游戏的暂停和恢复
  • 4. 在 Flame 中展示浮层
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档