FIT CTU

Adam Vesecký

NI-APH
Lecture 2

Engines

History of game engines

Pre-engine era

Pinball Construction Kit
1983
Adventure Construction Kit
1984
Garry Kitchen's GameMaker
1988
Freescape Engine
1987
Arcade Construction Kit
1988
RPG Maker
1990

Example: Vlak (1993)

1 ; ------ prep for next object
2 PosVlak6:add si,3 ; next obj address
3 mov dx,cx ; prev obj position
4 mov al,0
5 cmp ds:[si],al ; train tail yet?
6 je PosVlak7
7 jmp PosVlak2 ; not tail - next car
8
9 ; ------ last car deletion
10 PosVlak7:cmp dl,-1
11 je PosVlak8
12 call DispObr ; last car deletion
13 mov al,20 ; position counter
14 mul dh ; row-offset recalc
15 add al,dl
16 adc ah,0
17 add ax,offset Pole
18 xchg ax,di ; DI <- array address
19 mov byte ptr ds:[di],0

Source code for MS-DOS: link

ID Tech

  • family of game engines developed by ID Software
  • Id Tech 0 - the very first game engine
  • every next game had more advanced technology
  • all games were based on raycasting until 1996
Hovertank 3-D
1991
Catacomb 3-D
1991
Wolfenstein 3-D
1992
Doom
1993

1993: Doom

