Overview

5 Game board and game loop

In this chapter, the book completes the data-oriented design architecture by adding the parts that make the data and logic into an actual playable game. Unity is used as the implementation layer because it is a familiar OOP engine and provides a useful contrast: the goal is to fit a DOD-style flow into Unity without letting Unity’s usual object-by-object lifecycle take control. The result is a simple, explicit structure where Balance defines the rules, GameData stores state, Logic transforms data, Board presents gameplay, and Game orchestrates everything.

A major theme is reducing complexity by centralizing control. Instead of giving every GameObject its own independent Awake, Start, and Update behavior, the chapter argues for a single Game script to drive the loop, making execution order clear and debugging much easier. Game is implemented as a singleton MonoBehaviour so menus and the board can reach it easily, but the logic layer is kept separate and deterministic, never depending on hidden global state or Unity objects. This preserves testability while still allowing intentional coupling between the Unity-facing orchestration code.

The chapter then shows how to structure a simple Unity scene around that philosophy. Board is responsible for core gameplay presentation and input handling, using custom Init, Show, Hide, and Tick functions instead of Unity lifecycle calls, and it manages object pools, visual updates, and a virtual joystick. Game initializes shared data, starts gameplay, switches menus, and ends the game when Board reports game over. The scene stays minimal—just the camera, Game, Board, and a few UI canvases—because menus, levels, and other runtime differences are treated as data changes rather than separate scenes, keeping the architecture linear, readable, and easy to extend.

Our simple game architecture, showing how Game and Board fit with Balance, GameData and Logic. The Balance data is created at tool time and loaded by Game. Both Game and Board can communicate freely with each other. Only Logic modifies GameData. Both Game and Board can call Logic, and use the changes to GameData, or the return values from the functions they called, to show changes to the player, such as switching menus or moving sprites. Logic only modifies the data it receives and does not call Board or Game directly.
The most common way to make games in Unity, with each object controlling its own game loop using Unity’s lifecycle functions of Awake/Start/Update/OnEnable/OnDisable/etc. This makes debugging difficult because we have to track which objects are running and in what order.
The game loop with a single script, Game, controlling everything. Now it’s trivial for us to figure out what code is running and when, because we are controlling the flow in the game loop, instead of relying on Unity, a black box, to control it for us.
Game drives our entire game loop. It decides which menu to show and whether we are in core gameplay.
Game will always drive our game loop regardless of how many menus we add or how complex our game becomes.
We want to control when Board allocates memory and when it runs every frame, so we use the custom functions Init() and Tick() instead of the Unity-controlled Start() and Update(). This gives us complete control over when Board runs.
The scene hierarchy for our simple survivor game.
In our simple example, we assign assets directly in the Unity Editor by making them public. For a more complex game, load these using an asset management system.
To make it easier to tell where the player is moving, we’ll add a virtual joystick to our game. The outer circle is positioned on mouse down. The inner circle is positioned using mouse move and shows the direction the player will be moving.
Our Game object in the Unity editor with the assets and balance we need to manually assign. Ideally, the assets would be loaded dynamically, and the balance would come in binary form from the game designers.
In our simple example, we bind the StartGame() function to the Start button directly in the Unity Editor.
A basic data-oriented design architecture
The core gameplay architecture. Game takes in Balance and calls Board. Board takes in Input and calls Logic. Logic runs on arrays of data from GameData, which Board and Game then use to show the player what happened.
A generic mess of connections, roughly copied from a post on Reddit where someone was showing off their architecture for implementing a cheat code in their game. This is less than a quarter of what was drawn.

Summary

  • The Board visually shows our game to the player, including sprites and the UI.
  • The Board also takes player input.
  • The Game controls our game loop, including which menu we are on.
  • Singletons are a convenient way to make data publicly available without passing references around.
  • To reduce code complexity, Game is the only script that runs our game loop and the only one that uses Unity’s default lifecycle functions (Awake/Start and Update).
  • The board does not implement Unity’s default lifecycle functions (Awake/Start/Update).
  • The board implements its own function to initialize and allocate data called Init().
  • The board implements its own function that runs every frame, called Tick(), which the game’s Update() calls every frame.
  • To reduce code complexity and keep our architecture simple, we use a single Unity scene to implement our game.
  • Unity scenes are simply objects that hold our Camera and GameObjects; they don't fit a data-oriented architecture because they encapsulate our data in objects.

FAQ

What are the main responsibilities of the Board in this chapter’s architecture?The Board handles core gameplay presentation and input. It takes user input, calls Logic to update GameData, visually updates the player and enemies, and notifies Game when the game is over.
Why does the Game object act as the central game loop controller in Unity?Game drives the entire flow so code is easier to understand, initialize, and debug. It controls when objects are created, when they tick each frame, and when menus or gameplay screens are shown or hidden.
Why is Game implemented as a singleton?Game is a singleton so menus and Board can easily access it from anywhere in the scene. Since there is only one game loop, one globally accessible instance is a good fit for this architecture.
Why should Logic functions avoid accessing Game or Board directly?Logic should stay deterministic, testable, and independent from Unity-facing objects. It should only use data passed in through parameters and return results without relying on singleton state or hidden global data.
Why does this architecture use a single Unity scene instead of multiple scenes?Because most menus, levels, and game modes are treated as data rather than separate runtime scenes. Using one scene reduces complexity and keeps Game responsible for changing state instead of Unity’s scene system.
Why does Board use Init(), Show(), Hide(), and Tick() instead of Unity’s Awake(), Start(), and Update()?These custom functions let Game control when Board allocates memory, becomes visible, and updates each frame. That makes execution order explicit and easier to debug than relying on Unity’s default lifecycle.
What is initialized in Board.Init()?Board.Init() allocates long-lived data needed for the lifetime of the game, such as the enemy object pool. It also hides gameplay objects and UI so they are not visible before gameplay starts.
What happens in Board.Show()?Board.Show() prepares core gameplay to appear on screen. It stores the camera reference, starts the game logic, positions and activates enemies, shows the player, and activates the in-game UI.
How does Board.Tick() coordinate input, logic, and visuals?Each frame, Board.Tick() reads input, calls Logic.Tick() to update GameData, moves the enemy visuals to match the new data, updates the time display, and calls Game.GameOver() if the game has ended.
Why are menus and levels treated as data in this chapter?Because things like menu state, level rules, enemy counts, and visible UI can usually be represented as data instead of separate scenes or systems. This keeps the architecture simpler and makes Game responsible for orchestrating those changes.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • High Performance Unity Game Development ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • High Performance Unity Game Development ebook for free