Last active
July 17, 2018 13:55
-
-
Save andijcr/c7eb06092ae3ff460973f2e6c3428157 to your computer and use it in GitHub Desktop.
aperitalk scratchpad
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# chi sono | |
[contatti] | |
ciao sono andrea, lavoro qui a 2hire come sviluppatore embedded e smontacose. | |
Visto che chi non sa fare insegna, oggi voglio parlarvi di entity component system e perché penso sia veramente bello | |
e perché non l'ho mai usato | |
# survey | |
vedo un po' di facce conosciute. | |
quanti di voi sono programmatori puri? | |
quanti sono programmatori per necessità di videogioco? | |
quanti conoscono il pattern Entity Component system? | |
quanti usano un engine per i propri lavori? | |
# obiettivo | |
perché chiedo questo? | |
ecs è alla base di tantissimi prodotti in ambito videogiochi, e credo che conoscere un po' i meccanismi che fanno funzionare queste macchine, ci renda persone migliori e possa risolvere la fame nel mondo. | |
Per chi prima ha detto di essere un programmatore puro, che non usa engine per i suoi giochi, e che non conosce ecs, spero di riuscirvi a mostrare qualcosa di nuovo. | |
# antefatto [warning: fictonalization] | |
2 gamejam fà mi sono fatto convincere da Andrea a partecipare, a suon di parolacce | |
insieme a sarah, bruno, tsuneo e massimo ci eravamo dati appuntamento al pub per condividere un po' di idee e decidere quale tecnologia avremmo usato | |
io per l'occasione io avevo deciso finalmente di imparare love2d e ecs, ed ero molto deciso a condividerli con gli altri | |
Fu una bella sessione di brainstorming, si buttarono giù molte idee e avevamo anche una bozza di un possibile gameplay (lo so, non si fa) | |
# un problema [warning: informatica] | |
Problema: vogliamo modellare un sistema dove molteplici agenti interagiscono fra di loro contemporaneamente, e con un certo grado di autonomia | |
per esempio: in un videogioco abbiamo il personaggio di un giocatore, e dei nemici che si muovono a random | |
# proposta 1 | |
ecco come avrei affrontato io il problema, un po' di tempo fa | |
- è la mia prospettiva da programmatore che non vuole usare engine | |
modelliamo una classe player, nel suo metodo update leggiamo gli input per muoverlo. modelliamo una classe npc, e nel suo metodo lo facciamo muovere a random | |
# aggiunta | |
se il giocatore tocca un nemico, perde | |
# proposta 1.1 | |
nel loop del gioco facciamo if(player touches enemy) die() | |
# aggiunta | |
i nemici non si muovono a random, ma vanno verso il giocatore | |
# proposta 1.2 | |
la classe npc riceve il giocatore, ad ogni update si muove verso la sua posizione | |
^ pessimo design | |
# aggiunta | |
quando il giocatore attiva la sua arma, i nemici dietro di lui esplodono | |
# proposta 1.3 | |
nel loop del gioco mettiamo un if(x is pressed){for( e in enemies){if(e is behind player) die(e)}} | |
# cosa abbiamo finora | |
come potete immaginare questo è un design che diventa sempre più ingarbugliato, con logica sparsa un po' ovunque, oggetti che non si sa a chi appartengono, bug che compaiono in maniera imbarazzante. | |
Quale è il problema? aggiungere un comportamento diventa sempre più difficile, i dati sono inutilmente ridondanti. | |
questo design va bene quando abbiamo un solo giocatore, 2/3 nemici, ed un tutorial per qualche engine js/html5, ma possiamo allargare il nostro mondo solo spendendo molte bestemmie | |
# il problema | |
il problema di fondo del design di prima è che un comportamento (muoversi verso un obiettivo, esplodere) è mezzo mischiato con i dati su cui opera (la propria posizione, l'obiettivo, un evento) e questi piccoli pezzi di codice sono replicati un po' di volte. | |
# ecs | |
(non ho controllato wikipedia, garantito sto dicendo delle cazzate) | |
ecs dice: | |
il mondo è popolato da esseri, che si chiamano entità. essi hanno una identità e poco più. | |
nel mondo ci stanno anche leggi, chiamate sistemi, che governano come le entità si evolvono da un istante di tempo all'altro. | |
ad esempio: un sistema dice che se ho un obiettivo, devo "spostarmi verso di esso", | |
un'altra dice che "spostarmi" significa modificare la mia "posizione" con un vettore, | |
una terza dice che se c'è una esplosione vicino a me, allora vengo distrutto | |
# ecs -cont | |
i Sistemi interagiscono con le entità? No! ogni sistema interagisce con il suo tipo di dato, che è chiamato Componente. | |
Dove stanno questi Componenti? ogni Entità è un contenitore di tutti i Componenti che ne devono determinare il comportamento | |
In pratica cerchiamo di disaccoppiare completamente i dati dal codice, ed eliminiamo le dipendenze fra i vari pezzi di codice | |
# esempio | |
Modelliamo il nostro gioco con Entità{posizione, grafica, vita, input, nome="player"}, e tanti nemici modellati come Entità{posizione, obiettivo, grafica, nome="npc..."} | |
dove posizione, grafica, vita, input, obiettivo sono i nostri Componenti | |
poi creiamo un Sistema<posizione, input> che modifica la posizione a seconda dell'input, per permettere all'utente di controllare Qualcosa | |
un Sistema<posizione, obiettivo> che avvicina la posizione all'obiettivo, per far muovere Qualcosa | |
questi sono sistemi semplici, delle funzioni, che fanno evolvere le entità singolarmente | |
# esempio 2 | |
e per modellare le interazioni fra entità? | |
una soluzione (una delle tante) è avere un sistema per verificare se una interazione sta avvenendo, e se si creare al volo una entità che descrive questa interazione. Sui componenti di questa nuova Entità "evento" possiamo triggerare tutti i sistemi che ci pare. | |
per esempio: potremmo avere un Sistema<posizione, collidibile> che verifica quali entità collidono e genera una Entità{collisione, entità_a, entità_b} per ogni nuova collisione, un Sistema<collisione> che cambia il colore delle entità che collidono, un Sistema<collisione> che azzera la vita delle entità, un Sistema<vita> che uccide l'entità con vita zero, e un Sistema<collisione> che distrugge l'entità "evento", in modo da consumare gli eventi ad ogni turno | |
# sembra complicato? | |
si, è un po' complicato. sopratutto perché l'istinto naturale del "prima programma e poi chiedi scusa" qui viene sovvertito: prima di programmare c'è del lavoro da fare per individuare entità, componenti e sistemi, e cercare di evitare l'errore di nascondere dati dentro i sistemi, e comportamenti dentro le entità | |
# ma il mondo stesso è complicato | |
in realtà però il problema di architettura, il problema di spendere del tempo a sistemare il codice, è un problema che ad un certo punto qualsiasi progetto deve affrontare. | |
Chi ha già avuto un progetto personale, ad uno stato medio/avanzato sà quanto è doloroso il debito tecnico di copiare e incollare il codice in giro | |
# cosa non sto dicendo | |
ecs, come lo ho illustrato qui, è un meccanismo a basso livello per organizzare lo sviluppo, ma non è ancora chiaro come farlo funzionare nella pratica. | |
un approccio (semplicistico e poco ottimale) è: | |
nel setup, creo le Entità con i loro Componenti, e li salvo in una lista master. | |
nel loop, per ogni Sistema itero la lista, ed eseguo il sistema sulla entità se questa soddisfa il suo filtro (per esempio il Sistema<posizione, texture> si attiva solo per le entità con questi due componenti, e disegna a schermo una texture alla posizione indicata) | |
ovviamente c'è un discorso dell'ordine con cui attivo i sistemi, e un possibile ordinamento delle entità, che sto accuratamente evitando. | |
# un approccio più sensato | |
usate un motore di entity component system che vi renda la vita semplice. | |
La mia esperiza è limitata, ho provato love2d in congiunzione con tiny. | |
per chi non lo conoscesse love2d è un motore molto minimale che si programma in Lua, impone pochissime restrizioni ed ha delle performance ottime per videogiochi 2d | |
tiny-ecs invece è una piccola libreria http://bakpakin.github.io/tiny-ecs/doc/ per ecs con delle feature che considero essenziali per chi si vuole divertire ad usare questo pattern manualmente: | |
(premessa: in lua esiste solo la table, che è un mix fra dizionario e oggetto, con capacità avanzate) | |
le entità sono delle semplici table, e i componenti sono valori all'interno di questa table con un loro nome | |
i sistemi sono delle tabelle con ua interfaccia semplice, e tiny include delle utility per scrivere i filtri con cui i sistemi selezionano le entità a cui sono interessati | |
l'ordine con cui i sistemi sono aggiunti al motore serve ad indicare l'ordine con cui vengono eseguiti - per esempio, i system responsabili per eliminare entità devono essere aggiunti alla fine dello stack, per fare cleanup ad ogni update | |
infine, per far girare il tutto basta chiamare update(dt) ad ogni frame | |
molto semplice, poco minaccioso | |
# chi altro usa ecs | |
ecs come abbiamo visto può essere molto macchinoso da setuppare (scusate il verbo), e penso che sia per questo un paio di anni fa non trovai molte librerie open che fossero mantenute, utilizzabili e non antagoniste. | |
i motori come love2d o processing, che sono nati per creative coding sono diretti ad una audience che probabilmente si avvicina alla programmazione, e ha già troppo a cui pensare | |
mentre i motori veri e propri, come unity o i vari js+html5 sono diretti ad un pubblico che è più interessato a creare contenuti, piuttosto che addentrarsi dentro questi dettagli architetturali (a ragione, penso) | |
Però è innegabile che molti progetti "complessi" usano una qualche forma di ecs, più o meno esposta all'utente. | |
Tra l'altro sospetto (non ho aperto il codice) che box2d sia scritto con la tecnica ecs, per cui chiunque ha usato questo motore fisico può dire di aver toccato almeno una volta ecs. | |
# svantaggi | |
cambio di prospettiva, bisogna imparare a distinguere dati da comportamenti | |
una certa quantità di boilerplate code (se non si usa una libreria o questa libreria è antagonista) | |
alcuni concetti possono essere difficili da tradurre in un mondo ecs, ma di solito è possibile creare soluzioni "ibride" (ma attenzione a non cadere nello spaghetti code) | |
non adatto a tutti i tipi di videogiochi | |
non adatto a molto altro, al di fuori del mondo dei videogiochi e delle simulazioni | |
# perché è figo | |
performace possono migliorare, con una opportuna implementazione (data driven programming credo si chiami?) | |
mix and match: voglio permetter ad un utente di controllare un vaso di gerani? basta aggiungere il componente isPlayer all'entità del vaso, ed ecco che il sistema input comanderà il vado | |
salvataggio: quanto tutto il tuo stato è contenuto nelle entità, e il gioco è deterministico, basta serializzare la lista delle entità per salvare il gioco | |
è un approccio "scalabile" | |
è bello anche scoprire il trucco dietro le magie dei modori di videogiochi | |
# riferimenti | |
massimo il bidello dell'arci ragazzi, per avermi messo la pulce nell'orecchio anni fa con il suo ecs | |
vittorio romero che ha creato un framework per fare ecs in c++ a tempo di compilazione, molto figo | |
sara bruno andrea e tsuneo che mi hanno coinvolto in quella gamejam | |
alla fine non usammo nè love2d nè ecs, ma facemmo un gioco in processing di due rane che saltano, e fu molto figo | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment