Building a Game Engine with Firebase and Flutter

A Deep Dive
Lee Higgins
Lee Higgins
May 14, 2024

Introduction

At first glance, the idea of building a game engine on Firebase and Flutter might seem unconventional. However, imagine a scenario where designers can collaborate in real-time on the same level, make instant changes, and test these changes on the fly. Envision a persistent world where hundreds—or even thousands—of players interact simultaneously. This is exactly what we've been working on for the past two years. Let’s explore how these technologies make it possible.

Understanding Firebase

Firebase is not just a real-time database; it’s a dynamic platform that enables data storage, querying, and real-time updates. Changes made to the data are broadcasted to all active listeners, managed efficiently by Google’s robust infrastructure. The resulting low-latency communication allows for real-time interactions across a distributed network.

Capabilities Enabled by Firebase

Using Firebase as our backbone, we designed our game engine to support massive multi-user environments typically seen in social apps but rarely in online games. By leveraging Firebase’s scalability, we can support thousands of players simultaneously, all interacting within the same game world. The real-time data synchronization allows for immediate updates and a persistent world state, crucial for dynamic and immersive gaming experiences.

Game Engine Architecture

We decided we needed an Entity Component System (ECS) at the core of our engine. ECS is a widely-used architectural pattern in game development that prioritizes composition over inheritance, enabling more flexible and manageable codebases. In an ECS, each entity—be it a character or an object—comprises various components such as position, mass, and visuals. Systems within the ECS handle specific behaviors, like updating entity positions based on their physical attributes. Initially we have chosen to use Dartemis and so far it has served us well. One advantage of the pattern is that it's fairly easy to refactor and replace the implementation if we need to.

Spatial Management with Firestore

To efficiently manage large game worlds, we use Firestore to query entities based on their location. By employing spatial hashes, specifically geohashes, we can perform fast and localized queries to retrieve only the relevant entities in a particular area. This spatial querying mechanism is fundamental for supporting expansive, densely populated environments.

The geohashes handle streaming entities in and out on a large scale, but we also employ a Quad space query system for doing fast local spatial queries, this allows us to implement things like collision detection and flocking behaviors. 

Handling Offline Scenarios and Data Efficiency

Firestore excels in managing offline scenarios. It automatically caches changes made locally and syncs them once connectivity is restored. During the development phase, we use Firestore's capabilities to toggle between real-time and cached data modes depending on the needs, optimizing data usage and costs when the game moves into production. We use the firestore bundles feature to save on database reads for more static entities.

Integration with Flutter

Flutter not only integrates seamlessly with Firebase but also brings powerful cross-platform capabilities to the table. By compiling directly to native code and leveraging the Skia graphics engine (impeller for iOS), Flutter allows us to achieve high-performance rendering across multiple platforms—iOS, Android, Windows, and web—all from a single codebase. Furthermore, Flutter’s comprehensive widget library enables us to easily implement sophisticated UIs and animations critical for modern games. Implementing in app purchase for our "128 Things" game for example was a breeze using revenueCats flutter SDK.

Handling Large-Scale Assets

A standout challenge in game development is managing extremely large assets without compromising performance. For instance, in our game "128 Things," we deal with assets as large as 234 megapixels. Such large images cannot be loaded into RAM all at once due to their size. To address this, we implemented a custom level-of-detail (LOD) system that dynamically adjusts image resolution based on the camera's zoom level. This system not only optimizes memory usage but also ensures smooth performance and visual quality. Additionally, we use image tiling techniques, which allow only the visible regions of these massive images to be decompressed into RAM at any given time. This approach minimizes the load on the system and ensures efficient handling of large graphical assets, making it possible to create vast and richly detailed game worlds.

Advanced Features and Future Prospects

Our game engine supports complex animations with tools like Rive.app, handles large-scale images efficiently using custom level-of-detail systems, and provides a versatile platform for real-time, collaborative game development; we even have flocking and collision systems. While our initial release, "128 Things," demonstrates the engine's basic capabilities, the true potential of our technology lies in its scalability and flexibility, paving the way for more complex and engaging game projects. I can't wait for what is next.

Its not finished yet!

So one thing I forgot to mention.... no sorry you can´t sign up to use it yet! Although the engine is very powerful in it current form, and we have manage to publish a game with it... Its far from ready to turn into a product. Only a very select few are in the beta (you know who you are). The UI needs a lot of love and its still very much in prototype stage. This is where we need help. We will continue to work on the engine, but it is a giant project and our resources are limited, this is why we are seeking ways we can speed up the development, if you have any ideas, yes you, please contact us! :)