FIT ČVUT

Adam Vesecký

NI-APH
Přednáška 2

Enginy

Historie herních enginů

Pre-engine období

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

Příklad: Vlak (1993)

1 ; ------ priprava pro dalsi objekt
2 PosVlak6:add si,3 ; adresa dalsiho objektu
3 mov dx,cx ; stará pozice predesleho objektu
4 mov al,0
5 cmp ds:[si],al ; je jiz konec vlaku?
6 je PosVlak7
7 jmp PosVlak2 ; neni konec - dalsi vagon
8
9 ; ------ vymazani posledniho vagonu
10 PosVlak7:cmp dl,-1
11 je PosVlak8
12 call DispObr ; vymazani posledniho vagonu
13 mov al,20 ; pocet pozic
14 mul dh ; prepocet radku na offset
15 add al,dl
16 adc ah,0
17 add ax,offset Pole
18 xchg ax,di ; DI <- adresa v poli
19 mov byte ptr ds:[di],0

Zdrojový kód pro MS-DOS: odkaz

ID Tech

  • rodina herních enginů vyvinutá firmou ID Software
  • Id Tech 0 - první plnohodnotný herní engine
  • každá další hra měla pokročilejší technologii
  • až do roku 1996 byly všechny hry postavené na raycastingu
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 ...

Zdrojový kód: odkaz

Další pseudo-3D enginy

Voxel Space Engine
1992
Jedi Engine
1995
Build Engine
1996

Quake Engine

  • ~id Tech 2
  • vyvinut ID Software v roce 1996
  • nastartoval příchod 3D her
  • 3D real-time rendering, 3D světla
  • Id Tech 1 hry:
    • Quake, Hexen 2, Silver Wings
  • Další hry postavené na IdTech:
    • Call of Duty
    • Medal of Honor
    • Daikatana
    • Half-Life (forknutý Source Engine)
  • Následníci:
    • id Tech 3, 4, 5, 6, 7

Quake (zdrojový kód zde)

Rodina Quake enginů

Vliv herních enginů

Herní enginy - přehled

Herní enginy dneška

Trendy - 2014

Trendy - 2022

Unreal Engine

Unreal Engine 1

  • vytvořen v roce 1998 firmou Epic Games jako FPS engine
  • Unreal - první hra

Unreal Engine 4

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

Unreal Engine 5.3

  • Nanite virtualized geometry
  • Lumen illumination engine
  • zdrojový kód je dostupný

Unreal hry

Batman Arkham Knight

Star Wars Jedi: Fallen Order

Hellblade: Senua's Sacrifice

Borderlands

Fortnite

Planet Alpha

Unity

  • all-in-one (a nejen) herní engine
  • vznikl v roce 2005
  • podporuje všechny hlavní platformy
  • nejběžnější engine indie vývojářů
  • zdrojový kód dostupný pouze enterprise uživatelům

Unity 2023.3 - současná verze

  • UVS - vizuální jazyk (dříve Bolt)
  • Universal Render Pipeline
  • Split Graphics Jobs
  • nový multiplayer engine
  • ECS komponentový engine

Ori

Besiege

Cuphead

Godot

  • 2D a 3D engine
  • GDScript skriptovací jazyk
  • používá OOP architekturu
  • MIT licence
  • zatím žádné známé hry

Jaký engine potřebuji?

  • 2D minihry s jednoduchými animacemi se dají vytvářet bez enginu
  • na některé typy her stačí grafické knihovny (ThreeJS, PixiJS, BabylonJS)
  • Unity je hlavní volbou pro 2D a 3D indie hry, ale neumožňuje low-level customizaci
  • Unreal má pozvolnou učící křivku, customizace je flexibilnější
  • open-source enginy obvykle stojí na pár lidech a jejich osud je nejistý
  • migrace mezi enginy je prakticky nemožná

Architektura herních enginů

