FIT ČVUT

Adam Vesecký

NI-APH
Přednáška 4

Komponenty

Herní model

Herní model

  • všechna herní pravidla jsou součástí herního modelu
  • herní model je možno rozdělit do několika částí: doménový model, view model, networking model,...
  • herní model aktualizuje svůj stav a interpretuje jej ostatním částem aplikace
  • s každým updatem dojde k vykreslení interpretace stavu modelu na obrazovce

Herní model

Doménový Model

  • obsahuje pravidla a klíčová herní data

Presentační Model

  • to, co vnímá hráč
  • např. přehrávané zvuky, animované sprity

Fyzikální model

  • všechny entity, které se podílí na fyzikální interakci

AI model

  • všechna data a struktury, které může zpracovávat AI (navmesh, behaviorální stromy,...)

Networking model

  • vše, co je potřeba synchronizovat mezi zařízeními

Příklad: Super Mario Bros.

Herní model

  • komplexní systém je možno přesně modelovat pouze modelem, který je totožný s oním systémem
  • jednoduchý doménový model najdeme u her, které se dají modelovat jako stavový automat (např. u turn-based her, puzzle her a adventur)
  • u komplexních her jako GTA dává smysl vytvářet doménový model pouze pro základní mechaniky

Příklad: Šachy

Chessmaster 2000 (1986)

Chessmaster 11 (2007)

Šachový model

  • obsahuje jak atributy tak herní pravidla (v metodě makeMove())

Šachové modely

Chessmaster 2000Chessmaster 11
Doménový modelHerní deska, figurky, čas, pravidlaHerní deska, figurky, čas, pravidla
Presentační modelCGA sprity, beeper zvukyAnimované 3D objekty, zvuky, hudba
Fyzikální modelNeníRigidbody engine
AI modelEngine Davida KittingeraKing engine
Networking modelNeníPosílání tahů

Příklad: Strategie

Heroes of Might and Magic

Heroes of Might and Magic model

  • jsou zde pouze atributy

Příklad: Textová adventura

Příklad: Textová adventura

  • jsou zde jak atributy tak pravidla

Příklad: Pacman

Pacman - architektura

  • jsou zde pouze atributy

Objektová architektura

Příklad: Platformer

Hierarchie pro doménový model

Problém č.1: Zapracování fyziky

Další problémy

  • drak může mít možnost používat manu
    • možnost a) přepracovat hierarchii
    • možnost b) přesunout manu do rodičovské třídy
  • mág může mít schopnost transformace do draka
    • možnost a) vytvořit nový objekt DragonMage
    • možnost b) přidat referenci na objekt, do kterého se mág bude transformovat
  • orc může mít možnost použít range (např. luk/kuš)
    • přidat více stavů
  • mág může mít inventář, který ovlivňuje jeho schopnosti
  • můžeme chtít přidat další funkce během vývoje
Ne všechny závislosti jdou popsat pomocí orientovaného souvislého grafu

All-in-one pattern

  • používaný v 90. letech
  • jedna třída vládne všem
  • obrovské množství switchů a if-checků

Příklad: Doom 2

Objektová architektura: shrnutí

  • přirozený způsob zápisu hierarchie objektů
  • funguje dobře pro jednoduché hry s malým modelem
  • u komplexnějších her můžeme skončit se stovkami závislostí
  • dědičnost není dostatečná pro modelování závislostí
  • je potřeba použít kompozici, a to je doménou komponentové architektury

Shrnutí

  • jednoduché
  • rychlé prototypování
  • jednoduše se debugguje
  • hůře se škáluje
  • není flexibilní
  • objekty mohou mít vlastnosti, které nepotřebují

Komponentová architektura

Komponenta

  • modulární část systému, jejíž chování je definováno z hlediska přijímaných a poskytnutých rozhraní
  • komponenty jsou plug-and-play objekty
  • upřednostňuje kompozici před dědičností a DOP (Data-Oriented Programming)
  • chování objektu je stanoveno tím, jaké obsahuje komponenty
  • Dungeon Siege (2002) - jedna z prvních her s komponentovou architekturou

