A Simple Architecture (for an Engine)

This post is sponsored by SDL2

* note bueno: in this post im just talkin about simple 2d engines! i am totally not an authority on the subject but after working on a lot of game engine projects, this is my favorite way to do things. thank ya!

A nice idea that crops up a lot (the simpler) game engines is the
init->(update->draw) loop, which is what [something that exists] does throughout the course of its game-life.

It's like how coding an arduino works. setup() for when it first gains consciousness, and loop() forever until the power is removed.

What's surprising is that, for a nice simple setup, this idea can be used throughout an engine's whole architecture.

the toppest top level

The engine itself is an init->(update->draw) loop:

You can make a game with just this alone, but it'd have to be conway's-game-of-life-tier simple otherwise things can get messy quick.

scenes

The best common solution to attach a state machine to your engine. This machine switches between many different states [special init->(update->draw) loops you've made] which lets you run smaller bits of code specific to what you'd like to happen in that moment. Say, one loop can handle your main menu, another one can the first of couple of levels, and so on. This is the concept of a scene!

there are things in the world

The architecture's still a bit chunky. Complicated games keep track of a lot of different things at once. Like in asteroids!

the hit game asteroids

the hit game asteroids

Handling the ship and all the individual asteroids' logic is a hefty task for a single scope. Separate those concerns!

Everything that exists in a game can also be init->(update->draw) loops. An object is created, updated and drawn until destroyed, and everything can be an object.

So now we know:

Things can be greatly abstracted by using only 1 common idea.

it looks way simpler as an image

it looks way simpler as an image

So with this architecture, when update is called at an engine-level, it propagates through to the scene, and then every child object.

When the engine's update is called, the current scene's update is called, and the same is then called for all objects that exist in the scene at that time.

An engine's a little more than that though!

It is! Hmm, what else do you need.. Maybe a drawing library, maybe a physics library. Everything else you need is just utility. These can exist as sets of pure functions which your scenes and objects have access to.

A map of an engine

A map of an engine

And that's my preference when it comes to how my engines work. Everything else is put in place as they're needed. How would you make yours?

As proof of concept, let's do a quick PSEUDOCODE example:
Note that this isn't copy/paste-able this is just an idea

main.lua

scene1 = require "scene1"

local current_scene = scene1

function init()
  init_your_library()
  local window = make_window()

  current_scene:init()
  
  -- this is the gameloop!
  while window.open() do
    update()
    draw()
  end
end

function update()
  current_scene:update()
end

function draw()
  current_scene:draw()
end

init()

scene1.lua

local scene = {}
local objects = {}

function scene:init()
  -- make some objects
  table.insert(objects, require("myObject"))
end

function scene:update()
  for k,v in pairs(objects) do
    v:update()
  end
end

function scene:draw()
  -- maybe draw a background
  draw("background.png", 0, 0)
  -- draw the objects
  for k,v in pairs(objects) do
    v:draw()
  end
end

return scene

myObject.lua

local myObject = {}

function myObject:init()
  self.x = 0
  self.y = 0  
end

function myObject:update()
  -- slowly move right
  self.x = self.x + 1
end

function myObject:draw()
  draw("my_object.png", self.x, self.y)
end

return myObject

And that's it! While the stray functions in this example are huge abstractions, it's clear what they do. I believe you can probably implement them yourself, or even make it a little better!

Thanks for reading!

Go back home