Primární moduly

  • Game Loop - herní smyčka, zajišťuje real-time interakci
  • Scene Manager - udržuje objekty a jejich závislosti ve stromové struktuře
  • Input Manager - obstarává vstupy
  • Resource Manager - obstarává assety, cache a loading
  • Memory Manager - spravuje paměť (obvykle předalokovanou heapu)
  • Rigidbody Engine - mechanika tuhých těles (detekce kolizí)
  • Physics Engine - ovládá objekty na základě silového působení
  • Rendering Engine - zajišťuje vykreslování
  • Animation Engine - přehrává a načítá animace
  • Scripting Engine - sémantický můstek mezi jádrem enginu a dalšími jazyky (JS, C#,...)
  • Audio Engine - přehrává hudbu, klipy, zvuky,...
  • AI Engine - abstraktní vrstva pro AI (stavové automaty, behaviorální stromy,...)
  • Networking Engine - multiplayer
  • Další moduly - GUI framework, Level Editor, Camera, Event System, LOD system,...

Herní smyčka

Herní smyčka

  • nejdůležitější část většiny her
  • každý frame aktualizuje herní model
  • obvykle spojená s event smyčkou platformy
  • optimální frekvence her: 60 FPS = 16.6 ms na frame
  • vstupy a fyzika vyžadují častější update
Program obecně stráví 90% času v 10% kódu. Herní smyčka je zcela jistě v těch 10%.

Jednoduchá smyčka

Smyčka s odděleným renderingem

Kooperativní smyčka

  • poprvé použita ve hře Ultima VII (1994)

Update herního stavu

Fixní time step

  • každý update je proveden o fixní časovou jednotku
  • deterministické a stabilní
  • může zpomalit hru

Variabilní time step

  • každý update je proveden o jednotku závislou na skutečném čase
  • přirozené
  • nedeterministické a nestabilní

Adaptivní time step

  • variabilní smyčka s thresholdingem
  • dokáže se vypořádat se zamrznutím hry

Příklad: Unity

Graf scény

Graf scény

Graf scény

  • základní struktura jakékoliv grafické aplikace
  • způsob řazení dat do hierarchie
  • reprezentován jako N-ární strom nebo graf
  • implementován jako pole, oct-tree, quad-tree, bounding volume hierarchy,...
  • transformace objektů má vliv na všechny objekty pod nimi
  • listy reprezentují atomické objekty (polygony, vertexy,...)

Manažer scény

  • v některých enginech - přidává ke grafu scény logickou nadstavbu
  • hlavní funkce: komunikace a přenos událostí mezi objekty
  • Unity Engine - hierarchie tvořená herními objekty
  • Unreal Engine - hierarchie tvořená komponentami
  • Godot Engine - hierarchie tvořená uzly

Příklad: Graf scény

Vstupní zařízení

Input Manager

  • detekuje události od vstupních zařízení
  • polling - aktivní dotazování a porovnání s předchozím stavem
  • callbacky - ošetřeno softwarovou vrstvou

Zařízení

  • klávesnice, myš, gamepad, kamera,...
  • jednoosý ovladač - analogová páka
  • dvouosý ovladač - myš a joystick
  • tříosý ovladač - g-senzor
  • čtyřosý ovladač - simulační joystick

Co brát v potaz

  • jaký vstup je aktivní (např. stisknutá klávesa)
  • jak dlouho je aktivní
  • jaká kombinace vstupů je aktivní
  • jak mapovat vstup na výslednou akci ve hře

Input Events

Atomické události

  • stisk klávesy (keydown)
  • uvolnění klávesy (keyup)
  • pohyb myší (mouseover)

Složené události

  • click
  • fling
  • pinch to zoom
  • double tap

Komplexní dálosti

  • sekvence
  • kombo

Komplexní události a mapování

Sekvence

  • např. cheaty: IDDQD, IDKFA

Kombo

  • v bojových hrách

Mapování

  • vztah mezi událostí a výslednou akcí ve hře
  • závislé na kontextu, např. zda hráč řídí
    auto, jde po svých nebo letí helikoptérou

Příklad: 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 };

Skriptovací engine

Skripty

Skripty ve hrách

  • umožňují rapidní prototypování
  • oddělují gameplay a jádro enginu
  • dříve jediný způsob, jak
    modifikovat uzavřenou hru

Hexen (1995) - jedna z prvních skriptovaných her

Příklad: 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 }

Příklad: 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 };

Příklad: 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 Skriptovací API

  • engine musí komunikovat se skriptem - řeší se bridgingem
  • bridge je výkonnostní bottleneck, především pro per-frame operace
  • více skriptovacích jazyků = více práce na údržbu
  • Marshalling - transformace paměťové reprezentace objektu mezi doménami (např. různými jazyky)
  • Sémantická mezera - rozdíl v deklaraci objektu v různých doménách (např. relační databáze a OO struktura)
    • platí i pro vizuální skriptování

Příklad: 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 }

Příklad: Atomic Game Engine C# API

  • mapování z C++ do 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 }

Co jsme si řekli

  • Něco málo o historii enginů
  • Hlavní části herních enginů
  • Jak funguje herní smyčka
  • K čemu je graf scény
  • Použití skriptovacích jazyků v enginech

Hláška na závěr

Jakmile se designéři začnou inspirovat stejnými věcmi, jejich hry začnou vypadat stejně.Reddit fórum