Università degli Studi di Padova Dipartimento di Matematica "Tullio Levi-Civita" Corso di Laurea in Informatica

Il flusso di sviluppo di un videogame: risoluzione di bug per Milestone ed

Tesi di laurea

Relatore Prof. Davide Bresolin

Laureando Riccardo Damiani

Anno Accademico 2018-2019 Riccardo Damiani: Il flusso di sviluppo di un videogame: risoluzione di bug per Milestone ed Unreal Engine, Tesi di laurea, c Dicembre 2019. È sapiente solo chi sa di non sapere, non chi s’illude di sapere e ignora così perfino la sua stessa ignoranza. — Socrate

Sommario

Il presente documento descrive il lavoro svolto durante il periodo di stage, della durata di circa trecentoventi ore, presso l’azienda Milestone Srl con sede a Milano. Lo scopo dello stage è stato apprendere le metodologie di sviluppo software nell’ambito gaming. Particolare attenzione è stata posta sui processi, gli strumenti ed il way of working dell’azienda ospitante. Tra gli strumenti più rilevanti per un programmatore all’interno dell’azienda ci sono senz’altro il motore di gioco Unreal Engine 4, che oltre a fare da ossatura ai vari giochi permette anche lo sviluppo multi-platform, il sistema di versionamento Helix ed il sistema di project management JIRA.

0.1 Organizzazione del testo

Il primo capitolo descrive brevemente l’industria dei videogiochi, dalla sua nascita ai giorni d’oggi, e l’azienda che mi sta ospitando come stagista. Il secondo capitolo tratta il workflow di una software house di videogames, con riferimento all’azienda ospitante. Il terzo capitolo introduce il utilizzato da Milestone, Unreal Engine 4, da un punto di vista della programmazione C++. Il quarto capitolo approfondisce ulteriormente Unreal Engine 4, ma da un punto di vista del sistema dei Blueprint. Il quinto capitolo descrive i tools utilizzati all’interno dell’azienda per il supporto allo sviluppo, ed i framework con cui vengono strutturati i diversi giochi di casa Milestone. Il sesto capitolo tratta della mia esperienza iniziale di risoluzione bug, che mi è stata utile per fare i primi passi all’interno del mondo di Unreal e del game development, e per inserirmi in azienda nel team di Moto GP.

v

Ringraziamenti

Le prime persone a cui devo dire grazie per questo traguardo sono i miei genitori, fonte di sostegno e di coraggio, che mi hanno trasmesso la passione per lo studio e la voglia di raggiungere questo traguardo senza arrendermi di fronte alle difficoltà. Vorrei inoltre ringraziare il Prof. Davide Bresolin, relatore della mia tesi, per l’aiuto e il sostegno fornitomi durante la stesura del lavoro.

Padova, Dicembre 2019 Riccardo Damiani

vii

Indice

0.1 Organizzazione del testo ...... v

1 L’Industria Videoludica1 1.1 Introduzione ...... 1 1.2 I Diversi Ruoli ...... 1 1.3 L’Azienda ...... 5 1.4 Le Fasi dello Sviluppo ...... 6 1.5 Le Milestones ...... 11

2 Il Workflow 15 2.1 Le Fasi dello Sviluppo ...... 15 2.2 Le Milestones ...... 19

3 Unreal Engine: Dalla prospettiva del codice 23 3.1 Game Engines ...... 23 3.2 Programmare in C++ con Unreal Engine 4 ...... 24 3.2.1 C++ e i Blueprint ...... 24 3.2.2 Estendere una classe C++ tramite Blueprint ...... 28 3.2.3 Invocare funzioni da C++ ed internamente ai Blueprint . . . . 29 3.2.4 Le classi di Gameplay: Objects, Actors e Components . . . . . 32 3.2.5 Unreal Objects ...... 32 3.2.6 AActor ...... 32 3.2.7 UActorComponent ...... 33 3.2.8 UStruct ...... 34 3.3 Unreal Reflection System ...... 35 3.4 Object/Actor Iterators ...... 37 3.5 Gestione della memoria e Garbage Collection ...... 37 3.5.1 Garbage Collection e UObject ...... 38 3.5.2 Garbage Collection e AActor ...... 38 3.5.3 Riferimenti a Non-UObject ...... 39 3.6 Prefissi per la nomenclatura delle classi ...... 40

4 Unreal Engine: Dalla prospettiva dei Blueprint 41 4.1 Il sistema dei Blueprint ...... 41 4.1.1 Il Blueprint Editor ...... 41 4.1.2 Le Variabili ...... 42 4.1.3 Gli Eventi ...... 43 4.1.4 Le Azioni ...... 45 4.1.5 Eventi Custom ...... 46

ix x INDICE

4.1.6 Le Funzioni ...... 49 4.1.7 Gli Array ...... 50 4.1.8 Le Struct ...... 51 4.1.9 Gli Enum ...... 52 4.1.10 I Branch Condizionali ...... 54 4.1.11 Switch On Int ...... 54 4.1.12 For Each Loop ...... 55

5 Gli Strumenti ed i Framework di Supporto 57 5.1 I Plug-In per UE4 ed Ignition ...... 57 5.2 Perforce Helix ...... 58 5.2.1 Helix Core ...... 59 5.2.2 Gli Stream ...... 59 5.2.3 Helix Visual Client ...... 61 5.2.4 I Depot ...... 61 5.2.5 I Workspace ...... 62 5.2.6 P4Merge ...... 62 5.2.7 Helix Swarm ...... 62 5.3 JIRA ...... 63 5.3.1 I Core Component di JIRA ...... 63 5.3.2 Custom Workflows ...... 63 5.3.3 Bug Workflow ...... 64 5.3.4 Feature Workflow ...... 65

6 La mia esperienza a Milestone 67 6.1 Bug Fixing ...... 67 6.1.1 SX3 - Bug della camera durante caduta del pilota ...... 67 6.1.2 MGP20 - FastForward Cheat ...... 68 6.1.3 MGP20 - Audio Collision Debug ...... 69 6.1.4 MGP20 - Cambio camera ...... 71

Bibliografia 75 Elenco delle figure

3.1 C++ e i Blueprint - Proprietà di default della classe ...... 27 3.2 C++ e i Blueprint - Valori di default impostati ...... 27 3.3 C++ e i Blueprint - Valori caricati dopo il costruttore ...... 28 3.4 C++ e i Blueprint - Valori dopo l’invocazione di PostInitProperties() . 28 3.5 Estendere una classe C++ tramite Blueprint - Valori modificati . . . . 28 3.6 Estendere una classe C++ tramite Blueprint - Valori "DamagePerSe- cond" aggiornato ...... 29 3.7 Invocare funzioni da C++ ed internamente ai Blueprint - Categorie associate alle funzioni ...... 30 3.8 Invocare funzioni da C++ ed internamente ai Blueprint - Aggiornamento di "TotalDamage" ...... 30 3.9 UActorComponent - Albero dei componenti ...... 34 3.10 UActorComponent - I componenti nell’editor ...... 35

4.1 Editor dei Blueprint ...... 42 4.2 Le Variabili - Tipi di variabili ...... 43 4.3 Le Variabili - Creazione di una variabile ...... 44 4.4 Gli Eventi - Categorie di Eventi ...... 44 4.5 Gli Eventi - Eventi d’esempio ...... 45 4.6 Le Azioni - Inizializzazione con BeginPlay ...... 45 4.7 Le Azioni - Inizializzazione di due variabili ...... 45 4.8 Le Azioni - Distruzione di "Self" ...... 46 4.9 Le Azioni - Distruzione di "Other" ...... 46 4.10 Le Azioni - Distruzione di "ItemBP" ...... 46 4.11 Eventi Custom - Aggiunta di un nuovo Evento ...... 47 4.12 Eventi Custom - Configurazione Evento Custom ...... 47 4.13 Eventi Custom - Custom Event "AddScore" ...... 48 4.14 Eventi Custom - "Cast To" Action ...... 48 4.15 Eventi Custom - Caso d’uso di "Set Timer By Event" ...... 48 4.16 Le Funzioni - Aggiunta di una nuova Funzione ...... 49 4.17 Le Funzioni - Configurazione di una Funzione ...... 49 4.18 Le Funzioni - Esempio di funzione: "EnemiesLeft" ...... 50 4.19 Gli Array - Trasformazione di una variabile in un Array ...... 50 4.20 Gli Array - Popolamento di un Array ...... 50 4.21 Gli Array - Caso d’uso: Calcolo del punteggio ...... 51 4.22 Le Struct - Popolamento di una Struct ...... 51 4.23 Le Struct - Trasformazione di una variabile in una Struct ...... 51 4.24 Le Struct - Esempio di Struct "TNT" ...... 52

xi xii ELENCO DELLE FIGURE

4.25 Le Struct - Azioni "Break" e "Make" di una Struct ...... 52 4.26 Gli Enum - Aggiunta di un nuovo Enum ...... 53 4.27 Gli Enum - Popolamento di un Enum ...... 53 4.28 Gli Enum - Configurare un Enum ...... 53 4.29 Gli Enum - Caso d’uso: Cambio di mesh ...... 53 4.30 I Branch Condizionali - Caso d’uso: Controllo del punteggio ...... 54 4.31 I Branch Condizionali - Caso d’uso: Gestione salute ...... 54 4.32 Switch On Int - Caso d’uso: Difficoltà e num. nemici ...... 55 4.33 Switch On Int - Caso d’uso: Risposta in base al num. di domande . . 55 4.34 For Each Loop - Caso d’uso: Aggiornamento "Best Score" e "Best Player" 56 4.35 For Each Loop - Caso d’uso: Spegnimento lampade ...... 56

5.1 Lo stato attuale dei moduli di Ignition ...... 58 5.2 Gli Stream di Helix Core ...... 59 5.3 Lo Stream Mainline ...... 59 5.4 Lo Stream Release ...... 60 5.5 Lo Stream Development ...... 60 5.6 Lo Stream Task ...... 60 5.7 Lo Stream Virtual ...... 61 5.8 Default Workflow ...... 64

6.1 Modifiche apportate a GameBaseVehicle.h ...... 68 6.2 Modifiche apportate a GameBaseVehicle.cpp ...... 69 6.3 Modifiche apportate a IgnitionPlayerController.cpp ...... 70 6.4 Modifiche apportate a IgnitionVehiclePawn.cpp parte 1 ...... 70 6.5 Modifiche apportate a IgnitionVehiclePawn.cpp parte 2 ...... 71 6.6 Modifiche apportate a IgnitionVehiclePawn.cpp parte 3 ...... 71 6.7 Modifiche apportate a IgnitionVehiclePawn.cpp parte 4 ...... 72 6.8 Modifiche apportate a IgnitionVehiclePawn.cpp parte 5 ...... 72 6.9 Modifiche apportate a DefaultInput.ini ...... 73 Capitolo 1

L’Industria Videoludica

1.1 Introduzione

L’industria dei videogiochi è passata negli anni da mercato di nicchia a tendenza dominante. Oggigiorno il settore videoludico è in rapida espansione ed in grado di competere per utili e fatturato con le tradizionali industrie di entertainment e del software. Secondo i report dell’ISFE relativi al 2003/2004 sono stati raggiunti i 15.3 miliardi di euro a livello mondiale, considerando solo le vendite di software. Prese anche in considerazione quelle di hardware, la cifra raggiunge i 20 miliardi di euro. Gli stati uniti sono ancora oggi il mercato più florido in questo settore, con un fatturato di circa 6.4 miliardi, realizzato nel 2003. L’europa invece, che nel 1997 era il terzo mercato dopo il Giappone, nel 2003 lo ha superato con 5.6 miliardi di euro. Lo sviluppo dell’industria dei videogiochi, che ha avuto il suo primo vero inizio negli anni ’70 attraverso il lancio della prima console di casa Nintendo (Nintendo Color TV Game, 1977) e la memorabile simulazione di ping-pong arcade di casa Atari (Atari/Sears Telegames Pong, 1972), ha avuto la sua svolta decisiva con l’avvento dell’era Sony PlayStation One, intorno agli anni ’90. Dal 1995 al 2003 ben 89 milioni di unità sono state vendute in tutto il mondo. Il suo successore, la PlayStation 2, ha totalizzato 59 milioni di copie vendute fino al 2003. Mentre con le console GameCube di Nintendo e Xbox di Microsoft nel 2003 è stato raggiunto il risultato di 85 milioni di console di nuova generazione installate in tutto il mondo. Grazie ai miglioramenti e all’ampia diffusione delle tecnologie dell’informazione e della comunicazione, i giochi per PC e per console hanno raggiunto lo status di mercato di massa. Oggi i videogiochi sono disponibili in vari format, utilizzabili su piattaforme diverse e concorrenti accessibili a qualsiasi consumatore. Il mercato videoludico ha fornito in questi anni un contributo significativo alla divulgazione su larga scala delle tecnologie dell’informazione e della comunicazione. Per le generazioni più giovani, infatti, il videogioco rappresenta spesso il primo modo per avvicinarsi all’informatica, per quelle meno giovani esprime il ruolo sempre più importante della tecnologia nell’Home Entertainment.

1.2 I Diversi Ruoli

Sono diversi i ruoli all’interno della catena di produzione di un videogioco, sia da un punto di vista artistico che puramente tecnico. Possiamo individuare delle macro categorie rappresentative per ogni settore di sviluppo.

1 2 CAPITOLO 1. L’INDUSTRIA VIDEOLUDICA

1. Videogame Publisher: E’ coinvolto nel finanziamento dello sviluppo e cerca di capitalizzare l’investimento attraverso le licenze dei titoli prodotti. Quando sono grandi compagnie a ricoprire questo ruolo, a volte distribuiscono anche direttamente i loro prodotti, mentre quando sono compagnie di più modeste dimensioni, invece, ingaggiano aziende di distribuzione (o altri publisher più grandi) per distribuire i loro giochi. Le funzioni che un publisher svolge includono la scelta e l’acquisto di ogni licenza all’interno dei giochi. La localizzazione, la gestione del manuale utente, o anche la creazione degli elementi grafici come il box design del prodotto. Publisher di grandi dimensioni inoltre cercando di incrementare l’efficienza dei team di sviluppo interni ed esterni, possono fornire dei servizi ulteriori come il sound design e pacchetti software per offrire funzionalità condivise.

2. Videogame Producer: Il suo ruolo è di guidare e di mantenere concentrati gli altri membri del team, per permettergli di svolgere il loro lavoro nella maniera più efficace ed efficiente. E’ responsabile anche della pianificazione giornaliera e della gestione del team di lavoro. In alcuni studio, sono anche incaricati di mantenere il lavoro coerente con la "visione" del gioco. La pianificazione è più spesso organizzata attraverso il metodo agile detto Scrum, piuttosto che giornalmente, il progredire del progetto viene diviso in "sprint" che durano un paio di settimane (è proprio così che succede anche a Milestone, ed è una pratica piuttosto comune). Vengono stabiliti degli obiettivi personali e di gruppo, ed alla fine dello "sprint" vengono valutati ed eventualmente riprogrammati. Il producer controlla assieme ai suoi colleghi che non ci siano blocchi o impedimenti al normale svolgersi dell’attività di sviluppo, e li aiuta ad ottenere ciò di cui hanno bisogno per essere produttivi. Si interfaccia inoltre con altri soggetti esterni al team, ma che fanno parte degli stakeholders, come gli studio directors, i publisher, il dipartimento di marketing ecc. Tiene anche sotto controllo i budget disponibili, negozia i contratti, ordina anche da mangiare per il team a volte. Con lo sguardo rivolto al lungo termine, tiene il team concentrato e coeso verso l’obiettivo comune. I Producer alle prime armi vengono a volte chiamati Producer Associati o Assistenti Producer, e si occupano principalmente dei task giornalieri piuttosto che della visione globale d’insieme del progetto. I Producer Senior spesso diventano proprietari del progetto e sono responsabili della pianificazione a lungo termine, e possibilmente anche delle finanze, del gioco. I Producer Esecutivi tengono d’occhio anche più giochi allo stesso tempo. Per avere successo in questo campo sono necessarie buone capacità di pianificazione e di comunicazione. Molti Producer cominciano la loro carriera partendo prima come Tester, prima di passare in questo settore, in modo tale da fare esperienza nell’ambito gaming e prima di entrare a tutti gli effetti all’interno di un team come Producer Associati.

3. Videogame Designer: Più di ogni altro ruolo all’interno dell’industria video- ludica, un Designer necessita di una grande e vasta conoscenza dei videogame. Sicuramente ottenuta giocando molto e con una varietà di titoli diversi, analiz- zandoli, e discutendone con altre persone con le stesse affinità e con la stessa visione analitica del prodotto. Eventualmente i Designer creano i loro giochi personalmente in modo tale da avere esperienza diretta sul campo. Si occupano di discutere e di promuovere le loro idee di design con i Producer, i Programmer e 1.2. I DIVERSI RUOLI 3

gli Artist. Giocano anche i videogiochi dei competitor per analizzare i loro punti di forza e le loro debolezze. Scrivono i Game Design Documents (GDDs) per esporre le loro idee al loro team. Progettano i livelli e le meccaniche di Gameplay, gestiscono e bilanciano il Gameplay stesso, per assicurarsi che il gioco sia prima di tutto divertente e coinvolgente. Giocano ogni Build (la versione corrente del videogame) e prendono nota di come il design o l’implementazione possono essere migliorate. Utilizzano software come Microsoft Excel, XML Editor, o altri custom tool, per settare o tunare i parametri numerici che definiscono il Gameplay. La maggior parte degli studio dividono il lavoro di design in diverse sottosezioni, come il Level Design, il Mission/Quest Design, o il Game Design complessivo. Giochi ancora più grandi richiedono di dividere il lavoro in aree con granularità ancor più fine, un team di grandi dimensioni può aver bisogno anche di Combat Design, tuning e bilanciamento, progressione e ritmo del gioco ecc. Può essere impegnativo cominciare come Designer, a meno di non aver già partecipato alla creazione di qualche gioco di più modeste dimensioni, o senza essere in possesso di una certificazione in una scuola di Game Design. Alcuni Designer cominciano come QA Tester o Assistente Producer, e si spostano nell’ambito del Design una volta che dimostrano di avere il talento necessario. 4. Videogame QA Tester: Sfatiamo subito un mito, che i Tester non fanno altro che stare seduti a giocare tutto il giorno. E’ uno dei ruoli più pesanti, dovendo provare delle versioni del giochi ancora in via di sviluppo, ben prima che sia qualcosa di finito, quindi spesso contenenti diversi tipi di bug più o meno insidiosi, da scovare oltre che da correggere (o "fixare", in gergo). Spesso saranno privi della maggior parte dei contenuti, e non saranno "giocabili" nel vero senso della parola. Il compito principale di un Tester è quello di giocare una versione in costruzione del gioco (una "Build") e di tenere traccia di tutti i difetti riscontrati, anche estetici e non solo relativi alle meccaniche di gioco. Ecco perchè si chiama Quality Assurance Tester, proprio perchè lo scopo è quello di assicurare che il prodotto finale sia di ottima qualità. Quando un difetto, un bug, è stato individuato, una responsabilità del Tester è anche quella di capire come trovare un modo di farlo ripresentare in maniera predicibile. Compilare una Issue Report, cioè una descrizione del difetto, insieme agli step necessari per riprodurlo, all’interno di un software specializzato detto "Bug Tracker" oppure "Issue Database". Sottoporre il report al team del gioco in modo tale che possano fixare il problema. Il Programmer che riceverà il report, potrà richiedere ulteriori informazioni per poter trovare aiuto nella risoluzione del problema riscontrato. Alcuni QA Tester lavorano solo con le Build del gioco (chiamati "Black Box" Testers) mentre altri potrebbero avere anche accesso al codice sorgente ed aiutare i programmatori stessi con l’attività di debugging (chiamati "Grey/White Box" Testers in rapporto alla quantità di codice sorgente visibile). Il ruolo del Tester è molto critico dato che spesso sono l’ultima linea di difesa prima che il gioco sia rilasciato per la fruizione da parte dei videogiocatori. Se questo lavoro non viene portato a termine in maniera efficace, può portare alla delusione ed alla frustrazione di milioni di fan, che potrebbero rendersi conto che il gioco contiene bug di varia natura, crash, o ancora peggio che porta i giocatori a perdere i loro progressi all’interno del gioco. 5. Videogame Artist: Questo settore è composto da persone con forte propensione e talento artistico. Devono anche avere un’ottima confidenza e preparazione con i tool artistici usati per produrre contenuti digitali. Come Autodesk Maya 4 CAPITOLO 1. L’INDUSTRIA VIDEOLUDICA