1 boolean P_CheckMissileRange (mobj_t* actor){
2 if (!P_CheckSight(actor, actor->target))
3 return false; // can’t see the target
4
5 if ( actor->flags & MF_JUSTHIT ) {
6 // just hit -> fight back!
7 actor->flags &= ~MF_JUSTHIT;
8 return true;
9 }
10
11 if (actor->reactiontime)
12 return false; // do not attack yet
13
14 if (!actor->info->meleestate)
15 dist -= 128*FRACUNIT; // no melee
16
17 // check for ARCH-VILE
18 if (actor->type == MT_VILE){
19 if (dist > 14*64)
20 return false; // too far away
21 }
22 ...

Source code: link

Other pseudo-3D engines

Voxel Space Engine
1992
Jedi Engine
1995
Build Engine
1996

Quake Engine

  • ~id Tech 2
  • released by ID Software in 1996
  • initiated the rise of 3D gaming
  • true 3D real-time rendering, 3D light sources
  • Id Tech 2 Games:
    • Quake, Hexen 2, Silver Wings
  • Other IdTech-based games:
    • Call of Duty
    • Medal of Honor
    • Daikatana
    • Half-Life (forked Source Engine)
  • Successors:
    • id Tech 3, 4, 5, 6, 7

Quake source code: link

Quake engine family

Influence of Game Engines

Game Engines - overview

Game Engines Today

Trends - 2014

Trends - 2022

Unreal Engine

Unreal Engine 1

  • released in 1998 by Epic Games as FPS game engine
  • Unreal - the first game powered by this engine

Unreal Engine 4

  • film-quality postprocessing
  • VFX & Particle Systems
  • beta Raytracing

Unreal Engine 5.3

  • Nanite virtualized geometry
  • Lumen illumination engine
  • source code is available

Unreal games

Batman Arkham Knight

Star Wars Jedi: Fallen Order

Hellblade: Senua's Sacrifice

Borderlands

Fortnite

Planet Alpha

Unity

  • all-purpose (not only) game engine
  • first release in 2005
  • supports all main platforms
  • the most common engine for indie developers
  • source code is available only to enterprise users

Unity 2023.3 - current version

  • UVS - visual language (formerly Bolt)
  • Universal Render Pipeline
  • Split Graphics Jobs
  • new multiplayer engine
  • ECS component engine

Ori

Besiege

Cuphead

Godot

  • 2D and 3D engine
  • GDScript scripting language
  • uses OOP architecture
  • MIT license
  • no well-known games so far

Which engine do I need?

  • 2D microgames with simple animations can be made solely without engines
  • more complex games can be made in graphics libraries
  • Unity is great for 2D and 3D indie games, but doesn't offer low-level customization
  • Unreal is difficult to master, yet it can be customized in any way
  • open-source game engines heavily depend on the community and their future is uncertain
  • migration between engines is practically impossible

Game engine architecture

Game Engine Primary Modules

  • Game Loop - the heartbeat of all games
  • Scene Manager - manages objects and structures them in a scene graph
  • Input Manager - handles inputs (keyboard, mouse, touch, joystick, gamepad,...)
  • Resource Manager - manages assets, controls a cache
  • Memory Manager - memory allocator and deallocator
  • Rigidbody Engine - event-based collision detection
  • Physics Engine - handles behavior of objects based on forces and impulses
  • Rendering Engine - renders the game, takes care of the rendering pipeline
  • Animation Engine - handles animations
  • Scripting Engine - a bridge between the engine and interpreted languages (JS, C#,...)
  • Audio Engine - plays music, clips, sounds, calculates 3D sound
  • AI Engine - abstract engine for AI (state machines, behavioral trees,...)
  • Networking Engine - handles multipeer communication
  • Other modules - GUI framework, Level Editor, Camera, Event System, LOD system,...

Game Loop

Game Loop

  • the most important part of the game engine
  • each turn advances the state of the game
  • usually coordinated with the event loop of the platform/virtual machine
  • optimal time step for rendering: 60 FPS = 16.6 ms per frame
  • input, and physics require more frequent updates
In general, a program spends 90% of its time in 10% of its code. The game loop will be firmly in those 10%.

Simple Game Loop

Game loop with separated rendering

Cooperative game loop

  • first used in Ultima VII (1994)

Update method

Fixed time step

  • each update advances the game by a certain amount of time
  • deterministic and stable
  • the game may slow down

Variable time step

  • each update advances the game based on how much real time has passed since the last frame
  • natural
  • non-deterministic and unstable

Adaptive time step

  • switches between variable and fixed time step based on thresholds
  • deals with long breaks better than the other two

Example: Unity Game Loop

Scene Graph

Scene Graph

Scene Graph

  • essential structure of every interactive application
  • a way of ordering data into a hierarchy
  • represented as an N-Tree or a regular graph
  • implemented as an array, oct-tree, quad-tree, bounding volume hierarchy,...
  • parent nodes affect child nodes (translation, rotation, scale,...)
  • leaves represent atomic units (polygons, vertices)

Scene Manager

  • uses scene graph as a logical hierarchy
  • responsibility: communication, binding to logical components
  • Unity Engine - game objects form a hierarchy
  • Unreal Engine - components form a hierarchy
  • Godot Engine - nodes forms a hierarchy

Example: Scene Hierarchy

Input Devices

Input Manager

  • detects events from input devices
  • polling - compare against the previous state
  • callbacks - handled by an upper SW layer

Devices

  • keyboard, mouse, gamepad,...
  • one-axis controller - single analog state
  • two-axis controller - mouse and joystick
  • three-axis controller - g-senzor
  • four-axis controller - simulation joystick

What to consider

  • which input is active (e.g., pressed key)
  • for how long has been active
  • which input combination is active
  • how to map an input to an action in the game

Input Events

Atomic events

  • key press (keydown)
  • key release (keyup)
  • mouse movement (mouseover)

Compound events

  • click
  • fling
  • pinch to zoom
  • double tap

Complex events

  • sequences
  • chords

Complex events and mapping

Sequence

  • e.g., cheats: IDDQD, IDKFA

Chords

  • in combat games

Mapping

  • relationship between an event and an action in the game
  • dependent on the context, e.g., if the player
    drives a car, or walks on foot

Example: Godot Input Manager

1 class InputEvent : public Resource {
2
3 public:
4 static const int DEVICE_ID_TOUCH_MOUSE;
5 void set_device(int p_device);
6 int get_device() const;
7
8 bool is_action(const StringName &p_action, bool p_exact_match = false) const;
9 bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match) const;
10 bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
11 float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
12 float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
13 virtual bool is_pressed() const;
14
15 virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const;
16
17 virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; }
18 };

Scripting Engine

Scripts

Scripting in games

  • allows rapid prototyping
  • separates gameplay and engine core
  • used to be the only way
    to mod a closed game

Hexen (1995) - one of the first scripted games

Example: Hexen ACS Script

1 script 137 (int dir)
2 {
3 if(!dir)
4 {
5 Floor_LowerByValue(DoorTag, 16, 64)
6 Ceiling_RaiseByValue(DoorTag, 16, 64)
7 Delay(120);
8 Floor_RaiseByValue(DoorTag, 16, 64)
9 Ceiling_LowerByValue(DoorTag, 16, 64)
10 }
11 }

Example: Arma 2 SQS Script

1 // Creates boards and markers around mission Area
2 _xPos = position (_this select 0) select 0;
3 _yPos = position (_this select 0) select 1;
4
5 _howBigA = _this select 1;
6 _howBigB = _this select 2;
7 _tablesC = _this select 3;
8 _angle = _this select 4;
9 _i = 0;
10
11 while (_i < 360) do {
12 _x = (_howBighA * (sin _i));
13 _y = (_howBigB * (cos _i));
14 _x_rot = _xPos + _x*(cos _angle) - _y*(sin _angle);
15 _y_rot = _yPos + _x*(sin _angle) + _y*(cos _angle);
16 _k = createVehicle ["Danger", [_x_rot, _y_rot, 0], [], 0, "NONE"];
17 _m = createMarker [format ["Marker" + str _i], [_x_rot, _y_rot, 0]];
18 format ["Marker" + str _i] setMarkerType "Dot";
19 _k setDir _i;
20 format ["Marker" + str _i] setMarkerDir(_i - _angle);
21 _i = _i + 360/_tablesC;
22 };

Example: Godot GDScript

1 func _process(delta):
2 # Get ball position and pad rectangles
3 var ball_pos = get_node("ball").get_pos()
4 var left_rect = Rect2(get_node("left").get_pos() - pad_size*0.5, pad_size)
5 var right_rect = Rect2(get_node("right").get_pos() - pad_size*0.5, pad_size)
6
7 # Integrate new ball position
8 ball_pos += direction*ball_speed*delta
9
10 # Flip, change direction and increase speed when touching pads
11 if ((left_rect.has_point(ball_pos) and direction.x < 0)
12 or (right_rect.has_point(ball_pos) and direction.x > 0)):
13 direction.x = -direction.x
14 ball_speed *= 1.1
15 direction.y = randf()*2.0 - 1
16 direction = direction.normalized()
17 ...

Game Engine Scripting API

  • the engine needs to communicate with the script - provided by bridging
  • bridge is a performance bottleneck, especially for per-frame calls
  • more scripting languages = more bridges to maintain
  • Marshalling - transforming memory representation of an object between two domains (different programming languages)
  • Semantic gap - descriptive difference of an object in various representations (e.g. relational database vs object-oriented structure)
    • applies to visual scripting too

Example: Atomic Game Engine JS API

1 // Duktape JS mapping
2 static void jsb_class_define_FileSystem(JSVM* vm) {
3 duk_context* ctx = vm->GetJSContext();
4 js_class_get_constructor(ctx, "Atomic", "FileSystem");
5 js_class_get_prototype(ctx, "Atomic", "FileSystem");
6 duk_pop_2(ctx);
7 js_class_get_prototype(ctx, "Atomic", "FileSystem");
8 duk_push_c_function(ctx, jsb_class_FileSystem_SetCurrentDir, 1);
9 duk_put_prop_string(ctx, -2, "setCurrentDir");
10 duk_push_c_function(ctx, jsb_class_FileSystem_CreateDir, 1);
11 duk_put_prop_string(ctx, -2, "createDir");
12 ...
13 }
14
15 // CreateDir method
16 static int jsb_class_FileSystem_CreateDir(duk_context* ctx) {
17 String __arg0 = duk_to_string(ctx, 0);
18 duk_push_this(ctx);
19 FileSystem* native = js_to_class_instance<FileSystem>(ctx, -1, 0);
20 bool retValue = native->CreateDir(__arg0);
21 duk_push_boolean(ctx, retValue ? 1 : 0);
22 return 1;
23 }

Example: Atomic Game Engine C# API

  • mapping from C++ to C#
1 ATOMIC_EXPORT_API bool csb_Atomic_FileSystem_SetCurrentDir_4667(FileSystem* self, const char* pathName)
2 {
3 return self->SetCurrentDir(pathName ? String(pathName) : String::EMPTY);
4 }
5
6
7 ATOMIC_EXPORT_API bool csb_Atomic_FileSystem_CreateDir_4668(FileSystem* self, const char* pathName)
8 {
9 return self->CreateDir(pathName ? String(pathName) : String::EMPTY);
10 }
11
12
13 ATOMIC_EXPORT_API void csb_Atomic_FileSystem_SetExecuteConsoleCommands_4669(FileSystem* self, bool enable)
14 {
15 self->SetExecuteConsoleCommands(enable);
16 }

Lecture Summary

  • I know a thing or two about game engine history
  • I know the main parts of game engines
  • I know how game loop works
  • I know what scene graph is and what elements it contains
  • I know something about scripting engines

Goodbye Quote

When designers start taking inspiration from the same things, their games will start feeling the same.Reddit forum