ECS Pattern

  • Entity-Component-System (+ Attribute)
  • oblíbená architektura pro komponentové knihovny a enginy
  • herní objekt je pouze kontejner pro data a logiku, kterou mu dodají přiřazené komponenty
  • jednoduše se dá integrovat do grafu scény

Terminologie

Entity

  • herní objekt

Component

  • jednotka poskytující funkční chování (a někdy i data)

System

  • samostatná komponenta, co zodpovídá za větší celek (HealthSystem, StatsSystem, ScoreSystem)

Attribute

  • jednotka poskytující hernímu objektu data
  • většina enginů používá datové komponenty
Pojmenování se může lišit. Některé enginy používají Behaviours pro komponenty, Components pro systémy, Properties pro atributy atd.

Příklad: Platformer

  • atributy jsou DATA, komponenty jsou CHOVÁNÍ

ECS Architektura v C++

ECS příklad

Největší dilema v komponentové architektuře

Jak vhodně rozdělit zodpovědnosti?

Příklad: Pacman

Pacman

Root

  • kořenový herní objekt

Maze

  • model bludiště, obsahuje pozice teček, boosterů atd.

GameSystem

  • kontroluje hru jako jeden celek (např. přepíná herní stavy, určuje ukončovací podmínku - game over)

BoxBehavior

  • herní logika ohrádky (náhodně vytváří duchy)

PacmanBehavior

  • kontroluje pohyb Pacmana pomocí InputManager komponenty

GhostBehavior

  • jednoduché AI pro "chase" behavior

Příklad: Platformer

Komponentová architektura - shrnutí

  • škálovatelná
  • datově-orientovatelná
  • komponenty je snadné použít na více místech
  • jednoduché vytváření nových typů objektů
  • komponenty mohou mít polymorfní operace
  • vše je poskládáno v runtime
  • statická analýza kódu neodhalí potenciální překážky
  • kód je potřeba psát generickým způsobem
  • refaktoring může být problematický
  • hůře se debugguje

Messaging

Jak komponenty komunikují

Modifikací stavu herního objektu

  • např. sdílený stavový automat
  • nepřímá komunikace
  • špatně se debugguje

Přímým voláním

  • rychlé, ale zvyšuje zadrátovanost
  • musíme vědět, koho volat
  • volání typu getComponentByName().sth()

Pomocí message brokeru

  • eventy a commandy
  • každá komponenta deklaruje, které typy zpráv ji zajímají
  • např. jakmile dostaneme zprávu ITEM_PICK, přehrajeme zvuk

Message Broker

  • umožňuje komponentám, aby byly notifikovány o změně stavu, která je pro ně relevantní
  • může být použit i pro návrat hodnot (nebezpečí feedback deadlocku)
  • komponenty obvykle obsahují metodu jako OnMessage(), která zprávy zachytává
  • nabízí se možnost i asynchronního (odloženého) zpracování
  • Event - zpráva, která informuje, že se něco stalo
  • Command - příkaz, který instruuje, že se něco má provést

Typy zpráv

Unicast

  • komponenta pošle zprávu jiné komponentě (jen jedné)
  • ve většině případů stačí přímé volání
  • příklad: pauznutí hry

Multicast

  • a) komponenta pošle zprávu všem subscriberům
  • b) komponenta pošle zprávu všem objektům, které splňují určitá kritéria
  • příklad: notifikace jednotek v osadě, že hráč vychází z lesa
  • příklad: hráč šlápl do kaluže - přehrání zvuku

Broadcast

  • globální zprávy, příliš se nevyužívá
  • příklad: game over, případně debuggovací/loggovací komponenta

Příklad: Unity Messages

1 public interface ICustomMessageTarget : IEventSystemHandler
2 {
3 // functions that can be called via the messaging system
4 void Message1();
5 void Message2();
6 }
7
8 public class CustomMessageTarget : MonoBehaviour, ICustomMessageTarget
9 {
10 public void Message1()
11 {
12 // handle message
13 }
14
15 public void Message2()
16 {
17 // handle message
18 }
19 }
20
21 // sending message
22 ExecuteEvents.Execute<ICustomMessageTarget>(target, null, (x,y) => x.Message1());

