flame_splash_screen 使用指南:为你的 Flame 游戏打造炫酷启动画面
【免费下载链接】flameA Flutter based game engine.项目地址: https://gitcode.com/GitHub_Trending/fl/flame
flame_splash_screen是 Flame 游戏引擎官方生态中的一款 Flutter 组件包,它为游戏启动阶段提供一段带有火焰 Logo 展示的动画启动画面(Splash Screen),并支持完全自定义主题、前置/后置内容以及动画节奏控制。本文基于仓库中 packages/flame_splash_screen/README.md 展开,并结合该包的源码实现(splash.dart、controller.dart、theme.dart)深入讲解每个配置项的真实行为,读完本文你将能够在自己的 Flame 游戏中完整落地一套可定制、可控制时长的启动画面。
一、包概况与安装
flame_splash_screen的核心价值在于:无需自己编写动画控制器与资源加载逻辑,一个FlameSplashScreenWidget 即可呈现完整的 Logo 展示动画。从 pubspec.yaml 可以看到当前版本为0.3.1+3,其依赖极轻——仅依赖flutterSDK 与meta包,因此非常适合作为游戏首屏。
安装时只需在项目的pubspec.yaml的dependencies中添加该包(支持任意合法的 pub 依赖版本约束),然后在 Dart 代码中导入:
import 'package:flame_splash_screen/flame_splash_screen.dart';需要注意当前仓库环境中该包要求 Dart SDK>=3.12.0 <4.0.0、Flutter>=3.44.0(见 pubspec.yaml),请确认你的运行环境满足该前提。
二、最简单用法:两个必填参数
FlameSplashScreen是一个 StatefulWidget,使用它只需要两个必填参数:
| 参数 | 类型 | 说明 |
|---|---|---|
onFinish | ValueChanged<BuildContext> | 所有动画步骤全部播放完毕后执行的回调,通常在此跳转到游戏主界面 |
theme | FlameSplashTheme | 主题,可直接使用内置的FlameSplashTheme.dark或FlameSplashTheme.white |
最小可用示例:
FlameSplashScreen( theme: FlameSplashTheme.dark, onFinish: (BuildContext context) => Navigator.pushNamed(context, '/your-game-initial-screen'), );动画结束后,onFinish会收到当前的BuildContext,你可以借此执行页面跳转。从 splash.dart 的源码可以看到,onFinish实际是在initState阶段通过controller.setup(steps.length, () => widget.onFinish(context))注入到控制器中的,控制器内部走完所有步骤后才会触发它。
三、在 Logo 前后插入自定义内容
启动画面本质上是一连串"步骤"的依次展示。从源码 splash.dart 的_computeSteps可以看到,动画步骤队列的构成是:
steps = [ if (widget.showBefore != null) widget.showBefore!, // 前置内容(可选) widget.theme.logoBuilder, // 火焰 Logo(必有的核心步骤) if (widget.showAfter != null) widget.showAfter!, // 后置内容(可选) ];3.1 showBefore:在火焰 Logo 之前展示
FlameSplashScreen( theme: FlameSplashTheme.dark, showBefore: (BuildContext context) { return Text("To be shown before flame animation"); }, onFinish: (BuildContext context) => Navigator.pushNamed(context, '/your-game-initial-screen'), );3.2 showAfter:在火焰 Logo 之后展示
FlameSplashScreen( theme: FlameSplashTheme.dark, showAfter: (BuildContext context) { return Text("To be shown after flame animation"); }, onFinish: (BuildContext context) => Navigator.pushNamed(context, '/your-game-initial-screen'), );两个参数都是WidgetBuilder?类型,返回值可以是任意 Widget——比如你自己的游戏 Logo、版本号、版权信息或"加载中"提示。也可以同时指定showBefore与showAfter,此时启动画面会依次播放:前置内容 → 火焰 Logo → 后置内容 → 触发onFinish。FlameSplashScreenState.didUpdateWidget(splash.dart)还支持在动画尚未开始时动态更新这两块内容并重新开始播放。
四、主题定制:从内置暗/亮主题到完全自定义
4.1 内置主题
默认主题为深色背景(FlameSplashTheme.dark),适合深色系游戏;切换为FlameSplashTheme.white即可获得白色背景,适合浅色系应用:
FlameSplashScreen( theme: FlameSplashTheme.white, onFinish: (BuildContext context) => Navigator.pushNamed(context, '/your-game-initial-screen'), );从 theme.dart 可以看到两个内置主题的真实定义:
dark:backgroundDecoration为BoxDecoration(color: Color(0xFF000000)),即纯黑背景;white:backgroundDecoration为BoxDecoration(color: Color(0xFFFFFFFF)),即纯白背景;- 两者共用同一个默认
logoBuilder(由_logoBuilder构建的三层火焰 Logo 动画)与constraints: BoxConstraints.expand()。
这些默认值同样在 theme_test.dart 中有单元测试逐一断言,可作为事实依据。
4.2 自定义主题
FlameSplashTheme的构造方法接收三个字段:
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
backgroundDecoration | BoxDecoration(必填) | 无 | 位于 Logo 之下的背景装饰,可设置背景色、渐变、图片等 |
logoBuilder | WidgetBuilder(必填) | 无 | 构建"主步骤"Logo 的 lambda,可替换成你自己的品牌 Logo |
constraints | BoxConstraints | BoxConstraints.expand() | 外层容器约束,默认铺满可用空间 |
自定义示例(更换 Logo 并设置渐变背景):
FlameSplashScreen( theme: FlameSplashTheme( backgroundDecoration: const BoxDecoration( gradient: LinearGradient( colors: [Color(0xFF1A237E), Color(0xFF4A148C)], ), ), logoBuilder: (BuildContext context) => Image.asset('assets/my_logo.png'), ), onFinish: (BuildContext context) => Navigator.pushNamed(context, '/your-game-initial-screen'), );backgroundDecoration是标准BoxDecoration,因此支持颜色、渐变、边框、阴影、背景图等全部能力;logoBuilder返回的 Widget 会成为动画"主步骤",同样经历淡入 → 停留 → 淡出的完整动画周期。
五、Controller 高级用法:掌控时长与启动时机
默认情况下动画在 Widget 挂载后立即自动开始。如果希望手动控制启动时机或精细调节每一段动画的时长,就需要使用FlameSplashController。它允许将FlameSplashScreen的动画节奏定制化——控制器应存活与 Widget 状态相同的生命周期。
5.1 控制器参数
FlameSplashController构造方法(controller.dart)提供了 4 个参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
fadeInDuration | Duration(milliseconds: 750) | 每个步骤的淡入(显示)时长 |
waitDuration | Duration(seconds: 2) | 每个步骤淡入完成后的停留时长 |
fadeOutDuration | Duration(milliseconds: 450) | 每个步骤的淡出(隐藏)时长 |
autoStart | true | 是否在 Widget 挂载后自动开始播放;设为false后可手动调用start() |
从源码可以看到,三段时长会被封装进FlameSplashDurations(controller.dart),并提供totalgetter(三段时间之和)。每个步骤动画(__SplashScreenStepState.startAnimation,见 splash.dart)的执行流程为:fadeInDuration内透明度从 0 淡入到 1 →waitDuration停留 →fadeOutDuration内淡出,随后控制器在等待一个total周期后进入下一步骤(controller.dart),直至最后一个步骤结束触发onFinish。
5.2 完整示例:手动控制 + 前后内容 + 生命周期管理
class SplashScreenGameState extends State<SplashScreenGame> { FlameSplashController controller; @override void initState() { super.initState(); controller = FlameSplashController( fadeInDuration: Duration(seconds: 1), fadeOutDuration: Duration(milliseconds: 250), waitDuration: Duration(seconds: 2), autoStart: false, ); } @override void dispose() { controller.dispose(); // dispose it when necessary super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: FlameSplashScreen( showBefore: (BuildContext context) { return Text("Before the logo"); }, showAfter: (BuildContext context) { return Text("After the logo"); }, theme: FlameSplashTheme.white, onFinish: (context) => Navigator.pushNamed(context, '/the-game-initial-screen'), controller: controller, ), ); } }5.3 autoStart 与手动 start 的行为细节
控制器内部维护一个三态状态机FlameSplashControllerState(controller.dart):
idle:尚未开始,但已就绪。若设置了autoStart,该阶段会被跳过;started:已开始,正在按步骤播放;finished:全部步骤播放完毕,onFinish已触发。
当autoStart: false时,你可以通过controller.start()在任意时机启动动画(例如等待某个资源加载完成、等待用户点击"开始"按钮后再播放)。start()方法内部带assert校验(controller.dart):一是控制器必须已被某个FlameSplashScreenWidget 使用(即已调用过setup),二是不能重复启动——这些约束同样在 controller_test.dart 中通过throwsAssertionError断言验证。另外注意:当autoStart: true时切勿再手动调用start(),否则会触发断言失败。
需要特别强调的是生命周期:请务必在dispose()中调用controller.dispose()。值得注意的是,如果你把 controller 作为参数传入 Widget(外部控制模式),FlameSplashScreenState自身不会替你 dispose 它(见 splash.dart),释放职责完全落在你的 State 上;只有内部自建控制器时 Widget 才会自动释放。
六、动画原理:三层 Logo 与步骤动画的实现细节
6.1 火焰 Logo 的三层结构
默认 Logo 动画由AnimatedLogo(theme.dart)渲染,它把三张 PNG 资源以Stack叠加:
assets/layer1.png:底层火焰;assets/layer2.png:中间层,其透明度绑定动画值(随动画在 0~1 之间往复);assets/layer3.png:顶层火焰。
中间层的透明度由LogoComposite的AnimationController(周期 500ms)驱动,播放完成后自动反向、归零后再正向,从而形成火焰"跳动/呼吸"的循环视觉效果。整个 Logo 通过_logoBuilder包在LayoutBuilder+FractionalTranslation(Offset(0, -0.25))+ConstrainedBox(Size(300, 300))中(theme.dart),即默认居中略偏上、最大 300×300 的展示区域。相关资源位于 packages/flame_splash_screen/assets/ 目录,并已在 pubspec.yaml 中声明为 Flutter assets。
6.2 步骤播放的驱动方式
FlameSplashScreenState.build(splash.dart)通过ValueListenableBuilder监听controller.stepController(一个ValueNotifier<int>),当前步骤索引变化时重建对应的_SplashScreenStep;每个步骤都是一个独立的 StatefulWidget,自带AnimationController完成"淡入 → 停留 → 淡出"三阶段。因此每新增一个showBefore/showAfter步骤,总播放时长就会增加一个完整的fadeIn + wait + fadeOut周期。
6.3 控制器的时序推进
FlameSplashController._tickStep(controller.dart)以递归 +Future.delayed(durations.total)的方式推进步骤索引:每等待一个total周期后判断是否已到最后一个步骤,是则置为finished并调用onFinish,否则进入下一步。这也解释了为什么每个步骤会完整走完三阶段动画后控制器才推进到下一个。
七、完整落地示例
仓库自带的示例应用位于 example/lib/main.dart,它演示了启动画面到主界面的完整流转:MyApp启动后进入SplashScreenGame,其中FlameSplashScreen同时使用了showBefore、showAfter与FlameSplashTheme.dark,动画结束后通过Navigator.pushReplacement替换为OtherScreen,且支持"Come again"按钮再次进入启动画面——说明FlameSplashScreen可以被重复创建与展示,每次挂载都会重新走一遍完整动画:
class SplashScreenGameState extends State<SplashScreenGame> { @override Widget build(BuildContext context) { return Scaffold( body: FlameSplashScreen( showBefore: (BuildContext context) { return const Text('Before logo'); }, showAfter: (BuildContext context) { return const Text('After logo'); }, theme: FlameSplashTheme.dark, onFinish: (context) => Navigator.pushReplacement<void, void>( context, MaterialPageRoute(builder: (context) => const OtherScreen()), ), ), ); } }八、测试保障与进阶提醒
该包为关键行为提供了单元测试,可作为你排查问题时的参考:
- controller_test.dart:覆盖
autoStart开/关两种模式下控制器的启动校验(未挂载不可 start、不可重复 start)、状态迁移(idle → started → finished)以及步骤结束后onFinish的触发; - theme_test.dart:断言
white与dark两个内置主题的背景色与约束的精确取值。
进阶使用提醒汇总:
- 总时长预估:每个步骤的完整周期为
fadeInDuration + waitDuration + fadeOutDuration,默认(750ms + 2s + 450ms)约 3.2 秒;三个步骤(含前后内容)总耗时约 9.6 秒,设计游戏体验时请务必考量该累计时长; - 生命周期纪律:外部传入的 controller 必须由你负责
dispose(); - 自动启动与手动启动互斥:
autoStart: true时不要再调用start(); - 跳转时机:
onFinish是所有步骤结束后的唯一钩子,在此处进行Navigator跳转(pushReplacement可避免用户按返回键回到启动画面); - 版本前提:当前仓库版本要求 Dart
>=3.12.0、Flutter>=3.44.0,升级运行环境时注意兼容。
至此,从安装、基础使用、内容定制、主题定制到控制器精细控制,你已经掌握了flame_splash_screen的全部核心能力,可以立刻为你的 Flame 游戏接上一段专业的品牌启动动画。
【免费下载链接】flameA Flutter based game engine.项目地址: https://gitcode.com/GitHub_Trending/fl/flame
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考