* 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 engine itself is an init->(update->draw)
loop:
init
initializes [whatever rendering medium you're using], the display, the game's data, the default scene and so onupdate
runs a bit of code you'd like to run every framedraw
draws all your things and puts them on the screenYou 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.
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!
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
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
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.
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
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!