Příklad: Unreal Message Bus

  • umožňuje komunikaci mezi částmi aplikace pomocí techniky Message Passing
  • zprávy jsou rozdělené do commandů a eventů
  • všechny zprávy jsou zabalené do rozhraní IMessageContext

Message Broker - shrnutí

  • umožňuje komunikaci posíláním zpráv a příkazů
  • komponenty mohou reagovat na jakoukoliv zprávu, která přijde do brokera
  • není příliš vhodné pro per-frame zpracování (už vůbec ne pro dynamiku či závislý pohyb objektů)
  • pokud komponenta reaguje na příliš mnoho zpráv, není jednoduché ji refaktorovat a rozdělit na více komponent
  • pokud je nutné posílat konkrétní zprávu každý frame, je lepší použít přímé volání

Komponentové enginy a knihovny

Komponentové enginy a knihovny

Artemis framework

Atomic Game Engine

Unity

  • ECS architektura

Unreal Engine

  • hybridní objekto-komponentová architektura

Godot Engine

  • node-based OOP architektura, signály

Příklad: Artemis Engine

  • System obsahuje logiku, komponenty obsahují data
1 // new component
2 public class Health extends Component {
3 public int health;
4 public int damage;
5 }
6
7 // new archetype
8 Archetype dragonArchetype =
9 new ArchetypeBuilder()
10 .add(Flaming.class).add(Health.class).build(world);
11
12 public class MovementSystem extends EntityProcessingSystem {
13 public MovementSystem() { super(Aspect.all(Position.class, Velocity.class)); }
14 }
15
16 // create new transmuter
17 this.transmuter = new EntityTransmuterFactory(world)
18 .add(FrozenFlame.class).remove(Flaming.class).build();
19
20 // apply transformation to entity
21 this.transmuter.transmute(entity);

Unity

  • DOTS architektura (Data-Oriented Technology Stack), nadstavba ECS
  • entity jsou herní objekty, komponenty obsahují data, systémy obsahují herní logiku
  • třída MonoBehaviour může obsahovat jak data, tak i herní logiku

Unity Architektura

Příklad: Platformer2D

Příklad: Platformer2D Graf scény

Příklad: Platformer2D Events

1 // RocketComponent
2 void OnTriggerEnter2D (Collider2D col) {
3 // If it hits an enemy...
4 if(col.tag == "Enemy") {
5 // ... find the Enemy script and call the Hurt function.
6 col.gameObject.GetComponent<Enemy>().Hurt();
7 // Call the explosion instantiation.
8 OnExplode();
9 // Destroy the rocket.
10 Destroy (gameObject);
11 }
12 // Otherwise if it hits a bomb crate...
13 else if(col.tag == "BombPickup") {
14 // ... find the Bomb script and call the Explode function.
15 col.gameObject.GetComponent<Bomb>().Explode();
16
17 // Destroy the bomb crate.
18 Destroy (col.transform.root.gameObject);
19
20 // Destroy the rocket.
21 Destroy (gameObject);
22 }
23 }

Komponentové knihovny

EnTT

Entitas

A-Frame

ECSY

Příklad: ECSY Framework

1 var world = new World();
2 world
3 .registerSystem(MoveSystem)
4 .registerSystem(RendererSystem);
5
6 class MoveSystem extends System {
7 execute(delta, time) {
8 this.queries.moving.results.forEach(entity => {
9 let pos = entity.getMutableComponent(Position);
10 pos.x += entity.getComponent(Velocity).x;
11 });
12 }
13 }

Co jsme si řekli

  • Co je to herní model a z čeho se skládá
  • S jakými problémy se potýká objektová architektura ve hrách
  • Co je to komponenta
  • Jak funguje ECS pattern
  • Jak funguje messaging u komponentové architektury

Hláška na závěr

Ve všech strategiích je nejdůležitější Primalex - kdy vám voják s kýblem barvy přebarví budovy na vaší frakci, a ten nepřítel pak do nich nemůže vlézt.Recenzenti ze Score