Adesso che non-binary sta camminando sulle sue zampette e noi ci stiamo riposando (no, non è vero, ma lasciateci l’illusione), vorremmo condividere con voi qualche riflessione, darvi uno sguardo su cosa è significato costruire questo gioco sotto i suoi vari aspetti. Partiremo dal livello più basso, quello tecnico. Qui parla LazyFox, e vi racconterò un po’ di scelte e conclusioni raggiunte nello sviluppo con Unity.
ATTENZIONE: ci saranno alcuni vaghi spoiler in questa spiegazione. Se non avete ancora giocato, prendetevi una mezz’ora di tempo e lanciatevi!
Architettura
Ho deciso di approcciare lo sviluppo seguendo un’architettura a eventi basata su ScriptableObject, come già fatto per Le Andande (puoi trovare il devlog qui). Ci sono state varie nuove lezioni imparate, e alcune di queste saranno per me delle best practices:
- Il plugin Asset Usage Detector è ottimo per tracciare quali oggetti, in scena e fuori, vengono influenzati da quali eventi.
- L’inizializzazione delle variabili create con Unity Atoms deve sempre avvenire con un valore fisso: se dev’essere invece inizializzata da un manager è meglio riservare un valore “speciale”.
- Quando un evento è di modifica, impostare a 1 il replay per ricevere sempre il valore della variabile quando un listener si aggancia, altrimenti impostarlo sempre a 0. Ignora questo suggerimento a rischio di bug molto, molto tricky da trovare (ouch!)
L’utilizzo di Unity Atoms non elimina la necessità di manager, a volte esprimibili come ScriptableObject, altre volte come MonoBehaviour. Ricordatevi di avere una reference dei vostri manager in tutte le scene, specie se sono ScriptableObject! Una tecnica interessante è quella spiegata da Tarodev (scoperta dopo aver finito il progetto, e nonostante questo molto simile).
Influenzatɜ sia da Unity Atoms che dal background di sviluppo su React, la struttura principale del progetto è insolita rispetto a quella spesso consigliata, e separa gli asset in componenti. Ogni componente è un oggetto autocontenuto che ha al suo interno script, animazioni, sprite, e tutto il resto necessario per il suo funzionamento, mentre i componenti parlano tra di loro attraverso gli eventi di Unity Atoms.
Grafica
Per poter creare il colpo di scena che si trova alla fine del gioco ci siamo dovutɜ giostrare nella creazione di un progetto 3d che per la quasi totalità del tempo è in realtà 2d, subendo così le complessità del primo senza nessun vantaggio del secondo. Che fortuna! In pratica abbiamo dovuto rispolverare le vecchie tecniche di z-ordering degli elementi 2d per gestire le sovrapposizioni, mentre tutta la parte di collisioni e bullet hell sono gestite in 3d con un lock degli assi di movimento per impedire lo spostamento sull’asse della profondità.
Un altro aspetto che abbiamo indagato è stato quello degli shader: è stato davvero divertente sperimentare le varie personalizzazioni possibili su Pallinə! È stata una palestra di algebra, scoperte su Shader Graph, e pura creatività, che pure quella va lasciata libera ogni tanto. Fun little fact: non esiste alcuno sprite per la strada, è tutta calcolata via shader. Era necessario? Ovviamente no. Era divertente farlo così? Ovviamente sì!
Strumenti
Lo strumento che abbiamo più utilizzato per la gestione di questo progetto è stato Ink, che ha permesso una comunicazione facile tra la parte di programmazione e di creazione dei testi. L’idea è stata quella di utilizzare i file di Ink come driver di tutti gli eventi in gioco, e fornirgli attraverso funzioni, tag e marker gli strumenti per farlo, seguendo un approccio quindi simile a quello di Yarn Spinner. Nei prossimi giochi abbiamo tutte le intenzioni di potenziare di più questo approccio.
L’altro strumento di cui abbiamo abusato è la Timeline di Unity, per gestire varie parti dell’animazione. Una delle sfide è stata quella di interfacciare Unity Atoms con la Timeline, considerando che le variabili di Atoms non sono delle proprietà animabili, e che i Signal non sono degli eventi. La soluzione che abbiamo trovato è stata quella di dedicare un oggetto a ogni animazione, impostare degli script su quell’oggetto che facessero da ponte tra le proprietà serializzate e gli Atoms, e viceversa di scatenare eventi in reazione ai Signal della Timeline (che a tutti gli effetti svolgono la stessa identica funzione). Dopo averci preso la mano si è rivelato un approccio molto duttile ed efficace!
E adesso?
Cosa farne di questi discorsi? Uno degli obiettivi di owof è quello di condividere per crescere tuttɜ assieme. Quindi: se avete voglia di ragionare su altri aspetti assieme o elementi più nel dettaglio, siamo qui a zampette aperte. E tra qualche settimana condivideremo qualcosa che speriamo vi faccia felici.
Settimana prossima invece QueerWolf condividerà qualche riflessione sul narrative design.
Paws up!
owof