(modellazione 3D) o l’onnipresente e conosciutissimo Adobe Photoshop, e devono aver costruito negli anni un vasto Portfolio con contenuti di qualità. Ci sono svariati ambiti all’interno del settore artistico dell’industria videoludica, a seguire un elenco di quelli principali.

∗ Environment Artist: Crea gli scenari e costruisce le architetture presenti nel mondo virtuale di gioco. ∗ Character Modeler: Crea modelli tridimensionali dei personaggi al- l’interno del gioco, dal personaggio principale, agli NPC (Non Playable Characters), ai nemici. ∗ Character Animator: Prende i modelli creati dal Character Modeler e costruisce le animazioni che gli daranno vitalità e realismo all’interno del prodotto finale. ∗ Concept Artist: Supervisiona e pianifica l’aspetto ed il feeling globale di tutto il mondo di gioco e dei personaggi coinvolti nella trama. ∗ User Interface (UI) Artist: Si occupa del design e di disegnare i menù, gli HUD, ed altri componenti grafici per la navigazione delle opzioni di gioco.

Sono svariate le sotto-specializzazioni su cui qualsiasi Artist può decidere di dedicare la propria carriera, con lo scopo di incrementare le sue skill e di diventare veramente esperto. Esempi di specializzazioni sono la Concept Art, Character Modeling, Character Rigging (la creazione ed il tuning di particolari scheletri che permettono agli Animator di poter animare le mesh in maniera più agevole possibile), Animation, Environment, e Visual Effect. Ogni carriera all’interno della Videogame Art richiede abilità di tipo diverso, e di conseguenza anche un compenso economico che può variare anche di molto.

6. Videogame Audio Engineer: Ci sono pochi preziosi posti in questo settore dell’industria dei videogiochi, perchè può bastare un solo ingegnere audio per soddisfare i bisogni di molteplici team. Infatti, non è raro avere un singolo Audio Engineer che copre un interno studio. Molti studio di videogiochi non hanno nessun membro dello staff audio all’interno del proprio organico, perchè decidono di assumerli a contratto quando ce ne dovesse essere bisogno. Le mansioni svolte da un Audio Engineer coinvolgono: Parlare con il team di sviluppo per determinare quale tipo di musiche o di effetti audio che sono necessari, cercare all’interno delle librerie audio commerciali i suoni da usare come materiale. Registrare nuovi effetti audio in uno studio oppure nel mondo reale ("on the field"). Usare hardware audio specializzato e software per registrare effetti audio, crearne di nuovi, costruire "soundscapes" immersivi, oppure modificare e combinare suoni già esistenti per crearne di originali composti. Sotto l’ombrello di "game audio" ci sono varie specializzazioni come il Music Composer, l’Ingegnere dei Rumori ("Foley Engineer"), l’Audio Engineer Generalista, ed altri ruoli che comprendono programmare, mixare ed implementare l’audio del mondo di gioco. La maggior parte dei lavori sono posizioni a contratto.

7. Videogame Programmer: Un programmatore di videogiochi si ritrova spesso ad utilizzare linguaggi come C++ e C#, con l’obiettivo di inserire ogni componen- te (artistica o meno, detta "Asset") all’interno del progetto e di renderlo un gioco funzionante. La programmazione è decisamente l’aspetto più tecnico all’interno 1.3. L’AZIENDA 5

della catena di produzione dello studio. La maggior parte dei programmatori partono laureandosi in Informatica o Ing. Informatica (o Computer Science, dato che all’estero non esiste questa distinzione) prima di entrare in un team di sviluppo, ma ci sono anche persone che studiano da autodidatti. Le mansioni di un Game Programmer sono: Leggere la documentazione o discutere con gli altri membri del team per capire, e poi implementare, il funzionamento di una determinata feature di gioco. Pianificare il proprio approccio insieme agli altri programmatori, specialmente con il Lead Developer del team. Eseguire il codice del gioco per testare (Prima del QA) se le nuove modifiche siano funzionanti ed il gioco si comporti come previsto dai Designer, e fare dei fix se necessario prima che sia troppo tardi. Ricevere Bug Report dai QA Tester, e cercare di risolvere i problemi che hanno individuato. Implementare feature di gioco, sistemi di debugging, ottimizzare le performance, e convertire le azioni dei giocatori in risultati di gioco. Quasi tutti quanti i team, fatta esclusione per i più piccoli, hanno varie sotto-specializzazioni per i programmatori, concentrandosi su aree ben definite della code base come la parte online, il sistema di combattimento (in relazione al tipo di gioco, naturalmente), i personaggi e l’IA, l’input del giocatore e i suoi movimenti, la fisica di gioco, la grafica, come anche tool e pipeline per agevolare il lavoro di tutti. Il Videogame Programmer ha bisogno di profonde conoscenze tecniche, concentrazione, ed anche molta pazienza.

1.3 L’Azienda

L’azienda venne fondata (inizialmente chiamata Graffiti) nel 1994 da Antonio Farina. Nel 1996 assunse il nome Milestone ("pietra miliare" in inglese), sempre sotto la stessa leadership, specializzandosi soprattutto nelle simulazioni di giochi di corse per le varie piattaforme (Playstation, Xbox e PC). Nel 1998 ebbe inizio la partnership con Electronic Arts che ha permesso di produrre il primo capitolo della serie di simulazioni motociclistiche dedicate al mondo della Superbike, SBK World Championship, pubbli- cato sotto il prestigioso brand EA Sports. Il successo è arrivato proprio con questa nuova IP (Intellectual Property). Dopo i primi tre titoli, Milestone ha distribuito i suoi giochi attraverso la Black Bean, ed infine autonomamente. Il successo è arrivato con i giochi dedicati alla Superbike. I primi tre (1999, 2000, 2001) facevano parte della linea EA Sports. In seguito ha distribuito le sue produzioni attraverso la Black Bean, e infine autonomamente. Nel 2007 Milestone ha esordito su PlayStation Portable, e realizza i titoli SBK-07 e MotoGP 07. Nel 2008 sono usciti SBK-08 e MotoGP 08, i primi due prodotti per le console e PS3 realizzati dalla casa italiana. Nel 2009 sono prodotti SBK-09 e . Per il 2010 i seguiti SBK X e Superstars V8 Next Challenge, ed il ritorno, dopo cinque anni, del rally con la licenza grazie alla quale produce per PS3, Xbox 360 e PC fino al 2013 cinque giochi. A maggio 2012 è uscito SBK Generations, il prosieguo della saga SBK. Nel 2013 ha pubblicato MotoGP 13 su PC, Xbox 360, PS3 e PlayStation Vita. A giugno 2014 ha pubblicato MotoGP 14. A giugno 2015 è uscito MotoGP 15 per PlayStation 4, PlayStation 3, , PC, Steam, Xbox 360. Nel 2014 l’azienda milanese ottiene una nuova licenza, quella del campionato mondiale di motocross, per il quale ha finora sviluppato e pubblicato cinque giochi. Negli anni seguenti, Milestone pubblica altre due nuove IP: Ride, il cui primo capitolo è uscito nel 2015, seguito da Ride 2 (2016) e RIde 3 (2018) più lo spin-off dedicato ai 90 anni di Ducati (2016), e Gravel, dedicato alle corse su quattro ruote off-road. Proprio a cavallo tra il 2017 e il 6 CAPITOLO 1. L’INDUSTRIA VIDEOLUDICA

2018 avviene anche il cambio di motore grafico, passando da un software proprietario all’Unreal Engine 4 di Epic Games. Alla fine del 2002, Milestone divenne parte di Leader Group, una compagnia di videogiochi molto sfaccettata. Attraverso questa transizione Milestone divenne affiliata esclusivamente al publisher interno di Leader Group: Lago. Nonostante questo, lo studio successivamente cominciò a collaborare nuovamente con altri publisher esterni, nell’interesse di tutte le parti coinvolte. La loro posizione di consociati gli ha anche permesso di crescere e di sviluppare vari giochi per diverse piattaforme contemporaneamente. Nell’ottobre del 2007, lo studio aveva 55 dipendenti. A gennaio del 2010, Milestone ne aveva raggiunti 80 in totale, rendendola l’azienda di videogiochi più grande in Italia. Nel 2011 Milestone si è resa indipendente, con l’obiettivo di cresce ancora ma di divenire autosufficiente. Dopo aver fatturato poco più di 2.6 milioni di euro nel 2012, Milestone ha scelto di cessare le sue compartecipazioni e di cominciare a pubblicare giochi per conto proprio. Il risultato di questa strategia è stato l’incremento dei profitti dell’azienda che ha raggiunto i 28 milioni nel 2017. Il 14 agosto di quest’anno, l’azienda mediatica tedesca Koch Media ha raggiunto un accordo con Milestone (proprio mentre l’azienda era chiusa per la settimana di ferie estive, durante il mio tirocinio) per la sua acquisizione, comprese tutte le sue proprietà intellettuali, per la somma di 44.9 milioni di euro pagati in contanti. Al momento l’azienda ha 176 dipendenti così distribuiti: 55 programmatori, 14 tester, 39 designer e 66 artist (più altre figure di supporto).

1.4 Le Fasi dello Sviluppo

Lo sviluppo di un videogame necessita come ogni altra forma di software di una serie di milestone che permettano di organizzare il lavoro e di dividerlo in fasi ben definite. I metodi formali di sviluppo software sono spesso sottovalutati ed ignorati. Giochi che sono stati portati avanti con delle pessime metodologie di sviluppo sono molti soggetti a fallire a causa di esaurimento del budget disponibile prima che il gioco sia stato portato a compimento, errori grossolani nella stima dei tempi necessari, o giochi che contengono un numero di bug notevole. Lo sviluppo di un gioco non è complessivamente adatto ai metodi tipici per la gestione del ciclo di vita dei software tipici, come per esempio il Modello a Cascata. Il metodo più diffuso è quello Modello Agile, che si basa su prototipazione iterativa, un sottoinsieme della prototipazione software. Lo sviluppo agile dipende molto dai feedback e permette di rifinire il gioco gradualmente incrementando il numero e la qualità delle sue feature. E’ un metodo molto efficace soprattutto nell’industria videoludica, perchè molti progetti non partono subito con dei requisiti ben fissati e stabiliti a priori. Tra i metodi agili uno dei più diffusi è sicuramente Scrum, utilizzato anche in Milestone S.r.l..

1. Pre-Production: Detta anche Fase di Design è uno step di pianificazione del progetto che si focalizza sull’idea e sul concept e sulla produzione dei primi documenti di design. L’obiettivo del Concept Development è principalmente quello di produrre una documentazione chiara e di facile comprensione, che descriva tutti i compiti, la schedulazione e le stime operative del team di sviluppo. Il corpus dei documenti redatti in questa fase è chiamato Piano di Produzione. Questa fase non è solitamente finanziata dal publisher, anche se i più attenti alla qualità possono richiede agli sviluppatori di sottoporre dei documenti anche durante la pre-produzione. Si compone di varie sotto-fasi: 1.4. LE FASI DELLO SVILUPPO 7

Giochi sviluppati Nome Anno Piattaforme Super Loopz 1994 SNES Superbike World Championship 1999 PC Superbike 2000 2000 PS1, PC Superbike 2001 2000 PC L’eredità 2003 PS2, PC SBK-07: Superbike World Cham- 2007 PS2, PSP pionship MotoGP 07 2007 PS2 SBK-08: Superbike World Cham- 2008 Xbox 360, PS3, PS2, PSP, PC pionship MotoGP 08 2008 Xbox 360, PS3, PS2, Wii, PC SBK-09: Superbike World Cham- 2009 Xbox 360, PS3, PS2, PSP, PC pionship Superstars V8 Racing 2009 Xbox 360, PS3, PC SBK X 2010 Xbox 360, PS3, PC WRC: FIA World Rally Champion- 2010 Xbox 360, PS3, PC ship WRC 2 FIA World Rally Champion- 2011 Xbox 360, PS3, PC ship SBK Generations 2012 Xbox 360, PS3, PC WRC 3 FIA World Rally Champion- 2012 Xbox 360, PS3, PS Vita, PC ship WRC Powerslide 2013 Xbox 360, PS3, PC MotoGP 13 2013 Xbox 360, PS3, PS Vita, PC WRC 4 FIA World Rally Champion- 2013 Xbox 360, PS3, PS Vita, PC ship MXGP: The Official Motocross 2014 Xbox 360, PS3, PS Vita, PC Videogame MotoGP 14 2014 PS4, PS3, Xbox 360, PS Vita, PC Ride 2015 PS4, PS3, Xbox 360, PS Vita, PC MotoGP 15 2015 PS3, PS4, Xbox 360, Xbox One, PC Ducati - 90th Anniversary 2016 PS4, Xbox One, PC MXGP 2: The Official Motocross 2016 PS4, Xbox One, PC Videogame The Game 2016 PS4, Xbox One, PC Ride 2 2016 PS4, Xbox One, PC MXGP3 - The Official Motocross 2017 PS4, Xbox One, PC Videogame MotoGP 17 2017 PS4, Xbox One, PC Gravel 2018 PS4, Xbox One, PC Monster Energy Supercross - The 2018 PS4, Xbox One, PC, Switch Official Videogame MotoGP 18 2018 PS4, Xbox One, PC, Switch MXGP Pro 2018 PS4, Xbox One, PC Ride 3 2018 PS4, Xbox One, PC Monster Energy Supercross - The 2019 PS4, Xbox One, PC, Switch Official Videogame 2 MotoGP 19 2019 PS4, Xbox One, PC, Switch 8 CAPITOLO 1. L’INDUSTRIA VIDEOLUDICA

∗ High Concept: In questa prima fase il prodotto è ancora un’idea da valutare, per comprenderne le potenzialità e i punti deboli e decidere come organizzare il suo futuro sviluppo. Consiste in uno studio di fattibilità, nella stesura di massima di tutte le caratteristiche di gioco seguite da una stima del numero di persone necessarie allo sviluppo e dalla stima dei costi. ∗ Pitch: Conosciuto anche come Concept Document, o Game Proposal, è un breve documento di riepilogo che presenta i punti di forza del prodotto, che potrebbero attrarre gli utenti, e che spiega perchè il gioco proposto potrebbe essere redditizio una volta sviluppato. Possono non essere scritti, ma solo discussi all’interno dell’azienda. Alcune aziende li usano per richiedere i fondi necessari per lo sviluppo al publisher di riferimento. Questa proposta di gioco può dover superare diversi Green-Light Meetings con gli amministratori delegati del publisher prima di essere approvati ed il gioco finanziato. ∗ Concept: Detto anche Game Plan, è un documento più dettagliato del Pitch, che include complessivamente tutte le informazioni sul gioco. L’High Concept, il genere del gioco, la descrizione del gameplay, le funzionalità, l’ambientazione, la storia, il pubblico del gioco, le piattaforme hardware, la stima dei tempi necessari, analisi di marketing, il personale richiesto, e l’analisi dei rischi, sono tutte le informazioni e i dettagli che si possono trovare in questo documento onnicomprensivo. Prima che venga approvato un determinato design, un piccolo gruppo di programmatori e di artist collaborano per sviluppare piccoli prototipi che mostrano determinate feature chiave che gli stakeholders vorrebbero veder incorporate nel gioco finale. Gli artist invece creano concept art e schizzi da cui poi prenderanno vita i veri asset presenti nel gioco. ∗ Game Design Document: Prima che la produzione su vasta scala possa avere inizio, il team di sviluppo crea la prima versione del Game Design Document che incorpora tutto o la maggior parte del contenuto del Pitch Document. Il Design Document descrive il concept del gioco e le dinamiche di gameplay principali in dettaglio, spesso include anche schizzi preliminari di varie parti del gioco. Questo documento a volte include prototipi funzionali di alcune sezioni del prodotto. Il documento di design continua spesso ad essere migliorato ed incrementato lungo tutto l’arco dello sviluppo complessivo del gioco, venendo modificato settimanalmente o anche giornalmente in alcuni casi. ∗ Prototipo: Creare prototipi di idee di gamplay e di feature è un’attività importante che permette ai programmatori e ai game designer di speri- mentare diversi algoritmi e di casi d’uso per il gioco. Una grossa fetta dell’attività di prototipazione può avere luogo durante la pre-produzione prima che il documento di design sia completo, in modo tale da permettere di determinare quali feature saranno discusse e specificate nel design. La prototipazione durante questo stage e spesso fatta manualmente (su carta) e non utilizzando strumenti digitali, perchè ciò risulta più semplice e rapido da testare e da modificare senza spreco di risorse per idee che potrebbero essere cancellate in seguito. Questa è un’attività che può essere svolta anche contemporaneamente allo sviluppo principale, per testare nuove idee mentre il gioco prende vita. Spesso i prototipi necessitano di essere sviluppati velo- cemente e con veramente poco tempo a disposizione, per questo motivo solo i programmatori più prolifici vengono coinvolti per sviluppare rapidamente 1.4. LE FASI DELLO SVILUPPO 9

questi banchi di prova. Strumenti RAD (Rapid Application Development) possono essere utilizzati per velocizzare ulteriormente lo sviluppo. Un mo- dello di sviluppo di successo è la prototipazione iterativa, dove il design viene rifinito basandosi sui progressi correnti.

2. Production: La produzione è la fase principale dello sviluppo, quando gli asset ed il codice sorgente per il gioco vengono creati. La produzione è generalmente definita come il periodo di tempo in cui il progetto vede la compartecipazione di tutto lo staff a disposizione. I programmatori scrivono nuovo codice sorgente, gli artist creano nuovi asset di gioco, come le sprite o i modelli 3D (a seconda della tipologia di gioco). Gli ingegneri audio sviluppano effetti sonori e i compositori creano la colonna sonora del gioco. I level designers compongono i livelli, e i writer scrivono i dialoghi per i filmati e per gli NPC. I game designer continuano a sviluppare il design del gioco attraverso tutta la fase di produzione. Anch’essa è composta da diverse sotto-fasi:

∗ Game Design: Il Game Design è un processo essenziale nello sviluppo di un gioco, e collaborativo, che consiste nella progettazione dei contenuti e delle regole di gioco. Richiede competenze sia artistiche che tecniche, nonché di scrittura. La creatività e l’apertura mentale sono vitali per portare a termine un videogioco di successo. Durante lo sviluppo, il game designer implementa e modifica il design del gioco in modo tale che rifletta la visione d’insieme del progetto. Feature e livelli sono spesso modificati, aggiunti o rimossi. Le decisioni artistiche sono in continua evoluzione e la storia anche può essere soggetta a cambiamenti. Nuove piattaforme possono essere aggiunte o il target demografico potrebbe cambiare. Tutti questi cambiamenti devono essere documentati e diffusi attraverso il resto del team. La maggior parte dei cambiamenti avviene come update del Design Document. ∗ Game Programming: La codifica del gioco è gestita da uno o più pro- grammatori, che sviluppano prototipi per testare idee, molte delle quali potrebbero non finire mai a fare parte del gioco finale. I programmatori incorporano le nuove feature richieste dai designer e correggono eventuali bug che dovessero esser stati introdotti durante il processo di sviluppo. Anche se dovesse esser stato scelto l’utilizzo di un motore di gioco già pronto all’uso (di terze parti quindi), una grossa quantità di sviluppo software è necessaria per modificare quasi ogni gioco sul mercato. ∗ Level Design: Da un punto di vista temporale, il primo livello di gioco è quello che richiede più tempo per essere creato. A volte mentre i designer e gli artist utilizzano i tool per assemblare i livelli, si trovano ad avere bisogno di nuove feature e cambiamenti forniti dai tool interni che gli permettono uno sviluppo più rapido e di maggiore qualità. Le nuove feature introdotte potrebbero rendere i vecchi livelli obsoleti, in modo tale da rendere quelli sviluppati velocemente all’inizio scartabili. A causa dell’ambiente di sviluppo dinamico, anche il design dei primi livelli di gioco potrebbe essere soggetto a cambiamenti. Non è raro spendere anche fino a 12 mesi su di un solo livello di gioco prima di completarlo, all’interno di un progetto lungo 3 anni. I livelli successivi possono essere sviluppati più velocemente dato che l’insieme delle feature è più completo e la game vision è più chiara e stabile. 10 CAPITOLO 1. L’INDUSTRIA VIDEOLUDICA

