Generate a game foundation with our new template

Our new template makes it easy to get started building a game with Flutter and Flame

November 3, 2022
and 
November 3, 2022
updated on
April 19, 2024
By 
Guest Contributor

Our team is all about streamlining processes so that we can spend time on the fun parts of development. We love “boring” code, which means we try to standardize our projects and processes where possible. To help us in this endeavor, we have created a few open source templates accessible via our Very Good CLI to give us a scalable base that we can immediately build upon, instead of wasting time on project setup. Very Good CLI currently supports templates for a Flutter Starter App (Core), Flutter package, Dart package, Dart CLI, and federated plugin. Today we announce the addition of a game starter template!

Why we built the Very Good Game template

We started building the Flame game template a few months ago, and then took a detour to work on Very Good Ranch, a game we built with Flutter and Flame that allows you to collect unicorns at your own ranch. In building a real, playable game, we were able to standardize how we might build a game in a way that mirrors our “boring” approach to building apps. We then took what we learned from Very Good Ranch and used it to inform the design of our game template.

We built the Very Good Game template with one question in mind: “Would you actually start with this if you were building a game?” We kept it simple and the feature set pared down because we wanted the template to be a useful foundation without you needing to rip a bunch of stuff out.

Most of the code in the template is project setup, and the code responsible for the actual gameplay is less than 100 lines in total. As with our other templates, once you generate your project, everything is entirely customizable. Feel free to remove things, or update them as you see fit. The template is simply a starting place for how we at VGV would structure a game.

What’s included

The game template includes a simple demo game with the basics you'll need for game development and VGV-opinionated best practices. It has the following features:

Components - Think of them as game objects, or anything that can render in a game.

Entity and Behaviors - Entities are what manage the game objects and the behaviors handle the game logic for those objects. 

Sprite Sheets - Easily access and render sprites on the screen.

Audio - Background music and sound effects within the game.

VGV Project Architecture - This project contains a similar architecture to other VGV projects (see our core starter app).

100% Test Coverage — Each line is executed at least once by a test.

Demo game

The template includes a simple game with the above features. After launching the app, you’ll first see a loading screen as all game assets are loading in the background.

template game loading screen

Then you’ll reach the title page, which includes the game name and the start button. Clicking the start button will start the game: tap the unicorn to display an animation and update the counter. Background music will play in the background, and on each tap, a sound effect plays. To mute it, press the button in the top right. 

Note that there is currently no “win” state, as some games may not be able to be “won” by design. Again, we wanted to keep the template simple and provide the basics for game development, without adding too much that you would need to remove to implement your own game. 

demo game

How to use the Very Good Game template

First, make sure you have Very Good CLI installed.

Then, use the very_good create command to generate your Flame game:

very_good create my_game -t flame_game --desc "My new Flame game"

A closer look at the template code

Sprite sheets and animations

The Unicorn entity has a sprite animation, which displays when the unicorn gets tapped and displays the sunglasses falling down over its eyes. Shoutout to our teammate Erick Zanardo for creating this animated unicorn!

unicorn sprite sheet

You can see how the spite sheets are implemented within the game template here:

…
  SpriteAnimation? _animation;

  @visibleForTesting
  SpriteAnimation get animation => _animation!;

  @override
  Future<void> onLoad() async {
    _animation = await gameRef.loadSpriteAnimation(
      Assets.images.unicornAnimation.path,
      SpriteAnimationData.sequenced(
        amount: 16,
        stepTime: 0.1,
        textureSize: Vector2.all(32),
        loop: false,
      ),
    );

    resetAnimation();
    animation.onComplete = resetAnimation;

    await add(SpriteAnimationComponent(animation: _animation, size: size));
  }

  /// Set the animation to the first frame by tricking the animation
  /// into thinking it finished the last frame.
  void resetAnimation() {
    animation
      ..currentIndex = _animation!.frames.length - 1
      ..update(0.1)
      ..currentIndex = 0;
  }

  /// Plays the animation.
  void playAnimation() => animation.reset();

  /// Returns whether the animation is playing or not.
  bool isAnimationPlaying() => !animation.isFirstFrame;
}

Using flame_behaviors

We are using flame_behaviors to define our game objects and their behaviors. For this template, we have a single Unicorn entity that has a TappingBehavior:

class Unicorn extends Entity with HasGameRef {
  Unicorn({
    required super.position,
  }) : super(
          anchor: Anchor.center,
          size: Vector2.all(32),
          behaviors: [
            TappingBehavior(),
          ],
        );

  @visibleForTesting
  Unicorn.test({
    required super.position,
    super.behaviors,
  }) : super(size: Vector2.all(32));

  …

Check out our blog to learn more about how to use flame_behaviors.

Using Bloc to manage state

We are using bloc to manage the state of the volume level of all the audio being played. In this template, a single cubit holds both the audio players and manages their volume:

class AudioCubit extends Cubit<AudioState> {
  AudioCubit({required AudioCache audioCache})
      : effectPlayer = AudioPlayer()..audioCache = audioCache,
        bgm = Bgm(audioCache: audioCache),
        super(const AudioState());

  AudioCubit.test({
    required this.effectPlayer,
    required this.bgm,
  }) : super(const AudioState());

  final AudioPlayer effectPlayer;

  final Bgm bgm;

  void changeVolume(double volume) {
    effectPlayer.setVolume(volume);
    bgm.audioPlayer.setVolume(volume);
    if (!isClosed) {
      emit(state.copyWith(volume: volume));
    }
  }

  void mute() => changeVolume(0);

  void unmute() => changeVolume(1);

  @override
  Future<void> close() {
    effectPlayer.dispose();
    bgm.dispose();
    return super.close();
  }
}

class AudioState extends Equatable {
  const AudioState({this.volume = 1});
  final double volume;

  AudioState copyWith({double? volume}) {
    return AudioState(volume: volume ?? this.volume);
  }

  @override
  List<Object?> get props => [volume];
}

Fun fact: the audio files are a Wolfen original creation. 😎

Audio effects

We are using the audioplayers and flame_audio packages to play both background music and sound effects in the game. The background music uses the Bgm class (Bgm = background music) from the flame_audio package. This class automatically handles looping background music without any gaps in between the segments.

class _GameViewState extends State<GameView> {
  …
  late final Bgm bgm;

  @override
  void initState() {
    super.initState();
    bgm = context.read<AudioCubit>().bgm;
    bgm.play(Assets.audio.background);
  }

  @override
  void dispose() {
    bgm.pause();
    super.dispose();
  }
  …
}

What’s next

For the rest of the year, our team (Open Source & Tooling) is going to focus on making improvements to our existing tools, such as Very Good CLI and Dart Frog. We’re also working on updating documentation for Very Good CLI and the multiple templates it supports (now including this game template!).

We hope that our Very Good Game template is a helpful foundation for your next game! If you're looking for some inspiration, you can learn more about building complex games in Flutter – with a focus on architecture, testing, and automation – in our blog about how we built Very Good Ranch.

Check out the Very Good Game template code →

More Stories