∗ Art Design: E’ il processo di creazione degli aspetti artistici di un . Il design della video game art inizia già in fase di pre-produzione. I video game artist sono visual artist coinvolti fin dal concepimento del gioco, che si occupano di creare schizzi approssimativi dei personaggi, degli ambienti, degli oggetti ecc. Questi concept iniziali possono anche essere creati dai game designer prima che il gioco entri nella fase di produzione vera e propria. A volte questi concept design vengono chiamati Programmer Art. Una volta terminati gli schizzi iniziali ed il gioco è pronto per essere portato ad un livello più avanzato di sviluppo, sempre più artist vengono coinvolti nel progetto per dare vita a questi schizzi attraverso il Graphic Design. L’Art Design di un gioco può essere gestita da varie persone, più un’azienda è grande più è probabile che diverse persone si occupino di questo ambito. Piccole realtà tendono a non avere tanti artist il che significa che quelli a disposizione devono avere diverse skill a cui poter attingere, mentre in realtà più grandi ogni artist diventa sempre più specializzato. ∗ Audio Production: Il Game Audio si differenzia in tre sotto-categorie: Effetti sonori, musiche e dialoghi. La produzione di Sound Effect consiste nella creazione di nuovi suoni o la modifica di campioni o la replica di suoni presi dal mondo reale. Le musiche possono essere sintetizzate o anche performate live. Ci sono vari modi in cui la musica può essere presentata in un gioco, potrebbe essere ambientale, dove lo scopo è quello di rinforzare l’estetica di gioco ed il game setting. La musica potrebbe essere scatenata da eventi interni al gioco. Per esempio, in giochi come Pac-Man o Super Mario, quando il giocatore ottiene dei power-up viene riprodotto un suono distintivo. Per farsi un’idea, un gioco da 20 ore di campagna single-player può avere anche 60 minuti di colonna sonora. Dialoghi e doppiaggi rendono il gameplay ancora più realistico e coinvolgente, oltre a dare più carattere e personalità ai personaggi. ∗ Testing: Nelle fasi finali dello sviluppo, la Quality Assurance gioca un ruolo fondamentale. I tester cominciano il loro lavoro appena si ha in mano una sezione giocabile. Potrebbe essere un solo livello, o un sottoinsieme qualsiasi delle feature del gioco, basta che sia sufficientemente compatto ed utilizzabile. Inizialmente, testare un gioco richiede relativamente poco tempo. I tester possono lavorare a più di un gioco contemporaneamente. Quando si avvicinano le fasi finali dello sviluppo, testare un unico gioco può richiede vari tester full-time. Il testing è fondamentale per i giochi moderni, che sono particolarmente complessi, dove anche piccole modifiche possono avere effetti catastrofici. In queste fasi, le feature ed i livelli vengono prodotti alla velocità massima e c’è sempre più materiale da testare, più che in qualsiasi altra fase del gioco. I tester portano a termine dei Regression Test per assicurarsi che le feature che sono state introdotte inizialmente continuino ad essere funzionanti. I test di regressione sono un task vitale necessario ad uno sviluppo software efficace. Man mano che nuove feature vengono aggiunte, piccoli cambiamenti alla codebase possono avere effetti collaterali in differenti porzioni del gioco. Questo compito viene spesso sottovalutato, per diverse ragioni. A volte, quando una feature viene implementata e poi testata, viene considerata funzionante e non viene ripetuto il testing più avanti. Inoltre, le feature che vengono aggiunte successivamente sono considerate più prioritarie e quelle già esistenti non vengono testate per 1.5. LE MILESTONES 11

un tempo sufficiente. Un Regression Testing adeguato diventa costoso in maniera incrementale in linea con l’incremento nel numero delle feature, e viene spesso schedulato in maniera scorretta. Nonostante i rischi nel testare in maniera non efficace, alcuni game developer e publisher falliscono nel testare tutta la suite di feature e rilasciano giochi contenenti diversi bug. Tutto ciò può provocare il discontento degli utenti finali ed il fallimento nel raggiungere gli obiettivi di vendita del prodotto finale. Quando questo accade, la maggior parte dei developer e dei publisher cerca di fixare i bug velocemente rilasciando delle patch che auspicabilmente rendono il gioco pienamente giocabile.

3. Post-Production

∗ Mantenimento: Una volta che il gioco viene rilasciato, la fase di mante- nimento ha inizio. I giochi sviluppati per console in passato non avevano quasi nessuna fase di mantenimento. I giochi rilasciati rimanevano per sempre con lo stesso numero di bug e di feature, questo era comune dato che tutte le console avevano praticamente lo stesso hardware. L’incompatibilità non era fonte di bug. In questi casi, il mantenimento avveniva solo in caso di porting, di un sequel, o di un remake che riutilizzava una grande porzione dell’engine di gioco e degli asset. In tempi relativamente recenti la popolarità dei giochi online per console è cresciuta, e sono stati sviluppati servizi online come Xbox Live. Gli sviluppatori possono manutenere il loro software attraverso patch scaricabili. Questi cambiamenti non sarebbero stati possibili in passato senza la diffusione di internet. Lo sviluppo per PC è diverso: Gli sviluppatori devono fronteggiare la grande differenza di configurazioni hardware disponibili. Inoltre, il numero di configurazioni diverse elevato porta inevitabilmente alla scoperta di game-breaking bug che i programmatori ed i tester non avevano previsto. I programmatori attendono per un determinato lasso di tempo che vengano segnalati quanti più bug report, dopodiché, quando ritengono di aver ottenuto sufficienti feedback, cominciano a lavorare ad una patch. La patch può richiedere settimane o mesi interi per essere completata, ma è pensata per risolvere la maggior parte dei bug segnalati ed i problemi del gioco che erano stati ignorati in precedenti code release, e raramente anche quelli introdotti da patch precedenti. Occasionalmente le patch possono introdurre anche featu- re extra e contenuti ed anche alterare il gameplay. Nel caso dei Massively Multiplayer Online Game, come i MMORPG, il rilascio del gioco è l’inizio esatto dell’inizio della fase di mantenimento. Questi giochi sono in manteni- mento continuo dato che il mondo di gioco è continuamente modificato e nuove feature vengono aggiunte. Lo staff che si occupa di questo processo, per un MMOG di successo, può contenere svariate persone, di cui a volte fanno parte alcuni membri originari del team di sviluppo iniziale.

1.5 Le Milestones

Progetti commerciali di sviluppo videogame potrebbero dover soddisfare delle Milestone imposte dal publisher. Le milestone stabiliscono importanti risultati raggiunti durante lo sviluppo del gioco e sono utilizzate per tenere traccia dello stato di progresso raggiunto. Possono essere denominate, per esempio, first playable, alpha, o beta. Le milestone 12 CAPITOLO 1. L’INDUSTRIA VIDEOLUDICA di progetto dipendono dalla schedule di sviluppo. Si basano solitamente su multiple brevi descrizioni delle funzionalità: Un esempio potrebbe essere "il giocatore esplora l’ambiente di gioco" oppure "Fisica, collisioni e veicoli funzionanti" (varie descrizioni sono ammesse). Possono variare in numero, solitamente da 3 a 20, a discrezione degli sviluppatori e dell’editore. La loro lista è un accordo di collaborazione tra le parti in causa (studio e publisher). Lo studio si impegna nel rendere le descrizioni delle milestone brevi e semplici da leggere, ma a seconda del publisher, gli accordi sulle milestone possono diventare anche molto dettagliate per uno specifico gioco. Quando si lavora con un buon publisher, affidabile ed affermato, solitamente se la milestone è al 90% del suo completamento, lo studio verrà pagato in anticipo come se fosse stata finita, con la promessa che lo diverrà quando la prossima tappa sarà raggiunta. Le spese mensili dello studio sono spesso ingenti e necessitano di essere saldate regolarmente, e le due parti in causa cercano di venirsi in contro in modo da agevolare il raggiungimento degli obiettivi comuni e soddisfare gli interessi di entrambi. Inoltre a volte le milestone vengono scambiate, entrambe le parti potrebbero accordarsi per riorganizzare gli obiettivi in base al cambiamento dei requisiti ed alle risorse a disposizione. Gli accordi presi sulle milestone sono solitamente inclusi anche nella parte legale e contrattuale del rapporto. Conseguita una milestone segue solitamente un accordo di pagamento. Alcuni publisher molto affermati nell’industria potrebbero semplicemente accordarsi in base alla quantità di tempo in cui il gioco è stato in fase di sviluppo (mesi o periodi più lunghi) piuttosto che un insieme specifico di funzionalità di gioco, ma è molto meno comune. Non esiste ancora uno standard aziendale per definire le milestone, che variano di molto in base al publisher, all’anno, ed al progetto in causa. Le milestone più comuni per cicli di sviluppo di circa due anni, sono le seguenti:

∗ First Playable: Questa versione del gioco contiene una parte rappresentativa del gioco e dei suoi asset principali, ed è la prima versione a contenere le parti funzionali principali del gameplay. Si basa spesso sui prototipi creati in fase di pre-produzione. Le Alpha e First Playable sono solitamente utilizzate in riferimento ad un’unica Milestone, mentre in progetti di grandi dimensioni queste due versioni del gioco vengono separate e sono richieste entrambe, è richiesta a volte la First Playable prima di poter ottenere una Alpha con tutte le feature necessarie. La First Playable viene completata dai 12 ai 18 mesi prima del rilascio del codice. Viene chiamata anche "Pre-Alpha" oppure "Proof of Concept".

∗ Alpha: La Alpha è lo stage in cui le feature chiave del gameplay sono state implementate, e gli asset sono parzialmente completati. Un gioco in Alpha è completo di tutte le feature, cioè è giocabile e contiene le feature principali. Queste feature potrebbero essere ulteriormente revisionate in base al testing ed ai feedback. Piccole nuove feature potrebbero venir aggiunte in seguito, pianificate similmente, mentre quelle non implementate potrebbero essere scartate. I programmatori si concentrano principalmente sul completamento della codebase, piuttosto che implementare le nuove aggiunte. Le Alpha vengono completate da 8 a 10 mesi prima del rilascio del gioco, ma queste tempistiche potrebbero variare anche in maniera significativa in base alla dimensione dei contenuti che il progetto del gioco prevede.

∗ Code Freeze: Il Code Freeze è la fase in cui viene terminata l’aggiunta di nuovo codice al gioco e vengono solo risolti bug. Solitamente avviene da 3 a 4 mesi prima della Code Release. 1.5. LE MILESTONES 13

∗ Beta: La Beta è una versione del gioco completa di tutte le feature e degli asset, dove solo ed unicamente bug vengono fixati. Questa versione non contiene bug che impediscono al gioco di essere rilasciabile. Nessun cambiamento viene apportato alle feature di gioco, agli asset, o al codice. Le Beta si posizionano da 2 a 3 mesi prima della Code Release. ∗ Code Release: Detta anche QA Candidate, è lo stage in cui la maggior parte dei bug sono stati già risolti, ed il gioco è pronto per il rilascio o la pubblicazione, e per essere sottoposto alla revisione dei produttori di console. Questa è la versione che viene sottoposta alla verifica completa da parte del reparto QA. La prima candidata per la Code Release è solitamente pronta da 3 a 4 settimane prima dell’effettiva Code Release. ∗ Submission: In questa fase il gioco è pronto per il rilascio finale, ed il reparto QA è tenuto a confermare le checklist finali del processo di testing prima che il gioco sia effettivamente pronto per la produzione. Prima di procedere oltre, i tester devono provare il gioco nell’ambiente di produzione per assicurarsi che non ci siano bug di nessun genere. Una volta superati tutti i test, si procede alla Submission vera e propria tramite il reparto di publishing, che inoltra una copia del gioco ai console owner (Microsoft, Sony, Nintendo, e da quest’anno anche Google). Per ottenere la definitiva pubblicazione del gioco, esso viene testato secondo le TRC/TCR di ciascuna console. Questa è una fase decisamente delicata in quanto in caso di fallimento bisognerà ripetere la procedura finchè non verranno soddisfatti tutti i requisiti richiesti. Fallire una submission rappresenta una perdita di tempo ed economica. Superato il terzo fallimento le successive submission cominciano ad avere un costo molto ingente e possono pesare molto sul budget dell’azienda. ∗ Gold Master: Una volta che tutti i problemi importanti sono stati risolti, il testing è stato interamente portato a termine con successo, l’equivalente di una Release Candidate può essere approvata dal Publisher responsabile per essere finalmente rilasciata al grande pubblico. Questa è la vera e propria versione finale del gioco da distribuire ai giocatori di tutto il mondo.

∗ Post Release: Ora che il gioco è stato rilasciato, nuovi contenuti possono essere previsti per il futuro, o delle patch per migliorare l’esperienza di gioco o correggere dei bug (cosa che non dovrebbe mai accadere ma putroppo a volte può succedere, specialmente se i ritmi sono serrati ed i giochi vengono sviluppati in tempi troppo ridotti). In base al piano di supporto successivo al rilascio, il team può abbandonare la struttura delle milestone e gestire miglioramenti e aggiunte cadenzate secondo ogni singolo sprint futuro, o creare nuove milestone per la produzione di DLC e di pacchetti di espansione.

Capitolo 2

Il Workflow

2.1 Le Fasi dello Sviluppo

Lo sviluppo di un videogame necessita come ogni altra forma di software di una serie di milestone che permettano di organizzare il lavoro e di dividerlo in fasi ben definite. I metodi formali di sviluppo software sono spesso sottovalutati ed ignorati. Giochi che sono stati portati avanti con delle pessime metodologie di sviluppo sono molti soggetti a fallire a causa di esaurimento del budget disponibile prima che il gioco sia stato portato a compimento, errori grossolani nella stima dei tempi necessari, o giochi che contengono un numero di bug notevole. Lo sviluppo di un gioco non è complessivamente adatto ai metodi tipici per la gestione del ciclo di vita dei software tipici, come per esempio il Modello a Cascata. Il metodo più diffuso è quello Modello Agile, che si basa su prototipazione iterativa, un sottoinsieme della prototipazione software. Lo sviluppo agile dipende molto dai feedback e permette di rifinire il gioco gradualmente incrementando il numero e la qualità delle sue feature. E’ un metodo molto efficace soprattutto nell’industria videoludica, perchè molti progetti non partono subito con dei requisiti ben fissati e stabiliti a priori. Tra i metodi agili uno dei più diffusi è sicuramente Scrum, utilizzato anche in Milestone S.r.l..

1. Pre-Production: Detta anche Fase di Design è uno step di pianificazione del progetto che si focalizza sull’idea e sul concept e sulla produzione dei primi documenti di design. L’obiettivo del Concept Development è principalmente quello di produrre una documentazione chiara e di facile comprensione, che descriva tutti i compiti, la schedulazione e le stime operative del team di sviluppo. Il corpus dei documenti redatti in questa fase è chiamato Piano di Produzione. Questa fase non è solitamente finanziata dal publisher, anche se i più attenti alla qualità possono richiede agli sviluppatori di sottoporre dei documenti anche durante la pre-produzione. Si compone di varie sotto-fasi:

∗ High Concept: In questa prima fase il prodotto è ancora un’idea da valutare, per comprenderne le potenzialità e i punti deboli e decidere come organizzare il suo futuro sviluppo. Consiste in uno studio di fattibilità, nella stesura di massima di tutte le caratteristiche di gioco seguite da una stima del numero di persone necessarie allo sviluppo e dalla stima dei costi. ∗ Pitch: Conosciuto anche come Concept Document, o Game Proposal, è un breve documento di riepilogo che presenta i punti di forza del prodotto, che

15 16 CAPITOLO 2. IL WORKFLOW

potrebbero attrarre gli utenti, e che spiega perchè il gioco proposto potrebbe essere redditizio una volta sviluppato. Possono non essere scritti, ma solo discussi all’interno dell’azienda. Alcune aziende li usano per richiedere i fondi necessari per lo sviluppo al publisher di riferimento. Questa proposta di gioco può dover superare diversi Green-Light Meetings con gli amministratori delegati del publisher prima di essere approvati ed il gioco finanziato. ∗ Concept: Detto anche Game Plan, è un documento più dettagliato del Pitch, che include complessivamente tutte le informazioni sul gioco. L’High Concept, il genere del gioco, la descrizione del gameplay, le funzionalità, l’ambientazione, la storia, il pubblico del gioco, le piattaforme hardware, la stima dei tempi necessari, analisi di marketing, il personale richiesto, e l’analisi dei rischi, sono tutte le informazioni e i dettagli che si possono trovare in questo documento onnicomprensivo. Prima che venga approvato un determinato design, un piccolo gruppo di programmatori e di artist collaborano per sviluppare piccoli prototipi che mostrano determinate feature chiave che gli stakeholders vorrebbero veder incorporate nel gioco finale. Gli artist invece creano concept art e schizzi da cui poi prenderanno vita i veri asset presenti nel gioco. ∗ Game Design Document: Prima che la produzione su vasta scala possa avere inizio, il team di sviluppo crea la prima versione del Game Design Document che incorpora tutto o la maggior parte del contenuto del Pitch Document. Il Design Document descrive il concept del gioco e le dinamiche di gameplay principali in dettaglio, spesso include anche schizzi preliminari di varie parti del gioco. Questo documento a volte include prototipi funzionali di alcune sezioni del prodotto. Il documento di design continua spesso ad essere migliorato ed incrementato lungo tutto l’arco dello sviluppo complessivo del gioco, venendo modificato settimanalmente o anche giornalmente in alcuni casi. ∗ Prototipo: Creare prototipi di idee di gamplay e di feature è un’attività importante che permette ai programmatori e ai game designer di speri- mentare diversi algoritmi e di casi d’uso per il gioco. Una grossa fetta dell’attività di prototipazione può avere luogo durante la pre-produzione prima che il documento di design sia completo, in modo tale da permettere di determinare quali feature saranno discusse e specificate nel design. La prototipazione durante questo stage e spesso fatta manualmente (su carta) e non utilizzando strumenti digitali, perchè ciò risulta più semplice e rapido da testare e da modificare senza spreco di risorse per idee che potrebbero essere cancellate in seguito. Questa è un’attività che può essere svolta anche contemporaneamente allo sviluppo principale, per testare nuove idee mentre il gioco prende vita. Spesso i prototipi necessitano di essere sviluppati velo- cemente e con veramente poco tempo a disposizione, per questo motivo solo i programmatori più prolifici vengono coinvolti per sviluppare rapidamente questi banchi di prova. Strumenti RAD possono essere utilizzati per velo- cizzare ulteriormente lo sviluppo. Un modello di sviluppo di successo è la prototipazione iterativa, dove il design viene rifinito basandosi sui progressi correnti. 2. Production: La produzione è la fase principale dello sviluppo, quando gli asset ed il codice sorgente per il gioco vengono creati. La produzione è generalmente definita come il periodo di tempo in cui il progetto vede la compartecipazione di 2.1. LE FASI DELLO SVILUPPO 17

tutto lo staff a disposizione. I programmatori scrivono nuovo codice sorgente, gli artist creano nuovi asset di gioco, come le sprite o i modelli 3D (a seconda della tipologia di gioco). Gli ingegneri audio sviluppano effetti sonori e i compositori creano la colonna sonora del gioco. I level designers compongono i livelli, e i writer scrivono i dialoghi per i filmati e per gli NPC. I game designer continuano a sviluppare il design del gioco attraverso tutta la fase di produzione. Anch’essa è composta da diverse sotto-fasi: ∗ Game Design: Il Game Design è un processo essenziale nello sviluppo di un gioco, e collaborativo, che consiste nella progettazione dei contenuti e delle regole di gioco. Richiede competenze sia artistiche che tecniche, nonché di scrittura. La creatività e l’apertura mentale sono vitali per portare a termine un videogioco di successo. Durante lo sviluppo, il game designer implementa e modifica il design del gioco in modo tale che rifletta la visione d’insieme del progetto. Feature e livelli sono spesso modificati, aggiunti o rimossi. Le decisioni artistiche sono in continua evoluzione e la storia anche può essere soggetta a cambiamenti. Nuove piattaforme possono essere aggiunte o il target demografico potrebbe cambiare. Tutti questi cambiamenti devono essere documentati e diffusi attraverso il resto del team. La maggior parte dei cambiamenti avviene come update del Design Document. ∗ Game Programming: La codifica del gioco è gestita da uno o più pro- grammatori, che sviluppano prototipi per testare idee, molte delle quali potrebbero non finire mai a fare parte del gioco finale. I programmatori incorporano le nuove feature richieste dai designer e correggono eventuali bug che dovessero esser stati introdotti durante il processo di sviluppo. Anche se dovesse esser stato scelto l’utilizzo di un motore di gioco già pronto all’uso (di terze parti quindi), una grossa quantità di sviluppo software è necessaria per modificare quasi ogni gioco sul mercato. ∗ Level Design: Da un punto di vista temporale, il primo livello di gioco è quello che richiede più tempo per essere creato. A volte mentre i designer e gli artist utilizzano i tool per assemblare i livelli, si trovano ad avere bisogno di nuove feature e cambiamenti forniti dai tool interni che gli permettono uno sviluppo più rapido e di maggiore qualità. Le nuove feature introdotte potrebbero rendere i vecchi livelli obsoleti, in modo tale da rendere quelli sviluppati velocemente all’inizio scartabili. A causa dell’ambiente di sviluppo dinamico, anche il design dei primi livelli di gioco potrebbe essere soggetto a cambiamenti. Non è raro spendere anche fino a 12 mesi su di un solo livello di gioco prima di completarlo, all’interno di un progetto lungo 3 anni. I livelli successivi possono essere sviluppati più velocemente dato che l’insieme delle feature è più completo e la game vision è più chiara e stabile. ∗ Art Design: E’ il processo di creazione degli aspetti artistici di un video game. Il design della video game art inizia già in fase di pre-produzione. I video game artist sono visual artist coinvolti fin dal concepimento del gioco, che si occupano di creare schizzi approssimativi dei personaggi, degli ambienti, degli oggetti ecc. Questi concept iniziali possono anche essere creati dai game designer prima che il gioco entri nella fase di produzione vera e propria. A volte questi concept design vengono chiamati Programmer Art. Una volta terminati gli schizzi iniziali ed il gioco è pronto per essere portato ad un livello più avanzato di sviluppo, sempre più artist vengono 18 CAPITOLO 2. IL WORKFLOW

coinvolti nel progetto per dare vita a questi schizzi attraverso il Graphic Design. L’Art Design di un gioco può essere gestita da varie persone, più un’azienda è grande più è probabile che diverse persone si occupino di questo ambito. Piccole realtà tendono a non avere tanti artist il che significa che quelli a disposizione devono avere diverse skill a cui poter attingere, mentre in realtà più grandi ogni artist diventa sempre più specializzato. ∗ Audio Production: Il Game Audio si differenzia in tre sotto-categorie: Effetti sonori, musiche e dialoghi. La produzione di Sound Effect consiste nella creazione di nuovi suoni o la modifica di campioni o la replica di suoni presi dal mondo reale. Le musiche possono essere sintetizzate o anche performate live. Ci sono vari modi in cui la musica può essere presentata in un gioco, potrebbe essere ambientale, dove lo scopo è quello di rinforzare l’estetica di gioco ed il game setting. La musica potrebbe essere scatenata da eventi interni al gioco. Per esempio, in giochi come Pac-Man o Super Mario, quando il giocatore ottiene dei power-up viene riprodotto un suono distintivo. Per farsi un’idea, un gioco da 20 ore di campagna single-player può avere anche 60 minuti di colonna sonora. Dialoghi e doppiaggi rendono il gameplay ancora più realistico e coinvolgente, oltre a dare più carattere e personalità ai personaggi. ∗ Testing: Nelle fasi finali dello sviluppo, la Quality Assurance gioca un ruolo fondamentale. I tester cominciano il loro lavoro appena si ha in mano una sezione giocabile. Potrebbe essere un solo livello, o un sottoinsieme qualsiasi delle feature del gioco, basta che sia sufficientemente compatto ed utilizzabile. Inizialmente, testare un gioco richiede relativamente poco tempo. I tester possono lavorare a più di un gioco contemporaneamente. Quando si avvicinano le fasi finali dello sviluppo, testare un unico gioco può richiede vari tester full-time. Il testing è fondamentale per i giochi moderni, che sono particolarmente complessi, dove anche piccole modifiche possono avere effetti catastrofici. In queste fasi, le feature ed i livelli vengono prodotti alla velocità massima e c’è sempre più materiale da testare, più che in qualsiasi altra fase del gioco. I tester portano a termine dei Regression Test per assicurarsi che le feature che sono state introdotte inizialmente continuino ad essere funzionanti. I test di regressione sono un task vitale necessario ad uno sviluppo software efficace. Man mano che nuove feature vengono aggiunte, piccoli cambiamenti alla codebase possono avere effetti collaterali in differenti porzioni del gioco. Questo compito viene spesso sottovalutato, per diverse ragioni. A volte, quando una feature viene implementata e poi testata, viene considerata funzionante e non viene ripetuto il testing più avanti. Inoltre, le feature che vengono aggiunte successivamente sono considerate più prioritarie e quelle già esistenti non vengono testate per un tempo sufficiente. Un Regression Testing adeguato diventa costoso in maniera incrementale in linea con l’incremento nel numero delle feature, e viene spesso schedulato in maniera scorretta. Nonostante i rischi nel testare in maniera non efficace, alcuni game developer e publisher falliscono nel testare tutta la suite di feature e rilasciano giochi contenenti diversi bug. Tutto ciò può provocare il discontento degli utenti finali ed il fallimento nel raggiungere gli obiettivi di vendita del prodotto finale. Quando questo accade, la maggior parte dei developer e dei publisher cerca di fixare i bug velocemente rilasciando delle patch che auspicabilmente rendono il gioco 2.2. LE MILESTONES 19

pienamente giocabile.

3. Post-Production

∗ Mantenimento: Una volta che il gioco viene rilasciato, la fase di mante- nimento ha inizio. I giochi sviluppati per console in passato non avevano quasi nessuna fase di mantenimento. I giochi rilasciati rimanevano per sempre con lo stesso numero di bug e di feature, questo era comune dato che tutte le console avevano praticamente lo stesso hardware. L’incompatibilità non era fonte di bug. In questi casi, il mantenimento avveniva solo in caso di porting, di un sequel, o di un remake che riutilizzava una grande porzione dell’engine di gioco e degli asset. In tempi relativamente recenti la popolarità dei giochi online per console è cresciuta, e sono stati sviluppati servizi online come Xbox Live. Gli sviluppatori possono manutenere il loro software attraverso patch scaricabili. Questi cambiamenti non sarebbero stati possibili in passato senza la diffusione di internet. Lo sviluppo per PC è diverso: Gli sviluppatori devono fronteggiare la grande differenza di configurazioni hardware disponibili. Inoltre, il numero di configurazioni diverse elevato porta inevitabilmente alla scoperta di game-breaking bug che i programmatori ed i tester non avevano previsto. I programmatori attendono per un determinato lasso di tempo che vengano segnalati quanti più bug report, dopodiché, quando ritengono di aver ottenuto sufficienti feedback, cominciano a lavorare ad una patch. La patch può richiedere settimane o mesi interi per essere completata, ma è pensata per risolvere la maggior parte dei bug segnalati ed i problemi del gioco che erano stati ignorati in precedenti code release, e raramente anche quelli introdotti da patch precedenti. Occasionalmente le patch possono introdurre anche featu- re extra e contenuti ed anche alterare il gameplay. Nel caso dei Massively Multiplayer Online Game, come i MMORPG, il rilascio del gioco è l’inizio esatto dell’inizio della fase di mantenimento. Questi giochi sono in manteni- mento continuo dato che il mondo di gioco è continuamente modificato e nuove feature vengono aggiunte. Lo staff che si occupa di questo processo, per un MMOG di successo, può contenere svariate persone, di cui a volte fanno parte alcuni membri originari del team di sviluppo iniziale.

2.2 Le Milestones

Progetti commerciali di sviluppo videogame potrebbero dover soddisfare delle Milestone imposte dal publisher. Le milestone stabiliscono importanti risultati raggiunti durante lo sviluppo del gioco e sono utilizzate per tenere traccia dello stato di progresso raggiunto. Possono essere denominate, per esempio, first playable, alpha, o beta. Le milestone di progetto dipendono dalla schedule di sviluppo. Si basano solitamente su multiple brevi descrizioni delle funzionalità: Un esempio potrebbe essere "il giocatore esplora l’ambiente di gioco" oppure "Fisica, collisioni e veicoli funzionanti" (varie descrizioni sono ammesse). Possono variare in numero, solitamente da 3 a 20, a discrezione degli sviluppatori e dell’editore. La loro lista è un accordo di collaborazione tra le parti in causa (studio e publisher). Lo studio si impegna nel rendere le descrizioni delle milestone brevi e semplici da leggere, ma a seconda del publisher, gli accordi sulle milestone possono diventare anche molto dettagliate per uno specifico gioco. Quando si lavora con un buon publisher, affidabile ed affermato, solitamente se la 20 CAPITOLO 2. IL WORKFLOW milestone è al 90% del suo completamento, lo studio verrà pagato in anticipo come se fosse stata finita, con la promessa che lo diverrà quando la prossima tappa sarà raggiunta. Le spese mensili dello studio sono spesso ingenti e necessitano di essere saldate regolarmente, e le due parti in causa cercano di venirsi in contro in modo da agevolare il raggiungimento degli obiettivi comuni e soddisfare gli interessi di entrambi. Inoltre a volte le milestone vengono scambiate, entrambe le parti potrebbero accordarsi per riorganizzare gli obiettivi in base al cambiamento dei requisiti ed alle risorse a disposizione. Gli accordi presi sulle milestone sono solitamente inclusi anche nella parte legale e contrattuale del rapporto. Conseguita una milestone segue solitamente un accordo di pagamento. Alcuni publisher molto affermati nell’industria potrebbero semplicemente accordarsi in base alla quantità di tempo in cui il gioco è stato in fase di sviluppo (mesi o periodi più lunghi) piuttosto che un insieme specifico di funzionalità di gioco, ma è molto meno comune. Non esiste ancora uno standard aziendale per definire le milestone, che variano di molto in base al publisher, all’anno, ed al progetto in causa. Le milestone più comuni per cicli di sviluppo di circa due anni, sono le seguenti: ∗ First Playable: Questa versione del gioco contiene una parte rappresentativa del gioco e dei suoi asset principali, ed è la prima versione a contenere le parti funzionali principali del gameplay. Si basa spesso sui prototipi creati in fase di pre-produzione. Le Alpha e First Playable sono solitamente utilizzate in riferimento ad un’unica Milestone, mentre in progetti di grandi dimensioni queste due versioni del gioco vengono separate e sono richieste entrambe, è richiesta a volte la First Playable prima di poter ottenere una Alpha con tutte le feature necessarie. La First Playable viene completata dai 12 ai 18 mesi prima del rilascio del codice. Viene chiamata anche "Pre-Alpha" oppure "Proof of Concept". ∗ Alpha: La Alpha è lo stage in cui le feature chiave del gameplay sono state implementate, e gli asset sono parzialmente completati. Un gioco in Alpha è completo di tutte le feature, cioè è giocabile e contiene le feature principali. Queste feature potrebbero essere ulteriormente revisionate in base al testing ed ai feedback. Piccole nuove feature potrebbero venir aggiunte in seguito, pianificate similmente, mentre quelle non implementate potrebbero essere scartate. I programmatori si concentrano principalmente sul completamento della codebase, piuttosto che implementare le nuove aggiunte. Le Alpha vengono completate da 8 a 10 mesi prima del rilascio del gioco, ma queste tempistiche potrebbero variare anche in maniera significativa in base alla dimensione dei contenuti che il progetto del gioco prevede. ∗ Code Freeze: Il Code Freeze è la fase in cui viene terminata l’aggiunta di nuovo codice al gioco e vengono solo risolti bug. Solitamente avviene da 3 a 4 mesi prima della Code Release. ∗ Beta: La Beta è una versione del gioco completa di tutte le feature e degli asset, dove solo ed unicamente bug vengono fixati. Questa versione non contiene bug che impediscono al gioco di essere rilasciabile. Nessun cambiamento viene apportato alle feature di gioco, agli asset, o al codice. Le Beta si posizionano da 2 a 3 mesi prima della Code Release. ∗ Code Release: Detta anche QA Candidate, è lo stage in cui la maggior parte dei bug sono stati già risolti, ed il gioco è pronto per il rilascio o la pubblicazione, e per essere sottoposto alla revisione dei produttori di console. Questa è la versione che viene sottoposta alla verifica completa da parte del reparto QA. La prima 2.2. LE MILESTONES 21

candidata per la Code Release è solitamente pronta da 3 a 4 settimane prima dell’effettiva Code Release.

∗ Submission: In questa fase il gioco è pronto per il rilascio finale, ed il reparto QA è tenuto a confermare le checklist finali del processo di testing prima che il gioco sia effettivamente pronto per la produzione. Prima di procedere oltre, i tester devono provare il gioco nell’ambiente di produzione per assicurarsi che non ci siano bug di nessun genere. Una volta superati tutti i test, si procede alla Submission vera e propria tramite il reparto di publishing, che inoltra una copia del gioco ai console owner (Microsoft, Sony, Nintendo, e da quest’anno anche Google). Per ottenere la definitiva pubblicazione del gioco, esso viene testato secondo le TRC/TCR di ciascuna console. Questa è una fase decisamente delicata in quanto in caso di fallimento bisognerà ripetere la procedura finchè non verranno soddisfatti tutti i requisiti richiesti. Fallire una submission rappresenta una perdita di tempo ed economica. Superato il terzo fallimento le successive submission cominciano ad avere un costo molto ingente e possono pesare molto sul budget dell’azienda. ∗ Gold Master: Una volta che tutti i problemi importanti sono stati risolti, il testing è stato interamente portato a termine con successo, l’equivalente di una Release Candidate può essere approvata dal Publisher responsabile per essere finalmente rilasciata al grande pubblico. Questa è la vera e propria versione finale del gioco da distribuire ai giocatori di tutto il mondo. ∗ Post Release: Ora che il gioco è stato rilasciato, nuovi contenuti possono essere previsti per il futuro, o delle patch per migliorare l’esperienza di gioco o correggere dei bug (cosa che non dovrebbe mai accadere ma putroppo a volte può succedere, specialmente se i ritmi sono serrati ed i giochi vengono sviluppati in tempi troppo ridotti). In base al piano di supporto successivo al rilascio, il team può abbandonare la struttura delle milestone e gestire miglioramenti e aggiunte cadenzate secondo ogni singolo sprint futuro, o creare nuove milestone per la produzione di DLC e di pacchetti di espansione.

Capitolo 3

Unreal Engine: Dalla prospettiva del codice

3.1 Game Engines

I motori di gioco (come UE4) sono dei framework per lo sviluppo dei videogame che aiutano gli studio in tutte le aree centrali della creazione di un gioco. Grafica, audio, logiche; ma anche motore fisico, gestione del gioco online, intelligenza artificiale ed altro. I motori di gioco, o Game Engine, sono diventati sempre più specializzati e complessi nel corso degli anni. Questi framework forniscono gli strumenti chiave e le strutture di cui pressoché ogni gioco ha bisogno, senza che sia necessario reinventare la ruota ogni volta, al costo di memoria e tempo di esecuzione. Questo trade-off è più che giustificato oggi, grazie alla potenza crescente dell’hardware moderno (l’industria dei videogiochi ha sempre fatto da catalizzatore per l’evoluzione della capacità di calcolo, in particolare in ambito grafico) che riesce a gestire questo overhead senza particolari problemi. Una volta, prima dell’arrivo dei giochi 3D, il discorso era diverso; ma oggi l’uso di motori di gioco è diventato non solo di aiuto, ma necessario, vista la crescente complessità ed interdisciplinarietà dei videogiochi moderni. Molti studio fanno uso di questi framework per accelerare i tempi di produzione, mentre alcuni utilizzano ancora i propri motori proprietari, sviluppati internamente alla società (proprio come Milestone stessa, che prima di spostarsi su Unreal Engine aveva il suo motore di gioco interno, chiamato GEM). Ancora una volta ci troviamo di fronte ad un compromesso: Sviluppare un motore di gioco partendo da zero permette di ottimizzare e di adattare il motore alle specifiche necessità richieste dai propri giochi, mentre comprarne uno (o prenderlo "in affitto") permette di risparmiare moltissimo tempo e denaro speso a scrivere codice per creare le funzionalità più di base. I due principali concorrenti in questo settore sono Epic Games con Unreal Engine, e Unity Technologies con l’omonimo Unity. UE4 è un motore estremamente robusto e professionale che è diventato recentemente completamente gratuito ed è stato utilizzato da diverse software house per realizzare giochi del calibro di Batman Arkham City e Bioshock Infinite, giusto per citarne alcuni. Permette agli sviluppatori di utilizzare il sistema dei Blueprint (di cui parleremo più approfonditamente in seguito) grazie al quale i designer possono parametrizzare le funzionalità messe a disposizione dai programmatori e virtualmente costruire un gioco interamente senza scrivere una sola riga di codice (a discapito però delle prestazioni). Offre inoltre una versatilità notevole e la possibilità di

23 24 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

ottimizzare a bassissimo livello fino all’ultimo byte, oltre al controllo completo di ogni funzionalità. Viene adottato sia dagli studio che costruiscono giochi tripla-A come pure dagli amatori e dai piccoli studi che sviluppano giochi Indie. Unity invece, nonostante sia diventato famoso anche per colpa di alcuni progetti fallimentari pubblicati su Steam, ha dato vita a titoli come Assassin’s Creed Identity e Deus Ex: The Fall. Supporta linguaggi ad alto livello come C# e JavaScript, possiede molti tool che permettono a chi dovesse averne bisogno di bypassare la programmazione quasi interamente, nel tempo ha accumulato diversi appassionati e vanta una vasta community di appassionati che creano e mettono a disposizione un grande numero di asset e tutorial gratuiti che possono aiutare moltissimo i giovani creatori. Non a caso è uno dei primi engine a cui fare riferimento per i primi passi in questo mondo.

3.2 Programmare in C++ con Unreal Engine 4 3.2.1 C++ e i Blueprint UE4 supporta due metodi, C++ e il cosiddetto Blueprint Visual Scripting, per creare nuovi elementi di gameplay. Utilizzando C++, il programmatori possono aggiungere al gameplay di base sistemi che poi i designer possono utilizzare per estendere le funzionalità e creare nuove custom feature per ogni livello di gioco. In questi casi i programmatori lavorano utilizzando degli editor di testo o degli IDE (solitamente Visual Studio, che si integra facilmente), mentre i designer utilizzano l’editor dei Blueprint all’interno di UE4. L’API di gameplay ed il framework di classi sono disponibili per entrambi i sistemi menzionati, e possono essere utilizzati separatamente, ma mostrano il loro vero potenziale quando utilizzati in maniera congiunta e complementare. L’engine è stato pensato in modo tale da permettere ai programmatori di scrivere in C++ i blocchi di codice che verrano poi utilizzati dai designer per creare parti di gameplay interessanti e coinvolgenti. Da qui in poi vorrei mostrare un basilare ma tipico workflow, che permetterà ad un designer o ad un programmatore di estendere una classe via codice o tramite i Blueprint. In questa classe creerò alcune proprietà che i designer possono impostare, e deriverò nuovi valori da queste proprietà, utilizzando i tool e le macro messe a disposizione dal framework.

Listing 3.1: Una classe d’esempio

1 #include "GameFramework/Actor.h" 2 #include "MyActor. generated.h" 3 4 UCLASS() 5 class AMyActor : public AActor 6 { 7 GENERATED_BODY() 8 9 public: 10 // Impostai valori di default per le propriet di questo Actor 11 AMyActor(); 12 13 // Viene chiamata ad ogni frame 14 virtual void Tick( float DeltaSeconds ) override; 15 3.2. PROGRAMMARE IN C++ CON UNREAL ENGINE 4 25

16 protected: 17 // Viene chiamata quando parte il giocoo quandol’Actor spawnato 18 virtual void BeginPlay() override; 19 };

Questa classe può essere generata anche utilizzando il wizard interno all’editor di UE4, in questo modo le funzioni BeginPlay e Tick vengono automaticamente specificate come override. BeginPlay è un evento che permette di capire quando l’Actor è stato "spawnato" (creato da UE4 ed inserito nel mondo di gioco) ed è in uno stato giocabile. Questa funzione è un buon posto dove inserire logica di gameplay per la classe in questione. Tick viene chiamata una volta ogni frame con input la variabile DeltaSeconds che contiene il tempo trascorso dall’ultima chiamata fatta precedentemente sempre alla stessa funzione. Qui è possibile inserire della logica ricorrente. Se questa funzionalità non è necessaria, è preferibile evitare di farne l’override per risparmiare una piccola quantità di tempo di esecuzione. Nel caso in cui si decidesse di rimuoverla, è necessario rimuovere la riga di codice nel costruttore che segnala che il ticking avrà luogo. Il costruttore seguente contiene la riga in questione.

Listing 3.2: Costruttore della classe d’esempio

1 AMyActor::AMyActor() 2 { 3 4 // Indica all’Actor di chiamare Tick() ad ogni frame. Pu essere disattivata per migliorare le performance, se necessario. 5 6 PrimaryActorTick.bCanEverTick = true; 7 8 }

Ora che abbiamo creato una classe, possiamo creare alcune proprietà che i designer possono impostare nell’editor. Esporre una proprietà è semplice, e abbiamo bisogno della macro UPROPERTY, all’interno di questa istruzione abbiamo la possibilità di impostare la visibilità, per ora utilizzeremo "EditAnywhere".

Listing 3.3: Rendiamo la proprietà visibile nell’editor

1 UCLASS() 2 class AMyActor : public AActor 3 { 4 GENERATED_BODY() 5 public: 6 7 UPROPERTY(EditAnywhere) 8 int32 TotalDamage; 9 10 ... 11 };

Questo è tutto ciò che serve per essere in grado di modificare il valore della variabile all’interno dell’editor. Ci sono svariati modi per controllare come e dove 26 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

la si potrà modificare, attraverso il passaggio di informazioni all’interno della macro UPROPERTY(). Per esempio, se vogliamo che la proprietà ExposedVariable appaia in una sezione con altre proprietà correlate tra loro, si può usare la categorizzazione. Vediamone un rapido esempio.

Listing 3.4: Categorizzazione delle proprietà

1 UPROPERTY(EditAnywhere, Category="Damage" ) 2 int32 TotalDamage;

Quando l’utente cercherà di modificare questa proprietà, sarà in grado di trovarla sotto la categoria "Salute" insieme ad altre proprietà che sono state identificate con il nome di questa categoria. In questo modo si possono organizzare le variabili in macro categorie che possono rendere la vita più semplice ai designer (o a chi per loro). Ora passiamo ad esporre la stessa proprietà ai Blueprint.

Listing 3.5: Esporre a BP

1 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage" ) 2 int32 TotalDamage;

Come si può vedere, abbiamo aggiunto uno specificatore per rendere l’accesso alla proprietà sia in lettura che in scrittura ai grafi BP. C’è inoltre un altro specificatore, "BlueprintReadOnly", che può essere utilizzato se si vuole che la proprietà venga trattata come una costante nei Blueprint. Ci sono naturalmente molte altre opzioni per controllare in che modo una proprietà viene esposta, queste mostrate sono le più semplici ed intuitive. Vediamo di aggiungere qualche altra proprietà a questa classe, prima di procedere oltre. Abbiamo già una proprietà che stabilisce l’ammontare di danni totali che questo attore può infliggere, possiamo anche aggiungere una nuova variabile che misura anche come questi verranno inflitti in un arco di tempo preciso. Il codice seguente aggiunge una proprietà modificabile dal designer ed un’altra visibile ma non editabile.

Listing 3.6: Come usare gli specificatori

1 UCLASS() 2 class AMyActor : public AActor 3 { 4 GENERATED_BODY() 5 public: 6 7 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage" ) 8 int32 TotalDamage; 9 10 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Damage" ) 11 float DamageTimeInSeconds; 12 13 UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Transient, Category ="Damage" ) 14 float DamagePerSecond; 3.2. PROGRAMMARE IN C++ CON UNREAL ENGINE 4 27

15 16 ... 17 };

DamageTimeInSeconds è una proprietà che il designer può modificare, il cui valore viene calcolato usando i suoi settaggi (vedere in seguito). Lo specificatore VisibleA- nywhere rende la proprietà visibile ma non modificabile. Lo specificatore Transient invece sta a significare che non verrà salvata o caricata dal disco, rappresenta un valore derivato, non persistente, e che quindi non necessita di essere salvato. L’immagine seguente mostra le proprietà nell’insieme dei default della classe.

Figura 3.1: C++ e i Blueprint - Proprietà di default della classe

Settare i valori di default per le proprietà nei costruttori funziona allo stesso modo dello standard C++, in seguito possiamo vedere due esempi di come impostare i valori di default all’interno di un tipico costruttore.

Listing 3.7: Come usare un costruttore

1 AMyActor::AMyActor() 2 { 3 TotalDamage = 200; 4 DamageTimeInSeconds = 1.0f; 5 } 6 7 AMyActor::AMyActor() : 8 TotalDamage(200), 9 DamageTimeInSeconds(1.0f) 10 { 11 }

Possiamo notare che la stessa finestra precedente ora mostra i valori di default impostati all’interno del costruttore.

Figura 3.2: C++ e i Blueprint - Valori di default impostati

Per supportare le proprietà impostate per ogni istanza dai designer, i valori vengono anche caricati dai dati di ogni istanza per un determinato oggetto. Questi dati vengono applicati dopo l’esecuzione del costruttore. Si possono creare dei dati di default che si basano su quelli settati dai designer, utilizzando la catena di chiamate generata 28 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

da PostInitProperties(). Qui in seguito vediamo un esempio di come le proprietà TotalDamage e DamageTimeInSeconds sono state specificate in seguito. Nonostante siano poi settati dai designer, si possono fornire ugualmente dei default value utili, proprio come abbiamo fatto prima.

Figura 3.3: C++ e i Blueprint - Valori caricati dopo il costruttore

Listing 3.8: Settare le proprietà subito dopo il costruttore

1 void AMyActor::PostInitProperties() 2 { 3 Super::PostInitProperties(); 4 DamagePerSecond = TotalDamage / DamageTimeInSeconds; 5 }

Possiamo notare che la finestra che mostra i dati nell’editor dopo aver invocato PostInitProperties() è molto simile a quella vista in precedenza.

Figura 3.4: C++ e i Blueprint - Valori dopo l’invocazione di PostInitProperties()

3.2.2 Estendere una classe C++ tramite Blueprint Fin’ora abbiamo creato una semplicissima classe dimostrativa e abbiamo aggiunto alcune proprietà per i designer. Adesso possiamo esplorare come un designer (o un altro programmatore) può creare classi derivate dalla nostra banale classe base. La prima cosa da provare sarà cambiare i valori di default per le proprietà dei danni generati dall’attore rappresentato dalla classe appena creata, in un ipotetico gioco di combattimento. In questo caso, il designer ha cambiato TotalDamage da 200 a 300 ed il tempo necessario per infliggere tale danno da 1 a 2 secondi. Nell’editor i cambiamenti apportati appariranno in questo modo.

Figura 3.5: Estendere una classe C++ tramite Blueprint - Valori modificati 3.2. PROGRAMMARE IN C++ CON UNREAL ENGINE 4 29

Il calcolo dei danni non corrisponde a quello che ci aspetteremmo. Dovrebbe risultare 150, ma rimane sempre al valore di default, cioè 200. La ragione di questo fatto è che stiamo calcolando i danni al secondo solo dopo che la proprietà è stata inizializzata dal processo di caricamento. Cambiamenti che avvengono a runtime non vengono considerati all’interno dell’editor. C’è una semplice soluzione, l’Engine deve notificare l’oggetto target quando è stato modificato all’interno dell’editor. Il codice seguente mostra come ovviare a questo inconveniente.

Listing 3.9: "Strippare" il codice (dall’inglese "strip out")

1 void AMyActor::PostInitProperties() 2 { 3 Super::PostInitProperties(); 4 5 CalculateValues(); 6 } 7 8 void AMyActor::CalculateValues() 9 { 10 DamagePerSecond = TotalDamage / DamageTimeInSeconds; 11 } 12 13 #ifWITH_EDITOR 14 void AMyActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) 15 { 16 CalculateValues(); 17 18 Super::PostEditChangeProperty(PropertyChangedEvent); 19 } 20 #endif

E’ necessario notare che il metodo PostEditChangeProperty è all’interno di un #ifdef specifico dell’editor. In questo modo fare una build del gioco permette di compilare solo il codice di cui si ha effettivamente bisogno, rimuovendo codice extra che potrebbe aumentare le dimensioni dell’eseguibile inutilmente. Adesso che abbiamo aggiunto e compilato il codice presentato, il valore di DamagePerSecond corrisponde esattamente a ciò che ci aspettiamo, come possiamo vedere nell’immagine seguente.

Figura 3.6: Estendere una classe C++ tramite Blueprint - Valori "DamagePerSecond" aggiornato

3.2.3 Invocare funzioni da C++ ed internamente ai Blueprint Fin’ora abbiamo mostrato come esporre proprietà ai Blueprint, ma abbiamo bisogno di fare decisamente di più. Mentre creano sistemi di gameplay i designer hanno bisogno 30 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

di essere in grado anche di chiamare funzioni scritte dai programmatori. Questi ultimi a loro volta necessitano di poter invocare funzioni implementate attraverso i grafi dei Blueprint. Iniziamo rendendo la funzione creata in precedenza, CalculateValues(), invocabile dai Blueprint. Esporre una funzione è quasi identico ad esporre una proprietà.

Listing 3.10: Funzioni invocabili dai BP

1 UFUNCTION(BlueprintCallable, Category="Damage" ) 2 void CalculateValues();

La macro UFUNCTION gestisce questo meccanismo tramite il sistema di Reflection. L’opzione BlueprintCallable espone la funzione alla BP Virtual Machine. Ogni funzione esposta a BP necessita di avere una categoria associata, in modo tale da integrarsi con l’editor in maniera corretta. Ecco come apparirà nell’editor.

Figura 3.7: Invocare funzioni da C++ ed internamente ai Blueprint - Categorie associate alle funzioni

Come possiamo vedere, la funzione è selezionabile dalla categoria "Damage". Il codice in Blueprint qui sotto mostra un cambiamento nel valore di TotalDamage seguito da una chiamata alla funzione per ricalcolare i dati derivati.

Figura 3.8: Invocare funzioni da C++ ed internamente ai Blueprint - Aggiornamento di "TotalDamage"

Viene utilizzata la stessa funzione aggiunta in precedenza per calcolare le proprietà associate. Gran parte dell’Engine è esposto a BP tramite la macro UFUNCTION(), 3.2. PROGRAMMARE IN C++ CON UNREAL ENGINE 4 31

in modo tale da permettere agli utenti finali di costruire giochi interi senza scrivere codice C++, se fosse necessario. Da notare però che l’approccio migliore per sviluppare sistemi di gameplay di base, e funzionalità dove le performance sono particolarmente critiche, è quello di usare i Blueprint solo per comportamenti custom e di comporre feature utilizzando blocchi di codice C++. Ora che i designer possono invocare la nostra funzione C++, vorrei mostrare un modo più efficace di attraversare i confini tra C++ e i BP. Questo approccio permette di chiamare funzioni definite solo in Blueprint. Questa strategia viene spesso utilizzata per notificare i designer dell’occorrenza di un determinato evento, al quale possono rispondere come più ritengono adeguato. Spesso, questo significa spawnare effetti grafici, o altri comportamenti, come nascondere o rendere visibile un Actor in scena. Il code snippet seguente mostra una funzione implementata tramite BP.

Listing 3.11: Funzioni implementate tramite BP

1 UFUNCTION(BlueprintImplementableEvent, Category="Damage" ) 2 void CalledFromCpp();

Questa funzione viene invocata proprio come qualsiasi altra funzione in C++. Dietro le quinte, Unreal Engine genera un’implementazione di base della funzione C++ che sa come chiamare la BP Virtual Machine. Ci si riferisce a questa componente chiamandola Thunk. Se il Blueprint in questione non dovesse fornire un corpo a questo metodo, allora la funzione si comporterebbe come qualsiasi altra funzione C++ senza corpo: Non fa nulla. Nel caso in cui si volesse fornire un’implementazione di default in C++, lasciando sempre aperta la possibilità di override tramite BP di questo metodo, basta usare un’altra delle opzioni della macro UFUNCTION() fornita da Unreal Engine. Nel prossimo snippet mostro come fare.

Listing 3.12: Funzioni implementabili tramite BP, con implementazione di default in C++

1 UFUNCTION(BlueprintNativeEvent, Category="Damage" ) 2 void CalledFromCpp();

Anche questa versione genera sempre un metodo di Thunking per richiamare la BP Virtual Machine. Quindi come è possibile fornire un’implementazione di default? Il tool genera anche una nuova dichiarazione di funzione che segue questa sintassi: _Implementation(). Bisogna fornire questa versione del- la funzione altrimenti il progetto fallirà la fase di linking. A seguire l’implementazione del codice per la dichiarazione precedente.

Listing 3.13: Funzione invocata dalla Virtual Machine

1 void AMyActor::CalledFromCpp_Implementation() 2 { 3 // Corpo della funzione 4 }

Questa versione della funzione è quella che viene chiamata quando il Blueprint in questione non fa l’override del metodo. 32 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

3.2.4 Le classi di Gameplay: Objects, Actors e Components Il prossimo argomento riguarda come funziona la gerarchia di classi di gameplay, comincerò con i blocchi di base e tratterò di come si interfacciano tra di loro. Oggetto di discussione sarà il modo in cui Unreal Engine usa sia l’ereditarietà che la composizione per costruire feature custom di gameplay. Ci sono 4 tipi di classi principali da cui vengono derivate la maggior parte delle classi di gameplay. Sono UObject, AActor, UActorComponent e UStruct. Un uso tipico delle classi create al di fuori della gerarchia di UObject è di integrare librerie di terze parti, fare wrapping di feature specifiche del Sistema Operativo, e così via.

3.2.5 Unreal Objects I blocchi di base dell’Engine sono denominati UObject. Questa classe, accoppiata a UClass, fornisce parte dei servizi più importanti forniti dal motore:

∗ Proprietà e metodi della Reflection.

∗ Serializzazione delle proprietà.

∗ Garbage Collection.

∗ Trovare un UObject per nome.

∗ Valori configurabili delle proprietà.

∗ Supporto di rete per proprietà e metodi.

Ogni classe che deriva da UObject possiede un singleton di tipo UClass creato per essa che contiene tutti i metadati dell’istanza della classe stessa. UObject e UClass insieme sono alla radice di qualsiasi cosa che un oggetto di gameplay può fare durante il suo ciclo di vita. Il modo migliore per capire la differenza tra una UClass e un UObject è pensare che UClass descrive come un’istanza di UObject appare, quali sono le proprietà disponibili ad essere serializzate, il supporto di rete, e così via. La maggior parte dello sviluppo non comprende derivare direttamente da un UObject, ma da un AActor o un UActorComponent. Non serve sapere precisamente come UClass e UObject funzionano nei dettagli, per poter scrivere codice funzionante, ma è bene perlomeno sapere che questi sistemi esistono.

3.2.6 AActor Un AActor è un UObject che è considerato parte dell’esperienza di gameplay. Gli attori sono piazzati in un livello dai designer o creati a runtime dai sistemi di gameplay. Tutti gli oggetti che sono piazzati in un livello derivano da questa classe base. Alcuni esempi sono AStaticMeshActor, ACameraActor, APointLight. Dal momento che AActor deriva da UObject, possiede tutte le feature standard elencate nella sezione precedente per gli UObject. Gli actor possono essere distrutti esplicitamente attraverso il codice di gameplay (C++ oppure BP) o dal meccanismo standard di Garbage Collection quando il livello che li possiede viene rimosso dalla memoria principale. Gli attori sono responsabili per i comportamenti ad alto livello degli oggetti del gioco. AActor è anche il tipo base che può essere replicato durante l’online. Durante la Network Replication, gli attori possono distribuire informazioni per qualsiasi UActorComponent che possiedono, che richiede supporto di rete o sincronizzazione. Gli attori hanno i propri 3.2. PROGRAMMARE IN C++ CON UNREAL ENGINE 4 33 comportamenti (specializzazione tramite ereditarietà), ma agiscono anche da contenitori per la gerarchia di Actor Components (specializzazione tramite composizione). Tutto ciò viene realizzato tramite la variabile RootComponent dell’attore, che contiene un unico USceneComponent che a sua volta può contenerne molti altri. Prima che un AActor possa essere posizionato in un livello, deve contenere almeno un componente di scena, dal quale l’attore prenderà la sua posizione vettoriale, rotazione, e scalatura. Gli AActor hanno una serie di eventi associati che vengono invocati durante il loro ciclo di vita. La lista seguente è un insieme semplificato degli eventi che specificano il ciclo di vita: ∗ BeginPlay: Chiamato quando un Actor viene per la prima volta spawnato duranto il gameplay. ∗ Tick: Chiamato una volta sola per ogni frame, per occuparsi di compiti distribuiti lungo un lasso di tempo variabile. ∗ EndPlay: Chiamato quando l’oggetto sta lasciando lo spazio di gioco.

Runtime Lifecycle Abbiamo appena finito di parlare di un sottoinsieme del ciclo di vita di un Actor. Per gli AActor che sono stati spawnati in un livello, immaginare come funziona il ciclo di vita non è difficile: Gli attori vengono caricati ed esistono finchè il livello non viene rimosso dalla memoria e i suoi attori distrutti. Spawnare un attore è leggermente più complicato di creare un normale oggetto nel gioco, proprio perchè gli attori necessitano di essere registrati in una serie di sistemi runtime in modo tale da poter essere gestiti correttamente. La posizione iniziale e la rotazione iniziale di un Actor devono essere impostati. Il motore fisico necessita di queste informazioni fondamentali per fare il suo lavoro nella maniera prevista. Il manager responsabile di avvertire l’Actor di lanciare il Tick deve essere a conoscenza della sua esistenza. Eccetera eccetera. A causa di questo, esiste un metodo che ha la responsabilità di spawnare un Actor, SpawnActor(), che è un membro di UWorld. Quando un attore viene spawnato con successo, l’Engine chiamerà il suo metodo BeginPlay(), seguito da Tick() durante il frame successivo. Una volta che un AActor ha terminato il suo ciclo di vita, possiamo sbarazzarcene chiamando Destroy(). Durante questo processo, EndPlay() verrà eseguito, permettendo al programmatore di far girare della logica custom prima che l’Actor venga eliminato dal Garbage Collector. Un’altra opzione per stabilire quanto dovrà esistere un AActor è quella di usare la sua proprietà LifeSpan. Questa può essere settata nel suo costruttore o attraverso altre chiamate a runtime. Una volta che il tempo è stato esaurito, l’attore verrà automaticamente distrutto con una chiamata a Destroy().

3.2.7 UActorComponent I componenti degli attori (la classe UActorComponent) sono solitamente responsa- bili delle funzionalità condivise tra vari attori, come fornire Mesh osservabili, effetti particellari, prospettive delle telecamere, ed interazioni del motore fisico. Mentre gli Actor sono spesso legati ad obiettivi ad alto livello funzionali al loro ruolo all’interno del gioco, i componenti degli attori solitamente svolgono compiti individuali che supportano questi obiettivi di più alto livello. I componenti possono a loro volta avere attaccati altri componenti, oppure possono essere il RootComponent di un attore. Un componente può solo avere un parent component o un attore, ma potrebbero avere altri componenti collegati a loro stessi, in una struttura ad albero. Componenti figli hanno posizione, 34 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE rotazione e scalatura relativi al loro componente padre o al loro attore. Dato che ci sono vari modi per usare attori e componenti, un modo di immaginarsi la relazione attore-componente è quella di domandarsi "che cosa è questo?" per gli attori, mentre "di che cosa è fatto questo?" per i componenti. Il RootComponent è il membro di un AActor che contiene il componente radice nell’albero dei componenti dell’attore stesso. I componenti ricevono il Tick() una volta che il loro owner Actor lancia la funzione Tick(). Per permetterci di visualizzare meglio queste relazioni, proviamo ad analizzare uno degli elementi standard forniti da Unreal Engine in uno dei progetti base che permettono di prendere dimestichezza con tutta l’impalcatura: Il FirstPersonCharacter. Le immagini seguenti ci mostrano l’albero dei componenti per il personaggio in prima persona.

Figura 3.9: UActorComponent - Albero dei componenti

Il RootComponent è il CapsuleComponent. Attaccato al CapsuleComponent ci sono l’ArrowComponent, la MeshComponent e il FirstPersonCameraComponent. Il com- ponente foglia è "Mesh1P", che è imparentato con il FirstPersonCameraComponent, a significare che la mesh è relativa alla camera in prima persona. Questo albero di componenti è attaccato ad una sola istanza di attore. Come possiamo vedere dall’e- sempio, si possono costruire oggetti di gameplay anche molto complessi usando sia l’ereditarietà che la composizione. L’uso dell’ereditarietà è suggerito quando si vuole customizzare un AActor o un UActorComponent, mentre l’uso della composizione è utile quando diversi AActor condividono la stessa funzionalità.

3.2.8 UStruct

Per usare una UStruct, non serve derivare da qualche classe particolare, ma basta apporre la macro USTRUCT() ad una semplice struttura C++ e i tool di build di Unreal Engine fanno il lavoro di base per noi. A differenza degli UObject, le instanze di UStruct non vengono collezionate dal Garbage Collector. Se si creano istanze dinamiche, bisogna gestire manualmente il loro ciclo di vita. Una UStruct dovrebbe contenere dati semplici che abbiano il supporto della Reflection fornita dagli UObject, manipolazione da parte dei Blueprint, serializzazione, supporto di rete e via dicendo. 3.3. UNREAL REFLECTION SYSTEM 35

Figura 3.10: UActorComponent - I componenti nell’editor

3.3 Unreal Reflection System

Le classi di gameplay utilizzano uno speciale mark-up, prima di analizzarle, diamo un’occhiata ad alcune delle basi del sistema di proprietà di Unreal Engine. UE4 utilizza la sua stessa implementazione della Reflection per rendere disponibile feature dinamiche come il Garbage Collector, la serializzazione, la replicazione di rete, e la comunicazione tra C++ e Blueprint. Queste feature sono "opt-in", cioè bisogna aggiungere il mark-up correttamente ai propri tipi custom, altrimenti Unreal li ignorerà e non genererà i dati di Reflection in maniera prevista. Ecco una breve e sintetica overview del mark-up: ∗ UCLASS(): Utilizzato per indicare ad Unreal di generare i dati di Reflection per la classe. Questa classe deve derivare da UObject. ∗ USTRUCT(): Utilizzato per indicare ad Unreal di generare i dati di Reflection 36 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

per la struttura. ∗ GENERATED_BODY(): Unreal rimpiazza questa macro con tutto il codice boilerplate che viene generato per il tipo in questione. ∗ UPROPERTY(): Abilita una variabile membro di una UClass o di una UStruct per essere utilizzata come UPROPERTY. Una UPROPERTY può avere vari usi. Può permettere alla variabile di essere replicata, serializzata, e di essere letta tramite Blueprint. Serve anche al Garbage Collector per tenere traccia di quanti riferimenti ci sono ad un determinato UObject. ∗ UFUNCTION(): Abilita il metodo di classe di una UClass o di una UStruct ad essere usato come UFUNCTION. Una UFUNCTION può permettere al metodo così determinato di essere chiamato dai Blueprint o usato come Remote Call Procedure. Ecco un esempio di dichiarazione di una UClass:

Listing 3.14: Dichiarazione paradigmatica di UClass

1 #include "MyObject. generated.h" 2 3 UCLASS(Blueprintable) 4 class UMyObject : public UObject 5 { 6 GENERATED_BODY() 7 8 public: 9 MyUObject(); 10 11 UPROPERTY(BlueprintReadOnly, EditAnywhere) 12 float ExampleProperty; 13 14 UFUNCTION(BlueprintCallable) 15 void ExampleFunction(); 16 };

Possiamo notare l’inclusione di "MyObject.generated.h" alla riga #1, UE4 genera tutti i dati di Reflection e li mette in questo file. E’ necessario includerlo, come ultima inclusione nell’header file che dichiara il tipo custom. I mark-up di UClass, UPRO- PERTY e UFUNCTION visti in questo esempio includono specificatori addizionali. Questi non sono necessari, ma sono stati aggiunti a scopo dimostrativo, e permettono di determinare alcuni comportamenti e proprietà particolari. ∗ Blueprintable: Questa classe può essere estesa da un Blueprint. ∗ BlueprintReadOnly: Questa proprietà può essere letta da un Blueprint, ma non scritta. ∗ EditAnywhere: Questa proprietà può essere editata tramite una finestra delle proprietà, su Archetipi e istanze. ∗ Category: Definisce sotto quale sezione questa proprietà apparirà nella finestra dei dettagli dell’Editor. Ha scopo organizzativo. ∗ BlueprintCallable: Questa funzione può essere chiamata da un Blueprint. 3.4. OBJECT/ACTOR ITERATORS 37

3.4 Object/Actor Iterators

Gli iteratori di oggetti sono dei tool molto utili per iterare su tutte le istanze di un particolare tipo di UObject e su tutte le sue sottoclassi.

Listing 3.15: Iteratore di UObject generico

1 // TrovaTUTTE le istanze correnti di UObject 2 for (TObjectIterator It; It; ++It) 3 { 4 UObject* CurrentObject = *It; 5 UE_LOG(LogTemp, Log, TEXT("Found UObject named:%s" ),* CurrentObject->GetName()); 6 } Naturalmente si può limitare lo scope della ricerca fornendo un tipo più specifico all’iteratore. Supponendo di avere una classe di nome UMyClass che deriva da UObject. Si possono trovare tutte le istanze di questa classe, e quelle derivate, in questo modo:

Listing 3.16: Iteratore di UObject specifico

1 for (TObjectIterator It; It; ++It) 2 { 3 //... 4 } Gli iteratori di attori funzionano nella stessa maniera degli iteratori di oggetti, ma funzionano solo con oggetti che derivano da AActor. Gli iteratori di attori non hanno i problemi sovramenzionati, e ritornano unicamente oggetti che sono correntemente in uso dalla Game World Instance. Quando si crea un Actor Iterator, bisogna fornirgli un puntatore all’istance di UWorld. Molte classi UObject, come APlayerController, forniscono un metodo GetWorld() che può tornare utile a questo scopo. Se non si è sicuri, si può controllare il metodo ImplementsGetWorld() su un UObject per vedere se implementa oppure no il metodo in questione.

Listing 3.17: Utilizzo di GetWorld()

1 APlayerController* MyPC = GetMyPlayerControllerFromSomewhere(); 2 UWorld* World = MyPC->GetWorld(); 3 4 // Like object iterators, you can providea specific class to get only objects that are 5 // or derive from that class 6 for (TActorIterator It(World); It; ++It) 7 { 8 //... 9 }

3.5 Gestione della memoria e Garbage Collection

In questa sezione vediamo più da vicino la gestione base della memoria ed il Garbage Collection System di UE4. 38 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

3.5.1 Garbage Collection e UObject Unreal Engine 4 utilizza il sistema di Reflection per implementare il Garbage Collection System. Grazie alla garbage collection, non è più necessario gestire manualmente l’eliminazione delle istanze di UObject, basta fare attenzione a mantenere sempre un riferimento valido a queste ultime. Le classi custom necessitano di derivare da UObject per essere abilitate alla Garbage Collection. A seguire un semplice esempio di classe che può essere gestita da questo sistema:

Listing 3.18: Classe che può essere gestita dal GC

1 UCLASS() 2 class MyGCType : public UObject 3 { 4 GENERATED_BODY() 5 };

Nel Garbage Collector c’è un concetto chiamato Root Set. Il Root Set è una lista di oggetti che il collettore conosce e che non verranno mai rimossi. Un oggetto non viene eliminato finché esiste un percorso di riferimenti da un oggetto nel Root Set fino all’oggetto in questione. Qualora non dovesse esistere nessun percorso, l’oggetto viene definito irraggiungibile e verrà eliminato dal Garbage Collector la prossima volta che esso sarà in esecuzione. L’Engine chiama il Garbage Collector in determinati lassi di tempo prestabiliti. Ogni puntatore ad un UObject salvato in una UPROPERTY o in una classe container di UE4 (come per esempio TArray) è considerato un "riferimento" valido per il Garbage Collector. Cominciamo con un breve esempio:

Listing 3.19: Esempio di oggetto escluso dal Root Set

1 void CreateDoomedObject() 2 { 3 MyGCType* DoomedObject = NewObject(); 4 }

La funzione sovramenzionata crea un nuovo UObject, ma non salva nessun puntatore in nessuna UPROPERTY o in alcun contenitore, e quindi non entra a far parte del Root Set. Prima o poi il Garbage Collector lo scoverà e si renderà conto che non è raggiungibile, eliminandolo successivamente.

3.5.2 Garbage Collection e AActor Gli attori non sono solitamente eliminati dal Garbage Collector, ad esclusione fatta per la teminazione di un livello. Una volta spawnati, bisogna per forza chiamare Destroy() per rimuoverli dal livello senza terminare quest’ultimo. Saranno eliminati dal gioco immediatamente, e successivamente rimossi completamente durante la prossima fase del Garbage Collector. Il seguente è un caso d’uso più comune, in cui ci sono attori con proprietà contenenti UObject:

Listing 3.20: Esempio di oggetti con o senza riferimenti validi per il GC

1 UCLASS() 2 class AMyActor : public AActor 3.5. GESTIONE DELLA MEMORIA E GARBAGE COLLECTION 39

3 { 4 GENERATED_BODY() 5 6 public: 7 UPROPERTY() 8 MyGCType* SafeObject; 9 10 MyGCType* DoomedObject; 11 12 AMyActor (const FObjectInitializer& ObjectInitializer) 13 : Super(ObjectInitializer) 14 { 15 SafeObject = NewObject(); 16 DoomedObject = NewObject(); 17 } 18 }; 19 20 void SpawnMyActor(UWorld* World, FVector Location, FRotator Rotation ) 21 { 22 World->SpawnActor(Location, Rotation); 23 }

Quando viene chiamata la funzione sovracitata, spawniamo un attore all’interno del mondo di gioco. Il costruttore dell’Actor crea due oggetti. Uno lo assegna alla UPROPERTY, mentre l’altro ad un semplice puntatore. Dato che gli attori sono automaticamente parte del Root Set, SafeObject non verrà rimosso perchè può essere raggiunto a partire da un oggetto del Root Set. DoomedObject invece non gode dello stesso trattamento. Non lo abbiamo marcato con UPROPERTY, quindi il Garbage Collector non sa che è puntato da una variabile, e quindi prima o poi lo rimuoverà, lasciando indietro un dangling pointer. Quando un oggetto viene rimosso dal GC, tutte i riferimenti contenuti in UPROPERTY verranno impostati a nullptr. Questo rende safe fare un check se un certo oggetto è stato collectato oppure no.

Listing 3.21: Null-check di una UPROPERTY dopo il passaggio del GC

1 if (MyActor->SafeObject != nullptr) 2 { 3 // Use SafeObject 4 }

Questo passaggio è importante, come menzionato prima, dato che gli attori su cui è stato chiamato Destroy() non sono rimossi finché il Garbage Collector torna attivo. Si può anche controllare che il metodo IsPendingKill() per sapere se un UObject è in attesa di essere rimosso. Se il metodo in questione ritorna true, bisogna considerare l’oggetto disabilitato ed assolutamente non utilizzarlo.

3.5.3 Riferimenti a Non-UObject Oggetti normali di classi C++ (che non derivano da UObject) possono a loro volta avere la possibilità di essere referenziati da un UObject e di prevenire di essere rimossi dal Garbage Collector. Per fare ciò, l’oggetto custom deve derivare da FGCObject e fare l’override del suo metodo AddReferencedObjectsClass(). Ecco un esempio pratico: 40 CAPITOLO 3. UNREAL ENGINE: DALLA PROSPETTIVA DEL CODICE

Listing 3.22: Garbage Collection Prevention di oggetti custom

1 class FMyNormalClass : public FGCObject 2 { 3 public: 4 UObject* SafeObject; 5 6 FMyNormalClass(UObject* Object) 7 : SafeObject(Object) 8 { 9 } 10 11 void AddReferencedObjects(FReferenceCollector& Collector) override 12 { 13 Collector.AddReferencedObject(SafeObject); 14 } 15 };

Utilizziamo FReferenceCollector per aggiungere manualmente un hard reference allo UObject che ci serve e che non vogliamo venga rimosso. Quando l’oggetto viene rimosso e il suo distruttore eseguito, verranno automaticamente pulite tutti i riferimenti che esso ha aggiunto.

3.6 Prefissi per la nomenclatura delle classi

Unreal Engine fornisce i tool che generano il codice per noi programmatori durante il processo di build. Questi strumenti hanno alcune convenzioni per la nomenclatura delle classi che sono da rispettare, pena il sollevamento di warning o di errori in compilazione se i nomi non corrispondono alle aspettative. La lista dei prefissi per le classi qui sotto è sufficientemente esaustiva e permette di ottenere sempre codice che (perlomeno) compila.

∗ Classi che derivano da AActor devono avere prefisso -A, come per esempio AController. ∗ Classi che derivano da UObject devono avere prefisso -U, come per esempio UComponent. ∗ Gli enum necessitano del prefisso -E, come EFortificationType.

∗ Le classi interfaccia sono solitamente precedute dal carattere -I, come ad esempio IAbilitySystemInterface. ∗ Le classi templetizzate hanno prefisso -T, come i container TArray, TMap e TSet. ∗ Le classi che derivano da SWidget (appartenenti a Slate UI ) vengono precedute da -S, come SButton. ∗ Qualsiasi altra classe ha prefisso -F, come FVector. Capitolo 4

Unreal Engine: Dalla prospettiva dei Blueprint

4.1 Il sistema dei Blueprint

Il Blueprint Visual Scripting System di Unreal Engine è un sistema completo di scripting, che si basa sull’utilizzo di un’interfaccia grafica caratterizzata da grafi composti da nodi, che permettono di creare elementi del gameplay di gioco, all’interno dell’editor di Unreal. Come prassi comune di molti linguaggi di scripting, viene fatto uso di classi e oggetti definite dal paradigma OO (Object Oriented) all’interno dell’Engine. Mentre si fa uso di UE4, si ha spesso a che fare con oggetti definiti utilizzando i Blueprint. Questo sistema è estremamente flessibile e potente e fornisce ai designer la possibilità di utilizzo di virtualmente qualsiasi concetto e strumento disponibile ai programmatori. Inoltre il mark-up specifico dei Blueprint disponibile nell’implementazione in C++ di Unreal Engine permette ai programmatori di creare dei sistemi di base che possono essere facilmente estesi dai designer. Nella loro forma base, i Blueprint sono script visualizzabili dall’editor, che forniscono nuove funzionalità al gioco. Connettendo nodi, eventi, funzioni e variabili tramite pin e collegamenti, è possibile creare elementi complessi per sviluppare meccaniche di gioco. I Blueprint funzionano utilizzando grafi composti da nodi che adempiono svariati compiti, costruzione di oggetti, funzioni individuali, ed eventi generali di gameplay, che sono specifici per ogni istanza di Blueprint, in modo da implementare comportamenti e le più disparate funzionalità. Le classi Blueprint sono ideali per rendere interattivi gli asset, come porte, interruttori, item collezionabili, e oggetti di scena distruggibili. Diamo ora un’occhiata ai concetti, ai grafi e ai nodi principali che si hanno a disposizione nell’editor, con l’obiettivo di farci un’idea generale e di mostrare la transizione dalla sintassi base di C++ a quella dei BP.

4.1.1 Il Blueprint Editor Un gioco sviluppato in Unreal Engine contiene vari Actor che interagiscono l’uno con l’altro, per esempio giocatori, nemici ed oggetti che possono essere raccolti e collezionati. In UE4 l’editor di Blueprint può anche essere utilizzato per creare nuovi attori da inserire nel gioco. L’immagine seguente mostra il BP "ThirdPersonCharacter" presente nel template "ThirdPerson" appartenente alla libreria di default di Unreal, già aperto

41 42CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT nell’editor con le tab "MyBlueprint" e "EventGraph" visibili.

Figura 4.1: Editor dei Blueprint

La tab "MyBlueprint" mostra le variabili, le macro, le funzioni ed i grafi del Blueprint. Events ed Actions sono definiti nella tab "EventGraph" che determina suo comporta- mento all’interno del gioco. Nella tab "Components" si possono aggiungere vari tipi di componenti che saranno parte del Blueprint corrente. Per esempio qui abbiamo la mesh, l’illuminazione, il suono, forme geometriche utilizzate nei test delle collisioni, e via dicendo. La tab "Viewport" contiene la rappresentazione visiva dei componenti. La tab "Details" mostra le proprietà dell’elemento corrente selezionato in modo tale da permetterne le modifiche. La barra degli strumenti in cima alla finestra dell’editor ha dei bottoni fondamentali che permettono di editare l’oggetto in questione:

∗ Compile: E’ necessario compilare il BP per rendere valide le modifiche apportate.

∗ Save: Necessario per salvare lo stato corrente dell’oggetto BP.

∗ Class Settings: Contiene le proprietà del Blueprint come la descrizione, la categoria e la classe padre.

∗ Class Defaults: Permette di modificare i valori iniziali (i defaults) delle variabili.

4.1.2 Le Variabili Le variabili vengono utilizzate per immagazzinare i valori degli attributi dei BP che possono essere modificati durante l’esecuzione del gioco. Per creare delle variabili dobbiamo utilizzare il tab "MyBlueprint" e premere sul tasto con il simbolo "+" vicino alla categoria "Variables". L’immagine seguente mostra la suddetta tab ed alcuni dei tipi di variabile che esistono all’interno dell’Engine. 4.1. IL SISTEMA DEI BLUEPRINT 43

Figura 4.2: Le Variabili - Tipi di variabili

I tipi più basilari delle variabili sono:

∗ Boolean: Una variabile booleana che può contenere i valori true oppure false.

∗ Integer: Un tipo di variabile che contiene numeri interi.

∗ Float: Variabile che contiene numeri con la virgola.

∗ String/Text: Questi tipi contengono delle stringhe. In particolare il tipo Text supporta l’internazionalizzazione.

Nell’immagine seguente mostro come viene creata una variabile Integer con nome "AmmoBox". Questa variabile può essere utilizzata all’interno di un BP e rappresenta una cassetta di munizioni. Il suo valore indica il numero di munizioni che il giocatore può ricevere. L’opzione "Editable" selezionata rappresenta che la variabile può essere modificata all’interno dell’editor dei livelli. Il valore di default è 20, ma i level designer possono facilmente modificare la quantità di munizioni successivamente all’interno del livello di gioco.

4.1.3 Gli Eventi Unreal Engine utilizza gli Events per mandare messaggi agli Actors, i quali sono oggetti che possono essere aggiunti ai livelli. Gli script che possiamo creare all’interno dei BP sono delle Action che vengono eseguite in risposta a determinati Events che vengono generati dal motore di gioco durante il gameplay. Per visualizzare gli eventi disponibili, è necessario espandere la categoria "Add Event". In questa categoria sono presenti delle sotto-categorie che raggruppano eventi correlati come possiamo osservare nell’immagine qui in basso.

A seguire una breve descrizione degli eventi principali disponibili:

∗ Collision Events: Vengono attivati quando due attori entrano in collisione o si sovrappongono. 44CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT

Figura 4.3: Le Variabili - Creazione di una variabile

Figura 4.4: Gli Eventi - Categorie di Eventi

∗ Mouse Events: Vengono attivati quando l’utente preme e rilascia i tasti del mouse o quando il cursore passa sopra un determinato attore.

∗ Custom Events: Sono nuovi eventi che possiamo creare all’interno dei Blueprint.

∗ Event Begin Play: Viene attivato quando il gioco comincia per l’attore a cui si riferisce l’evento.

∗ Event Destroyed: Viene attivato quando un attore sta per essere rimosso dal gioco.

∗ Event Tick: Viene attivato ad ogni frame del gioco. Per esempio, se il gioco gira a 60 frame per secondo, questo evento sarà attivato per 60 volte in un secondo. 4.1. IL SISTEMA DEI BLUEPRINT 45

Si possono aggiungere diversi tipi di eventi all’interno del cosiddetto "EventGraph", ma ogni evento con lo stesso nome deve naturalmente essere unico. L’immagine seguente mostra alcuni esempi di eventi che sono stati aggiunti al grafo degli eventi ma non hanno ancora nessuna Action associata.

Figura 4.5: Gli Eventi - Eventi d’esempio

4.1.4 Le Azioni Le Actions vengono utilizzate per definire i comportamenti di un BP. Le azioni vengono sempre originate da un evento. Le azioni principali sono cambiamenti delle variabili di un BP o la chiamata di funzioni che cambiano lo stato degli attori. Per esempio, possiamo immaginare che un BP ha una variabile intera con nome "Ammo". Per inizializzare questa variabile al valore 50 all’inizio del gioco possiamo usare l’evento "Begin Play".

Figura 4.6: Le Azioni - Inizializzazione con BeginPlay

Ogni evento può essere aggiunto una volta sola all’interno del grafo degli eventi. Per utilizzare più di una Action per un evento specifico è necessario mettere le azioni in sequenza. L’immagine seguente mostra l’inizializzazione di due variabili.

Figura 4.7: Le Azioni - Inizializzazione di due variabili

Le funzioni permettono ai valori di essere scambiati tramite l’uso dei parametri. La maggior parte delle funzioni ha un parametro chiamato Target. Questo parametro 46CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT indica l’attore modificato dalla funzione. Il valore di default di questo parametro è Self che è un riferimento speciale all’Actor che possiede lo script in esecuzione. Le immagini seguenti mostrano modi diversi di utilizzare il parametro Target della funzione "De- stroyActor" quando un evento di tipo "Overlap" viene attivato. Nell’ultimo esempio, l’attore che verrà distrutto è quello che viene referenziato dalla variabile "ItemBP".

Figura 4.8: Le Azioni - Distruzione di "Self"

Figura 4.9: Le Azioni - Distruzione di "Other"

Figura 4.10: Le Azioni - Distruzione di "ItemBP"

4.1.5 Eventi Custom In aggiunta agli eventi forniti da Unreal Engine, possiamo creare dei nuovi Events che possono essere utilizzati all’interno dei Blueprint dove l’evento stesso è stato creato, 4.1. IL SISTEMA DEI BLUEPRINT 47 oppure da altri BP. Per creare un evento custom, bisogna espandere la categoria "AddEvent" e selezionare "Add Custom Event ...". Nella tab "Details" si possono settare il nome dell’evento ed i parametri in ingresso. Gli eventi non hanno output. L’immagine seguente mostra un evento chiamato "AddScore" che riceve un determinato numero di punti che vanno aggiunti al punteggio corrente.

Figura 4.11: Eventi Custom - Aggiunta di un nuovo Evento

Figura 4.12: Eventi Custom - Configurazione Evento Custom

Partendo dall’assunto che questo evento è stato creato in un BP di nome "BP_Player", l’immagine seguente mostra come l’evento viene invocato in un altro BP che rappresenta un oggetto che conferisce dei punti quando viene collezionato. L’azione "Cast To" è utilizzata per assicurarsi che è stato proprio il "BP_Player" a collidere con l’oggetto, ed anche per ottenere un riferimento di tipo "BP_Player" per poter accedere all’evento "AddScore".

Notiamo che un evento possiede un piccolo quadratino rosso nell’angolo in alto a destra del suo nodo, chiamato Delegate, che rappresenta un riferimento all’evento stesso. Alcune Action ricevono un evento come parametro ed è utilizzando un Delegate che questo è reso possibile. Nell’esempio sottostante il Delegate dell’evento "Clock" viene 48CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT

Figura 4.13: Eventi Custom - Custom Event "AddScore"

Figura 4.14: Eventi Custom - "Cast To" Action

utilizzato nell’azione "Set Timer By Event", in modo tale da permettere all’evento "Clock" di essere chiamato ogni secondo.

Figura 4.15: Eventi Custom - Caso d’uso di "Set Timer By Event" 4.1. IL SISTEMA DEI BLUEPRINT 49

4.1.6 Le Funzioni Le funzioni permettono ad un insieme di azioni di essere eseguite in varie sezioni del Blueprint e di essere raggruppate in un unico posto per una più semplice organizza- zione e mantenimento dello script. Le funzioni possono essere invocate da altri BP e permettono l’utilizzo di parametri di output e di input. L’esempio seguente mostra la creazione di una funzione di nome "EnemiesLeft" che ha un parametro di output chiamato "NumEnemies". Questa funzione è stata marcata come "Pure", e quindi non avrà dei pin di esecuzione. Le funzioni pure non sono abilitate a modificare le variabili del loro Blueprint.

Figura 4.16: Le Funzioni - Aggiunta di una nuova Funzione

Figura 4.17: Le Funzioni - Configurazione di una Funzione

Le funzioni permettono l’uso di variabili locali che sono visibili solo all’interno della funzione stessa. Queste sono molto utili nell’assistere funzioni complesse e non si mischiano alle altre variabili del Blueprint. La funzione "EnemiesLeft" è stata creata in un BP di nome "Enemy Manager" che è responsabile della gestione dei nemici del gioco. Il suo scopo è di ritornare il numero di nemici che sono rimasti in base alla classe del nemico che è contenuta nella variabile "CurrentEnemyClass". 50CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT

Figura 4.18: Le Funzioni - Esempio di funzione: "EnemiesLeft"

4.1.7 Gli Array Utilizzare gli array permette di raggruppare variabili dello stesso tipo. Creare un array all’interno di un Blueprint è piuttosto semplice ed intuitivo, basta creare una nuova variabile e sceglierne il tipo. Vicino al tipo della variabile c’è un’icona che necessita di essere cliccata per rendere quella variabile un array. Dopo aver compilato il BP è possibile aggiungere dei valori di default all’array, come si può vedere nelle immagini seguenti.

Figura 4.19: Gli Array - Trasformazione di una variabile in un Array

Figura 4.20: Gli Array - Popolamento di un Array

In questo esempio ho creato un array di nome "LevelBonus" che mantiene i punteggi extra che il giocatore può riceve quando completa un determinato livello. Ogni elemento dell’array rappresenta un livello in particolare. Bisogna notare che il primo elemento di un array, proprio come ci aspetteremmo, ha indice zero. La Action qui sotto mostra come aggiungere dei punteggi extra al punteggio del giocatore. La variabile intera 4.1. IL SISTEMA DEI BLUEPRINT 51

"CurrentLevel" rappresenta il livello corrente del gioco ed è utilizzata come indice dell’array e ci permette di ottenere il punteggio equivalente al livello selezionato.

Figura 4.21: Gli Array - Caso d’uso: Calcolo del punteggio

4.1.8 Le Struct Una Struct può essere utilizzata per raggruppare in uno stesso posto diverse variabili. Le variabili che appartengono ad una struttura possono essere di tipo diverso (a diffe- renza degli Array). Si possono inoltre avere delle Struct che ne contengono altre in maniera annidata, o che contengono degli array. Per creare una nuova Struct, bisogna cliccare il tasto "Add New" nel sotto-menu "Blueprints" sotto "Structure". Doppio click sulla struttura che è stata creata per modificarla. Premere "New Variable" per aggiungere delle variabili alla struttura.

Figura 4.22: Le Struct - Popolamento di una Struct

Come esempio creerò una variabile che rappresenta l’inventario del giocatore. Creerò inoltre una nuova variabile nel BP chiamato "Inventory" utilizzando il tipo struttura che ho appena creato. Nei valori di default della variabile array che possiamo vedere verranno aggiunti degli elementi all’inventario. Ogni elemento contiene una variabile definita nella struttura.

Figura 4.23: Le Struct - Trasformazione di una variabile in una Struct 52CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT

Figura 4.24: Le Struct - Esempio di Struct "TNT"

Quando viene creata una Struct, le azioni "Break" e "Make" di questa struttura vengo- no aggiunte per potere essere utilizzate all’interno del BP. L’azione "Break" riceve una struttura come input e separa i suoi elementi, mentre l’azione "Make" riceve in input gli elementi separati, e crea con questi una nuova Struct. L’immagine seguente mostra come le azioni "Break" e "Make" della struttura "ItemStruct" sono state create.

Figura 4.25: Le Struct - Azioni "Break" e "Make" di una Struct

4.1.9 Gli Enum Un Enum è un insieme di costanti con dei nomi significativi che specifica tutti i possibili valori che una variabile può avere. Per creare un nuovo Enum è necessario premere su "Add New" sotto "Blueprints" e selezionare "Enumeration".

Fare doppio click sull’Enum appena creato per editarlo. Premere su "New" per ag- giungere dei nomi che fanno parte di questo tipo di variabile.

Ora, per creare una nuova variabile in un BP utilizzando questo tipo di Enum appena creato, mettere la spunta sull’opzione "Editable" in modo tale da permettere al valore della variabile di essere selezionabile nell’editor di livelli. L’immagine seguente mostra come un Enum di esempio che rappresenta il tipo di arma può essere creato.

Esiste un tipo di Action di tipo Switch che determina il flusso di esecuzione in accordo con il valore dell’Enum. Nell’esempio seguente "Weapon Type" è una variabile di tipo 4.1. IL SISTEMA DEI BLUEPRINT 53

Figura 4.26: Gli Enum - Aggiunta di un nuovo Enum

Figura 4.27: Gli Enum - Popolamento di un Enum

Figura 4.28: Gli Enum - Configurare un Enum

Enum e "Weapon Mesh" è un componente mesh. La mesh statica verrà impostata in base al diverso tipo di arma.

Figura 4.29: Gli Enum - Caso d’uso: Cambio di mesh 54CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT

4.1.10 I Branch Condizionali Questo particolare nodo dirige il flusso di esecuzione di un Blueprint in base ad un booleano chiamato "Condition", che naturalmente può assumere i valori true o false. Nell’esempio seguente mostro come alla fine di un match viene controllato se il punteg- gio del giocatore è superiore al punteggio maggiore raggiunto fin’ora. Se la condizione è true, questo punteggio viene salvato nella variabile "High Score".

Figura 4.30: I Branch Condizionali - Caso d’uso: Controllo del punteggio

Come secondo esempio, vediamo come l’evento "AnyDamage" viene attivato, ed il nuovo valore di "Health" diventa il suo vecchio valore meno il valore di "Damage" ricevuto. Se il valore di "Health" è minore di zero, l’attore viene distrutto.

Figura 4.31: I Branch Condizionali - Caso d’uso: Gestione salute

4.1.11 Switch On Int Questo tipo di nodo determina il flusso di esecuzione in base ad un valore di tipo Integer ricevuto in input. Se il valore non viene trovato, l’esecuzione prosegue a partire dal pin "Default". Come primo esempio vediamo come la difficoltà di gioco è salvata in una variabile Integer chiamata "Difficult" che può variare tra i valori da 0 a 3 (compresi). Il numero totale di nemici viene impostato in base alla difficoltà. 4.1. IL SISTEMA DEI BLUEPRINT 55

Figura 4.32: Switch On Int - Caso d’uso: Difficoltà e num. nemici

In un secondo esempio vediamo come questa tipologia di nodo viene utilizzata per de- terminare una risposta in base al numero di domande che sono state poste al giocatore.

Figura 4.33: Switch On Int - Caso d’uso: Risposta in base al num. di domande

4.1.12 For Each Loop Questo nodo prende in input un parametro di tipo array ed esegue una serie di opera- zioni che sono associate al pin di output "Loop Body" per ogni elemento dell’array che può essere ottenuto tramite il pin di output "Array Element". Dopodiché il flusso di 56CAPITOLO 4. UNREAL ENGINE: DALLA PROSPETTIVA DEI BLUEPRINT esecuzione viene rediretto verso il pin di output "Completed". Nel primo esempio il For Each Loop viene utilizzato per iterare su di un array che contiene i punteggi del giocatore. Per ogni valore viene testato se questo è il punteggio maggiore a disposizione, se si dimostra vero, questo valore viene salvato nella variabile "Best Score" e l’indice del giocatore viene messo nella variabile "Best Player".

Figura 4.34: For Each Loop - Caso d’uso: Aggiornamento "Best Score" e "Best Player"

In un secondo esempio, quando il giocatore va in overlap con questo BP, tutte le lampade nell’array "Lamps" verranno spente ad eccezione della lampada il cui indice e salvato nella variabile "Lamp Index to Keep On".

Figura 4.35: For Each Loop - Caso d’uso: Spegnimento lampade Capitolo 5

Gli Strumenti ed i Framework di Supporto

5.1 I Plug-In per UE4 ed Ignition

UE4 si presta molto alla sua customizzazione, anche tramite plug-in, gratuiti ed open-source, ed a pagamento, sviluppati da team di professionisti con scopo di lucro, possiamo citare alcune di queste "Mod" tra le più famose:

∗ textbftrueSKY: Questo plug-in a pagamento, che vanta ben 10 anni di presenza sul mercato, si occupa di gestire il tempo atmosferico all’interno dei mondi di gioco sviluppati con UE4. Permette di integrare all’interno del proprio software una gestione realistica, ed in real-time, del tempo atmosferico. Non è disponibile solo per Unreal, ma anche per Unity ed anche come SDK indipendente. Correntemente viene utilizzato anche da Milestone, che ha acquistato la licenza professionale per l’utilizzo di questo tool senza restrizioni di sorta.

∗ Wwise: (Wave Works Interactive Sound Engine) Software di casa Audiokinetic’s per la gestione audio di media interattivi e videogiochi, le funzionalità messe a disposizione per gli ingegneri audio sono centralizzate in una interfaccia grafica che permette di gestire tutti gli aspetti della creazione di effetti sonori e musiche. Anche questo tool è utilizzato dai giochi Milestone, ed ha preso il posto del precedente motore di gestione audio, FMOD.

∗ Modo Material Importer: Tool per l’importazione di mesh tridimensionali disponibile all’interno dell’UE Marketplace, sviluppato per conto di The Foundry. Strumento molto versatile ed utile per importare ed esportare mesh, materiali e texture in formato xml.

∗ Game Analytics: Strumento eclettico che aiuta gli sviluppatori a meglio com- prendere il comportamento in-game dei giocatori. Permette di tracciare, visualiz- zare e valutare: La progressione del giocatore, l’economia di gioco, acquisti con valuta reale e validazione delle transazioni, bug tracking ed altre sezioni utili per poter misurare l’aspetto economico e gestionale del gioco.

Ignition è il framework proprietario di Milestone, costruito dal reparto R&D nel corso degli anni, basandosi su Unreal Engine e con l’intento di migliorare il supporto alle

57 58 CAPITOLO 5. GLI STRUMENTI ED I FRAMEWORK DI SUPPORTO classi, ed ai Blueprint, messi a disposizione dal motore, per realizzare giochi racing. Moto, macchine, da strada, da cross, le possibilità sono molteplici. Inserire Immagine Dashboard di Ignition Unreal Engine, nonostante sia un motore di gioco che potremmo definire "General Purpose" nella sua versione vanilla offre anche la possibilità di creare dei semplici giochi di corse automobilistiche (può essere interessante approfondire la classe "SimpleWheeledVehicle" ed il componente "SimpleWheeledVehicleMovement"). Ignition è composto da vari moduli, che collaborano tra loro per migliorare le capacità di Unreal Engine nella gestione dei sistemi e delle componenti fondamentali per lo sviluppo di un gioco di corse. Nello schema seguente vorrei mostrare uno schema generale di come questi moduli sono strutturati e la gerarchia di cui fanno parte, e dello stato corrente di sviluppo.

Figura 5.1: Lo stato attuale dei moduli di Ignition

5.2 Perforce Helix

Per il controllo di versione, Milestone ha adottato la suite di tools denominata Helix dell’azienda americana leader di settore (particolarmente quello videoludico) Perforce: ∗ Helix Core: Il primo in lista è il sistema di gestione del database centrale, del master repository che si occupa di immagazzinare le differenti versioni dei file della codebase. ∗ Helix P4V: Questo tool di Helix, denominato Helix Visual Client è una GUI che permette di gestire in maniera visuale (ma si ha naturalmente a disposizione anche la riga di comando) il proprio "Workspace", visualizzare il flusso delle modifiche osservando i cosiddetti "Stream", aprire e visualizzare lo stato delle code review e caricare/scaricare i file dai "Depot" di Helix Core. ∗ Helix Swarm: Strumento per la gestione delle code review, con threads di commenti accanto al codice, una dashboard per monitorare tutte le review, e diversi filtri per gestirne la priorità. 5.2. PERFORCE HELIX 59

5.2.1 Helix Core Le feature che offre questo DVCS sono molteplici, che lo differenziano dai sistemi tradizionali, vediamone le principali:

5.2.2 Gli Stream

Figura 5.2: Gli Stream di Helix Core

Gli Stream sono stati soprannominati "Dei Branch con il cervello", sono l’equivalente dei branch di Git, ma con la promessa di essere di più semplice, intuitiva e funzionale gestione. Le nuove modifiche seguono un percorso di "Merge Down" verso una codeline meno stabile, una volta completate e testate, queste modifiche possono raggiungere lo stato di "Merge Up". Questa best-practice, il flusso "Merge down and copy up", previene gli errori e migliora la produttività degli sviluppatori. Inoltre permette di proteggere la mainline, dato che il codice non maturo viene tenuto separato. I project manager e gli altri stakeholders possono facilmente vedere quali sezioni del lavoro complessivo sono state completate, e quali modifiche hanno ancora bisogno di essere integrate. Gli Stream offrono degli indicatori visivi per permettere a chiunque all’interno del team di sviluppo di sapere dove e come eseguire un’operazione di branching. Sia i project manager che gli sviluppatori possono vedere le relazioni all’interno del codice, come i cambiamenti si propagano tra uno Stream e l’altro, e tutte le integrazioni che sono in attesa di essere incorporate. Tutto ciò può semplificare il lavoro extra necessario a definire i branch ed a gestire le integrazioni. Configurare i Workspace e mappare i file può richiedere molto tempo, grazie agli Stream si può saltare da uno all’altro con facilità, dato che i Workspace stessi sono a conoscenza di quali file sono disponibili in base a quale Stream è stato selezionato. Esistono diverse tipologie di Stream a disposizione degli utenti: ∗ Mainline:

Figura 5.3: Lo Stream Mainline

Questo Stream permette di mantenere la codeline stabile ed organizzata. Gli 60 CAPITOLO 5. GLI STRUMENTI ED I FRAMEWORK DI SUPPORTO

Stream di sviluppo all’interno della sua gerarchia possono essere "Copied Up" fino a raggiungere la Mainline. A questo punto il codice può essere inserito in uno degli stream di Release.

∗ Release:

Figura 5.4: Lo Stream Release

Gli Stream di Release sono più flessibili della loro controparte Mainline. Sono stati pensati per essere stabili e vengono utilizzati solitamente per fare bug fixing e per il mantenimento delle release.

∗ Development:

Figura 5.5: Lo Stream Development

Vengono utilizzati per progetti a lungo termine e per le feature più importanti, questi Stream è dove il vero processo di sviluppo ha luogo.

∗ Task:

Figura 5.6: Lo Stream Task

Questi branch sono leggeri, e hanno un ciclo di vita piuttosto breve. Sono stati progettati per permettere ai programmatori di lavorare ad una piccola porzione 5.2. PERFORCE HELIX 61

dello sviluppo complessivo. In questo modo gli sviluppatori possono lavorare in maniera privata e cambiare contesto velocemente. Una volta terminato il lavoro, sia i metadati che le modifiche vengono integrati e confluiscono nello Stream di provenienza. ∗ Virtual:

Figura 5.7: Lo Stream Virtual

Permettono di fare da filtro nei confronti del Workspace, permettono al team di concentrarsi su una particolare porzione della codeline. Tutto ciò è particolar- mente utile quando si ha a che fare con delle codebase dalle dimensioni piuttosto importanti. Possono essere utilizzati per accedere a determinati file dello Stream padre, in questo modo, se dovesse essere necessario lavorare solo su pochi file, non si è obbligati a scaricare l’intero Stream nel proprio Workspace

5.2.3 Helix Visual Client Il workflow flessibile di Helix permette gli utenti di lavorare in locale tramite i Workspace. Con la funzione integrata detta "Replication" è possibile clonare velocemente i dati, senza dover creare una mappa remota, fare "Fetch" dei dati sui "Depot", e "Push" dei cambiamenti locali sui server remoti, mantenendo le stesse funzionalità della riga di comando. Il client P4V si integra anche con lo strumento di code review Swarm.

5.2.4 I Depot Il server di Helix Core salva i dati in repository condivisi chiamati Depot. Di default, in ogni installazione di P4V abbiamo a disposizione un Depot locale. Questi sistemi possono essere di tipo diverso: ∗ Local: Questa è la forma standard, che risiede in locale sulla macchina del server, che può essere anche remoto, o condiviso. ∗ Stream: Questo Depot contiene gli Stream, i branch che includono una gerarchia e delle policy. Come la categoria precedente, risiedono su di un server Perforce. ∗ Spec: Contiene tutte le informazioni di configurazione modificate dagli utenti. Viene utilizzato per il tracciamento delle specifiche dei Workspace, per il "Branch Mapping", ed altri metadati. ∗ Archive: Vengono utilizzati per i dati nearline e offline che vengono prelevati in maniera poco frequente. ∗ Unload: Analogo alla categoria precedente, ma fornisce un luogo dove imma- gazzinare i metadati che sono prelevati poco frequentemente dai client, piuttosto che vecchie versioni dei file. 62 CAPITOLO 5. GLI STRUMENTI ED I FRAMEWORK DI SUPPORTO

5.2.5 I Workspace La specifica di un determinato Workspace definisce una porzione di un Depot che può essere acceduta da quello stesso Workspace, e specifica dove le copie in locale dei file vengono immagazzinate all’interno del Depot. Uno stesso computer (con relativo client) può contenere più di un Workspace. Un Workspace è richiesto quando ci si connette ad un servizio Perforce, se si ha intenzione di lavorare con dei file. La mappatura tra i file del Depot e quelli in locale viene chiamata Workspace View. Se stiamo lavorando con degli Stream, la Workspace View viene automaticamente generata da Perforce, in base alla loro struttura. Se questa cambia, quest’ultima viene aggiornata automaticamente.

5.2.6 P4Merge Attraverso questo tool della suite Perforce, presente nel client visuale P4V, è possibile tracciare e comparare gli effetti di lavoro già compiuto o pendente, per i Branch o per file individuali. Tramite questa interfaccia si possono visualizzare le differenze tra le versioni dei file, risolvere conflitti risultanti da sviluppo parallelo e concorrente. I cosiddetti "Folder Diff" inoltre rivelano la history di branch e di cartelle tra due punti lungo la linea temporale. Questo strumento può essere utile per diagnosticare bug derivanti dall’integrazione continua, e può anche permettere di misurare quanto codice necessita di essere risolto durante i merge in stato pending. E’ possibile utilizzarlo anche sulle immagini (di vari formati) per vederne le differenze, tramite un overlay che isola le modifiche a livello dei pixel.

5.2.7 Helix Swarm Questo strumento integrato nella suite permette, tramite un’interfaccia web-based, ai team di collaborare online, per mezzo di code reviews. I membri possono verificare codice o documenti, e monitorare lo stato delle build della loro continuous integration da un’unica interfaccia. Ogni review ha associati dei "follower" con diversi privilegi, che possono o meno votare up o down le nuove modifiche introdotte nella codebase. Una determinata Changing List (una serie di modifiche appena introdotte, che può rimanere in attesa o può essere caricata su un determinato Depot anche prima dell’apertura di una review, tramite un Check In) può avere associata una review, che può assumere i seguenti stati:

∗ Needs Review: La review è stata appena aperta, e necessita dell’attenzione dei diretti interessati.

∗ Needs Revision: La review è stata appena scrutinata, e necessita dell’attenzione dell’apportatore delle modifiche, per attenersi ai cambiamenti richiesti, sottoforma di "jobs", indicati dai commenti dei "followers".

∗ Approved: In questo caso tutti quanti i "followers" con la responsabilità di approvazione hanno accettato la modifica, è richiesta l’unanimità.

∗ Rejected: Stato in cui ci si viene a trovare se anche solo uno dei "follower" con privilegi più elevati ha bocciato la modifica.

∗ Archived: La review è andata a buon fine, le modifiche sono state accettate ed è pronta per l’archiviazione. 5.3. JIRA 63

5.3 JIRA

JIRA è un sistema di project management centralizzato ed altamente personalizzabile. Tutti i progetti vengono memorizzati in un database centrale ed ognuno di questi passa attraverso una serie di processi detti Workflow. Questi hanno come scopo quello di controllare lo stato di un progetto e di gestire le regole che permetto di mettere in atto le transizioni verso altri stati. La metodologia Agile è già integrata all’interno di JIRA. Questo particolare ed oggigiorno estremamente diffuso framework per lo sviluppo software utilizza quattro principi: ∗ Individui ed interazioni messi al di sopra dei processi e degli strumenti. ∗ Software funzionante a partire da una documentazione esaustiva. ∗ La collaborazione con i clienti è più importante dei negoziati sui contratti. ∗ E’ importante rispondere ai cambiamenti seguendo un piano preciso. La compagnia che sviluppa questo sistema, Atlassian, sulla base di questi principi ha creato questo software, che si fonda sulla flessibilità e sulla customizzazione. Con le sue radici che nascono nello sviluppo software, JIRA può essere però d’aiuto anche in altri settori dove diversi team si trovano a dover collaborare e lavorare a delle Issue in maniera ordinata. Vediamo velocemente degli esempi di gruppi che potrebbero beneficiare dell’aiuto che questo sistema può fornire, per farci un’idea generale. ∗ Marketing: Una certa compagnia necessità di creare una campagnia di marke- ting. JIRA potrebbe essere utilizzato per comunicare le direttive con i writer, la grafica necessaria ai designer, e determinare quando il progetto è stato terminato per poi essere approvato dal responsabile dell’ufficio marketing. ∗ Conformità: Le società bancarie e di trading, tanto quanto quasi qualsiasi piccolo business, ha bisogno di un preciso tracciamento dei loro Workflow. JIRA può venire incontro alle necessità di documentazione da parte dei dipartimenti di conformità, o durante un auditing. ∗ Compagnie e team remoti: Se si ha a che fare con una compagnia remota, o con una che collabora con molti freelancer, sono molto utili delle funzionalità di organizzazione e gestione dei compiti, che possono essere assegnati e gestiti dai lavoratori a progetto. Gli strumenti dettagliati di report messi a disposizione da JIRA possono essere apprezzati molto dai manager.

5.3.1 I Core Component di JIRA 5.3.2 Custom Workflows La gestione dei progetti in JIRA è rappresentata dai Workflow, che possono essere personalizzati in base alle esigenze sollevate da ogni progetto, Issue, e task minori. Qualsiasi cosa che abbia bisogno di passare attraverso uno o più processi può far parte di un Workflow. Nell’immagine seguente possiamo osservare l’esempio di un Workflow di default:

I blocchi colorati rappresentano degli stati, e le frecce le varie transizioni disponibili. Ogni Workflow contiene i suoi stati e le sue transizioni, e attraverso la creazione di grafi personalizzati, si ha la possibilità di tracciare esattamente, all’interno dello scope di un 64 CAPITOLO 5. GLI STRUMENTI ED I FRAMEWORK DI SUPPORTO

Figura 5.8: Default Workflow progetto, in quale stage o task si è collocati. Nonostante JIRA contenga al suo interno dei Workflow predefiniti, le sue vere potenzialità sono nella personalizzazione di questi ultimi. E’ possibile progettarne da zero, o scaricare quelli già disponibili nell’Atlassian Marketplace. Ci sono svariate altre feature oltre il tracciamento tramite i Workflow, per esempio si possono impostare delle condizioni di approvazione per determinati task. Ci sono anche delle funzionalità che vengono attivate quando una certa transizione ha luogo. Nel project managing dei giochi di Milestone ho potuto osservare ed essere coinvolto in alcuni di questi Custom Workflow, qui di seguito ne riporto alcuni:

5.3.3 Bug Workflow Inserire Immagine Bug Workflow Una volta che un bug è stato individuato, la sua issue viene aperta e successivamente viene assegnato, preferibilmente al programmatore che si è occupato di sviluppare la feature in questione. Appena il responsabile si mette a lavoro sul bug in questione, marca la Issue come "In Progress". Se per qualche motivo deve sospendere il lavoro, e mettere il bug in attesa, per ulteriori istruzioni o perchè il programmatore deve dedicarsi ad altro, il bug passa allo stato "Acknowledged". Se il bug non è risolvibile al momento, o necessita di ulteriori operazioni preliminare, viene fatta una transizione e la Issue viene posta in stato "Suspended". Quando, per procedere nella risoluzione del problema, ci si trova costretti a richiedere un feedback esterno, al proprio lead programmer, oppure al reparto QA testing, il bug viene posizionato in stato "Feedback Given" (una volta ricevute le direttive necessarie) e può essere riportato allo stadio "In Progress" una volta che si continua il lavoro. Quando il programmatore ritiene di avere fixato il problema, può accingersi a spostare la Issue in posizione "Resolved", in attesa che venga testato ed approvato. A questo punto si aprono due scenari: Il bug è effettivamente stato risolto, ed il reparto di testing dà la 5.3. JIRA 65 sua approvazione, e la issue finisce il suo ciclo di vita nello stato "Closed". Altrimenti il bug viene riaperto e passa allo stadio "Reopened".

5.3.4 Feature Workflow Inserire Immagine Feature Workflow Il percorso di una nuova feature di gioco è leggermente più complesso, ma analogo all’esempio precedentemente discusso. Si parte dallo stadio "Opened", quando una feature viene assegnata ed è stata selezionata per lo sviluppo ad un determinato gruppo di persone (programmatori, designer, artist, più figure professionali possono essere chiamate in causa per collaborare insieme). Una volta che è stata approvato il suo sviluppo, decisi i collaboratori e determinato lo sprint (anche più di uno per feature particolarmente complesse) in cui dovrà svolgersi il lavoro, la Issue si sposta allo stadio "Selected for development". Se viene determinato dalla sezione di pianificazione, o chi per loro, che una determinata feature non ha più motivo di essere completata, finisce il suo ciclo di vita in "Deprecated", e viene scartata. Altrimenti si può procedere allo stato "In Progress" dove si porta a termine il lavoro, e lo si sottopone alla "Production", cioè ai propri responsabili, che nel caso dei programmatori sono i lead programmer, e visionata in maniera preliminare dal producer e dal lead designer. Se sono soddisfatti dello stato di terminazione del lavoro, la Issue passa in stato "Approved by Production", altrimenti "Rejected by Production". Una volta superato questo stadio preliminare, è responsabilità dei tester del reparto QA di controllare a fondo che la feature non contenga bug di sorta, e se viene verificata la sua compliance, si può passare in stato "Tested by QA" ed infine "Approved by QA". A questo punto il Workflow è terminato e la nuova feature può essere aggiunta al gioco.

Capitolo 6

La mia esperienza a Milestone

6.1 Bug Fixing

I primi passi in Milestone mi hanno visto coinvolto, con l’aiuto di qualche collega più esperto, nella risoluzione di alcuni bug esemplificativi e formativi. Alcuni erano banali, altri molto meno, ho voluto riportare quelli che mi sono sembrati più interessanti come insight all’interno di Ignition e di Unreal Engine 4. I giochi in cui mi sono trovato a collaborare nel risolvere questi errori di programmazione sono stati SuperCross 3 e MotoGP 20. Il mio percorso di stage mi ha visto prima all’interno del team GET (Game Engineering and Tools) per la mia formazione, team che fa da supporto e gestisce i tool per migliorare lo sviluppo di tutti i team dei giochi, e poi sono stato spostato nel team di sviluppo di MotoGP 20, dove mi trovo tutt’ora.

6.1.1 SX3 - Bug della camera durante caduta del pilota Componente: Gameplay Camera. Descrizione: Durante un replay, se si cambia la camera nel momento esatto in cui il pilota cade dalla moto, la camera risulterà spostata dalla posizione originale, resettando la posizione se si cambia camera o il pilota che si sta osservando cade. Problema: Ogni pilota ha una camera associata, che può trovarsi in posizioni differenti in base alle preferenze del giocatore (telecamera in terza persona, visuale interna al casco del pilota, ecc). Il bug si presenta quando si entra in modalità caduta, e la camera diventa fissa, posizionata lungo un determinato marker della spline distintiva della pista. Quando il sistema passa nuovamente alla camera selezionata dal giocatore, abbandonando quella fissa della modalità caduta, la posizione della camera appare spostata dalla sua posizione standard. Questo si è rivelato accadere solo nella camera in prima persona, una volta approfondito il problema. Il motivo era che la mesh del pilota, invece di mostrare solo le braccia del personaggio, appariva completa, cosa che quindi faceva sembrare la camera in posizione errata. Le camere hanno diversi livelli di priorità, e vengono selezionate in base a questi, chiamati "Override". Essendo questa una nuova feature aggiunta successivamente alla creazione del sistema delle camera, in questo caso è stata bypassata dalla particolare configurazione, e quindi non permetteva di aggiornare correttamente il sistema di inquadrature ed i parametri associati (come la visibilità della mesh). Il problema può essere descritto in questa maniera:

1. Il gioco si trova in modalità caduta e la camera corrente è la FallCamera.

67 68 CAPITOLO 6. LA MIA ESPERIENZA A MILESTONE

2. Il cambio di target (oggetto inquadrato dalla camera corrente) avviene diretta- mente sul veicolo, che chiama la funzione BecomeViewTarget(), ma la FallCamera al momento è ancora attiva e la visibilità della mesh non viene modificata.

3. La FallCamera reagisce al cambio di target, nota che la nuova moto selezionata (dato che viene cambiata la camera dal giocatore) non è caduta, e modifica gli "Override".

4. Viene chiamata una nuova SetViewTarget() sul veicolo (la funzione che modifica l’oggetto inquadrato dalla camera selezionata), ma dato che quest’ultimo è già il "ViewTarget" selezionato, non viene chiamata nuovamente la funzione BecomeViewTarget(), e la visibilità non viene aggiornata, ricadendo in uno stato inconsistente.

Soluzione: Come possiamo vedere nel "Diff" (funzionalità offerta da Perforce) rap- presentato dall’immagine seguente, la soluzione che ho adottato è stata quella di aggiungere una nuova funzione che aggiorna la visibilità quando vengono rimossi tutti gli "Override".

Figura 6.1: Modifiche apportate a GameBaseVehicle.h

Nell’immagine seguente invece possiamo vedere un diagramma di sequenza che illustra le chiamate principali che vengono effettuate durante il passaggio dalla FallCamera alla camera precedente, una volta terminato il lasso di tempo assegnato alla caduta. Inserire diagramma-sequenza01

6.1.2 MGP20 - FastForward Cheat Componente: Cheat Manager. Descrizione: Il Cheat "FastForward" è legato al frame rate della piattaforma, e la velocità di percorrenza del tracciato non è omogenea. Problema: Questo Cheat 6.1. BUG FIXING 69

Figura 6.2: Modifiche apportate a GameBaseVehicle.cpp

(traducibile in italiano con "trucco", un modo per aggirare le leggi del gioco) è stato creato come strumento di supporto per il debugging, o qualsiasi altra attività che dovesse richiedere attraversare la pista durante il gameplay ad elevatissima velocità, in modo da posizionarsi velocemente in qualsiasi sezione del tracciato, in base alle necessità. Si è notato però, che la velocità alla quale la moto "scivolava" lungo il tracciato variava notevolmente al variare del Framerate, e quindi il codice era dipen- dente sia dalle prestazioni dell’hardware, che dalle piattaforme stesse (le console hanno tendenzialmente un Framerate molto più basso, paragonate ad un PC con componenti performanti). Leggendo il codice ho notato che la funzione che gestisce questo Cheat non prendeva in considerazione il parametro "DeltaSeconds" della funzione "Tick" (di cui abbiamo parlato nella sezione di Unreal Engine). Soluzione: La soluzione è stata rendere questa funzione "Frame Independent", scalando la velocità costante del movimento della moto in pista utilizzando il parametro "DeltaSeconds" passato in input alla funzione "Tick", ad ogni frame. Il fix è visibile nell’immagine in basso:

6.1.3 MGP20 - Audio Collision Debug Componente: FModVehicleDebug. Descrizione: Al momento del passaggio dal plug-in audio FMod a WWise, alcune funzionalità accessorie fornite dal primo plug-in necessitavano di essere rifattorizzate per essere compatibili con il nuovo gestore audio. In particolare la funzione di debugging che mostrava un overlay su schermo che era d’aiuto ai designer, che mostrava ad ogni oggetto entrato in contatto con la moto del giocatore, se gli asset audio associati alla collisione fossero correttamente presenti, e configurati correttamente. In particolare con il console command "FModVehicleDebug" vengono visualizzati a schermo, tutte le interazioni tra la moto e quello che la circonda, ad esempio: collisioni, superfici, RPM etc. Di ogni suono viene mostrato il nome e l’intensità con il quale viene riprodotto. Questo comando dà la possibilità di verificare il corretto funzionamento dell’asset 70 CAPITOLO 6. LA MIA ESPERIENZA A MILESTONE

Figura 6.3: Modifiche apportate a IgnitionPlayerController.cpp sonoro e di constatare se gli oggetti siano stati correttamente flaggati. Il mio compito è stato rifattorizzare il codice e renderlo funzionante dopo la migrazione da un supporto altro a quello di nuova acquisizione da parte di Milestone. Qui di seguito riporto le modifiche al codice più salienti che ho apportato:

Figura 6.4: Modifiche apportate a IgnitionVehiclePawn.cpp parte 1 6.1. BUG FIXING 71

Figura 6.5: Modifiche apportate a IgnitionVehiclePawn.cpp parte 2

Figura 6.6: Modifiche apportate a IgnitionVehiclePawn.cpp parte 3

6.1.4 MGP20 - Cambio camera Componente: Input Mapping. Descrizione: Non funziona il cambio camere durante il gameplay, non è possibile passare per esempio dalla camera in terza persona a quella in prima persona. Pro- blema: Il tasto associato al cambio camera (è un bottone della UI nella modalità 72 CAPITOLO 6. LA MIA ESPERIENZA A MILESTONE

Figura 6.7: Modifiche apportate a IgnitionVehiclePawn.cpp parte 4

Figura 6.8: Modifiche apportate a IgnitionVehiclePawn.cpp parte 5 replay, mentre durante il gameplay è mappato su uno dei tasti del PlayerController) non provoca nessuna action, il manager delle camere non viene chiamato in causa e non è possibile cambiare la camera in alcun modo, in nessuna modalità delle diverse modalità di gioco. Soluzione: Il problema è sorto quando il nome della Action è stato cambiato, da "SwitchCamera" a "CameraNext". Ma chi ha apportato queste modifiche si è dimenticato di rimappare anche il file .ini che si occupa di mappare i tasti con le input action, questo file è "DefaultInput.ini" e si trova all’interno della cartella di configurazione del progetto di Visual Studio del gioco. La soluzione è stata semplicemente quella di modificare il nome del mapping ed adeguarlo alle modifiche apportate precedentemente da chi ha provocato il bug. 6.1. BUG FIXING 73

Figura 6.9: Modifiche apportate a DefaultInput.ini

Bibliografia

Riferimenti bibliografici

Frignani, Marco Accordi Rickards Paola. Le professioni del videogioco. Una guida all’inserimento nel settore videoludico. Lapilli, 2010. Sewell, Marcos Romero Brendan. Blueprints Visual Scripting for Unreal Engine: The faster way to build games using UE4 Blueprints, 2nd Edition. Packt Publishing, 2019.

Siti web consultati

Atlassian. JIRA Documentation. url: https://confluence.atlassian.com/jira/ jira-documentation. Games, Epic. Unreal Engine 4 Documentation. url: https://docs.unrealengine. com. Perforce. Perforce Helix Documentation. url: https://www.perforce.com/support/ self-service-resources/documentation.

75