Latest Posts

0

Eppur si muove! Si ma pianissimo però...

CiacioZ 23.9.15
Proprio quando il becchino stava già buttando l'ultima badilata di terra sul feretro di questo progetto e i follower avevano perso ogni speranza (quali follower!?) ecco che arriva un aggiornamento!

Ebbene sì, dopo prove e riprove, pause, altre prove, pause, parolacce e prove di parolacce sono riuscito finalmente a superare uno degli scogli più duri: il PATHFINDING!

Sotto questo nome altisonante quanto esoterico viene raggruppato quell'insieme di algoritmi, trucchi e beceri accrocchi che permettono al personaggio di camminare all'interno di una stanza saltando eventuali ostacoli e compiendo il tragitto più breve per giungere a destinazione.

Non sto a spiegare nel dettaglio gli incantesimi arcani e i riti alchemici che mi hanno portato alla soluzione visto che credo interessino veramente a pochi (e siete già pochissimi), vi basti sapere che l'idea di base l'ho presa da questo fantastico articolo.

Per l'occasione ho anche dato una rinfrescata alla demo in modo da poter permettere a tutti di fare qualche test.

Qui potete scaricare la demo.


Elenco tasti per la demo:

ESC per terminare la demo.
F1 per visualizzare l'area calpestabile e l'ultimo percorso calcolato.
0

Sotto il cofano... Parte IV

CiacioZ 5.2.14 ,
Giuro che questo è l'ultimo post della serie "Sotto il cofano... Parte X", li avrei cambiati anche prima ma siccome sono un precisino mi avrebbe dato fastidio come la sabbia nel letto avere dei titoli non uniformi quindi a malincuore mi è toccato proseguire con la serie... prima di inorridire ricordo a tutti che sono un programmatore.

Detto questo, dopo la prima puntata con la panoramica sull'architettura generale, la parte sull'AssetManaer e il post sullo ScriptManager eccoci arrivati all'ultimo pezzo del motore: la Presentation!

Questo strato del motore è quello che si occupa di visualizzare le entità del gioco e gestire l'interazione con l'utente.
Essendo anche questa parte trasparente rispetto agli alti elementi, può essere implementata in qualsiasi modo rendendola quindi indipendente dalla libreria utilizzata.
La mia scelta per esempio è stata quella di utilizzare il binding per .NET della libreria SFML che rivaleggia più o meno sullo stesso piano della più famosa SDL.
Come mai la scelta è ricaduta sulla prima? Principalmente perché leggendo alcune comparative mi sembra più performante e moderna implementando per esempio l'accelerazione tramite GPU (non che il mio gioco ne abbia bisogno per carità) oltre al fatto di avere un binding con .NET aggiornato.

Quello che a prima vista può sembrare lo strato più semplice in realtà è quello che mi ha fatto avvicinare di più alla dannazione eterna a causa di possenti invocazioni dal forte tono dispregiativo verso divinità di ogni sorta.
Già perché quando si ha a che fare con funzioni che utilizzano la scheda grafica il rischio di sbagliare qualcosa e far precipitare le prestazioni a livello CryEngine che gira su Commodore64 è un dietro l'angolo.
Non basta infatti chiamare una funzione che visualizza i byte dell'immagine dell'omino a schemo per essere tranquilli ma il modo in cui vengono istanziati gli oggetti e il numero di chiamate effettuate alla funzione che "disegna" su schermo possono fare una differenza enorme tra un risultato ottimo o uno mediocre.

In questa libreria per esempio ogni cosa che si vuole visualizzare a schermo passa da un oggetto Texture che può essere passato alla funzione "Draw" che lo renderizzerà a schermo.
Istanziare ad ogni ciclo le Texture, le dimensioni delle stesse e il modo in cui vengono gestite e passate alla funzione Draw incidono parecchio e purtroppo vista la documentazione un po'scarsa mi sono dovuto barcamenare tra l'approccio a tentoni, richieste sul forum ed esempi presi da articoli fatti da altri utilizzatori.

Ad esempio visto che col mio portatile il background in HD di una locazione non riesce a stare in un unico oggetto Texture ho dovuto suddividerlo in porzioni più piccole e ricomponendolo tipo puzzle in fase di visualizzazione. Questo approccio però aveva portato ad un aumento delle chiamate alla funzione "Draw" della libreria con conseguente crollo delle performance.
La soluzione, dopo aver camminato sui muri, vomitato verde e incendiato crocifissi con la sola imposizione della fiatella, ho scoperto essere quella di gestire le Texture tramite il VertexBuffer.
Vi risparmio i dettagli ma in pratica consiste nel definire un poligono di "Vertex" a cui viene associata la parte di Texture dello sfondo. 
Questo è un approccio molto più gradito dalla scheda video che come per magilla torna a processare frame come se non ci fosse un domani (tranne sempre sul mio portatile ma per lui il domani è sempre più incerto).

Per adesso, nonostante la libreria offra già delle possibilità legate al 3D, mi concentrerò su un approccio 2D come le care vecchie avventure LucasFilm/Arts.
In futuro, se e quando sarà finito il motore, magari valuterò di evolverlo introducendo il 3D ma per quello c'è ancora molta strada oltre che una moltitudine in più di librerie con ottimi binding per .NET da valutare come per esempio: il MOGRE (binding .NET per la libreria Ogre) o il NeoAxis sempre basato sull'Ogre.

Se già con un semplice approccio 2D ho avuto scomuniche da parte di quasi tutte le religioni del pianeta non oso immaginare cosa succederebbe se dovesse entrare in gioco la terza dimensione con l'introduzione di concetti come Camera, Luci, Poligoni, Texture etc. probabilmente farei la fine di Gozer il gozeriano*.






*Se non sapete di chi sto parlando lasciate subito questo blog.

0

Sotto il cofano... Parte III

CiacioZ 30.1.14 ,
Lo so ormai siamo ai livelli delle più becere produzioni cinematografiche seriali: Parte I, Parte II e adesso, tocco di fantasia: Parte III!
Il livello di questo post cercherà quindi di, ammesso che sia umanamente possibile, abbassare ulteriormente l'asticella come d'altronde la tradizione cinematografica impone ovvero il crollo verticale di ogni aspetto produttivo con l'aumentare del numero dei seguiti.

Come promesso, quest'oggi andrò ad illustrarvi lo ScriptEngine: come nasce, si sviluppa, rituali di accoppiamento e integrazione col proprio habitat. Scusate il tono stile lezioni di Nettuno ma sento una certa affinità col programma: orari di messa in onda e stesso audience.

Lo ScriptEngine è quella parte che rappresenta il cuore del motore, si posiziona tra l'AssetManager (da cui preleva i dati) e lo strato di Presentation (a cui li invia per essere visualizzati) occupandosi in sostanza di gestire il ciclo tipico di ogni gioco:


  1. Leggi eventuali input dell'utente
  2. Aggiorna le entità del gioco
  3. Mostra a video i risultati


Per svolgere questo scopo definisce al suo interno tutta una serie di funzioni che servono a manipolare le entità del gioco e le interazioni tra le stesse.
Ad esempio quando un giocatore clicca su un punto dello schermo è compito di questo strato fare in modo che le entità si aggiornino correttamente facendo sì che ad ogni ciclo il personaggio si muova fino a destinazione.
Queste funzioni vengono poi esposte tramite un linguaggio di script permettendo così, tramite l'editor, di implementare la logica delle varie azioni andando a definire quindi la storia e l'evolversi del gioco.

Ci sarà quindi ad esempio una funzione per caricare una stanza, piuttosto che una funzionalità per specificare che un personaggio si deve muovere in una determinata posizione oppure dire qualcosa etc.

Se fossi un programmatore figo, con i cosiddetti e con un sacco di tempo libero mi sarei fatto un linguaggio di script ad hoc per l'occasione ma siccome non ho nessuna di queste caratteristiche preferisco non addentrarmi un una problematica così complessa per puro sfizio. Visto che ho l'obiettivo di realizzare qualcosa di usabile in tempi compatibili con la vita umana (soprattutto la mia)  ho deciso di integrare un linguaggio già fatto, collaudatissimo e molto usato: LUA.

La scelta è caduta su questo linguaggio prima di tutto per la sua diffusione e semplicità garantendo quindi poco sforzo da parte degli utilizzatori finali (sempre che un giorno ce ne siano) secondo per la presenza di DynamicLua una libreria per il binding con C# particolarmente semplice da utilizzare che mi ha permesso di esporre facilmente le funzionalità del motore (tradotto: con poche e semplici linee di codice, minimizzando invocazioni poco raffinate a divinità di ogni pantheon conosciuto).

Ultima cosa da segnalare, ma non di poco conto, questo strato del motore si occupa anche di regolare la velocità del ciclo di gioco adattandolo al FrameRate (velocità di visualizzazione delle varie entità ad opera della Presentation) in modo che, per esempio, un'animazione risulti alla stessa velocità indipendentemente dall'Hardware su cui gira il motore.
Questo viene fatto da una parte imponendo al massimo 60 cicli al secondo per evitare che chi ha Deep Blue in casa veda animazioni velocissime, dall'altra saltando uno o più cicli per compensare la differenza con il FrameRate massimo.
Se ad esempio un computer dovesse renderizzare 30 FPS, nell'animazione di una camminata formata da 10 passi (1, 2, 3, 4, 5, 6, 7, 8, 9 e 10) invece di considerarli tutti verrebbero mostrati solo: 1, 3, 5, 7, 9. Il risultato è che visualizzando la metà dei Frame nel doppio del tempo la durata finale dell'animazione risulta uguale al caso ideale dei 60 FPS.
E se un PC non riuscisse a realizzare neanche un ciclo al secondo!? Beh in quel caso visto il modesto carico di lavoro richiesto dal motore vorrebbe dire avere a che fare con un Hardware equiparabile ad una calcolatrice di quelle da fustino del detersivo quindi sto abbastanza sereno (in realtà non molto visto che in questo caso il motore va in crash pesante quindi non passate la demo a nessuno che non sia dotato almeno di un calcolatrice scientifica).
Per inciso per adesso l'unico catorcio su cui ho ottenuto meno di 60 FPS è proprio il portatile che sto usando per lo sviluppo... ANUBI!

Direi che le premesse sono state rispettate in pieno: tedioso e soporifero come un corso di analisi matematica di Nettuno delle 2 del mattino, adesso manca solo la parte sulla Presentation e poi con i tecnicismi abbiamo finito... a parte ovviamente un piccolo dettaglio chiamato Editor ma non voglio creare troppa hype ;)

Alla prossima puntata con il fantastico mondo delle librerie grafiche: ne volete sapere di OpenGL, modalità video e double buffering? Io no quindi non contate su di me, se ho usato l'ennesima libreria già fatta ci sarà un motivo no? :P


0

Sotto il cofano... Parte II

CiacioZ 24.1.14 ,
Lo so che eravate in trepidante attesa di un nuovo emozionante articolo pieno interessantissimi e coinvolgenti approfondimenti tecnici ma appostarsi sotto casa mia urlando "ESCI! ESCI! ESCI!" mi è sembrato un tantino eccessivo... in ogni caso la prossima volta evitate di mettere la polo di Equitalia che tanto non ci casco, bel tentativo ma ci vuole ben altro, mi ricordo per esempio quella volta che una ragazza si mise a picchiare furiosamente i pugni alla mia porta "APRI! APRI! APRI!", ma io non l'ho fatta uscire... perchè l'amore è sacrificio!
Ma sto divagando... dunque come vi avevo minacc... hem preannunciato nella prima parte relativa alla descrizione dell'architettura generale in questo articolo tratteremo, rullo di tamburi... l'AssetManager!

L'AssetManager è quel livello dell'applicazione che si occupa di memorizzare e caricare gli asset del gioco, quindi la grafica, i suoni, le animazioni etc.
L'implementazione attuale sfrutta la serializzazione binaria degli oggetti messa a disposizione dal Framework.Net
Per chi fosse poco pratico dell'argomento (tranquilli faccio tanto il maestrino ma non è che ne sappia poi così tanto) questa funzionalità permette di salvare un oggetto in formato binario su disco e richiamarlo successivamente ottenendolo nello stesso stato in cui l'avevamo salvato.
Bingo direte voi! Ed in effetti visto che il Framework di Microsoft si sobbarca già buona parte del lavoro è una gran bel passo in avanti ma il primo problema che è sorto immediatamente è stato: come faccio ad impacchettare e a gestire tutte le risorse del gioco in un unico file?
Già perché il metodo che fornisce il Framework di base prevede che venga serializzato un oggetto in un file.
Questo ovviamente è uno scenario che ho scartato subito in quanto non aveva senso avere millanta file per ogni locazione, personaggio etc. non siamo mica ai tempi di Maniac Mansion o Zack McKracken* ;)  

L'idea per risolvere questo problema mi è venuta leggendo alcune note tecniche sui file delle avventure della Lucas disponibili sul sito dello ScummVM a questo indirizzo.
In pratica nello SCUMM™ ovvero il motore utilizzate per le avventure della LucasFilm/Arts c'è un file che fa da indice per le risorse e un file che contiene tutte le risorse.

Applicando lo stesso concetto al mio programma ho così fatto in modo che esistano due file:

Resources.Bin
E'la serializzazione binaria di una lista che associa al nome di una risorsa la posizione che occupa la sua versione serializzata nel file Resources.Dat

Resources.Dat
Continene tutte le risorse serializzate in versione binaria.

Quando tramite lo script di gioco viene fatta caricare la locazione tramite il comando:

ShowLocation("Locazione1")

Il motore di gioco chiede all'AssetManager "Dammi l'oggetto locazione che corrisponde alla chiave 'Locazione1'... magari in un modo più tecnico e ostentando quell'accento binario tipico degli scatolotti grigio sabbia ma è per rendere l'idea ;)

L'AssetManager sbrigate le quisquilie burocratiche, bacio all'anello esadecimale "Documenti grazie" "Lei non sa che strato software sono io!" etc. controlla nella lista deserializzata dal file Resources.Bin dove si trova l'oggetto richiesto: "Locazione1 primo piano a destra, interno ventordici", si posiziona nel punto indicato del file Resource.Dat e deserializza l'oggetto corrispondente.

Il tutto funziona piuttosto bene e permette per adesso di caricare in tempo reale locazioni, personaggi etc. senza attese di caricamento e minimizzando al massimo lo spreco di RAM.

Tutto fantastico quindi? Ovviamente no, il problema della serializzazione binaria del Framework.Net è che le stringhe non vengono convertite in binario e sono quindi leggibili editando il file, una soluzione potrebbe essere per esempio quella adottata sempre dallo SCUMM™ (fonte ScummVM) che consiste nell'applicare un'operazione XOR sul contenuto del file in modo da renderlo difficilmente leggibile da qualche ardito smanettone che volesse modificare con facilità le risorse del gioco.
Per adesso va bene così, ma è sicuramente nella lista dei "TODO".

Il primo approfondimento sugli elementi che compongono il motore di gioco è teminato, era una hola quella!? Spero resisterete qualche giorno in attesa di scoprire cosa si nasconde dietro... lo ScriptEngine!

Mwahahaha haha ha a...




*Nelle prime versioni dello SCUMM™ (Manica Mansion e Zack McKracken) c'era un file per ogni locazione: 1.lfl, 2.lfl etc.
0

Sotto il cofano... Parte I

Eccoci al primo attesissimo (!?) appuntamento di una serie di articoli in cui spiegherò l'architettura dell'engine e del suo funzionamento interno.

Siccome vi vedo impazienti come fan di Guerre Stellari alla prima de "La minaccia fantasma" comincio subito con lo spiegozzo, spero solo in reazioni migliori rispetto al film di Lucas :P

Attenzione! Se dovete andare in bagno o comprare i pop-corn questo è l'ultimo momento utile per farlo.

Architettura Generale:
Il motore si divide sostanzialmente in 3 parti: l'AssetManager, lo ScriptEngine e la Presentation.

AssetManager:
E'la parte del motore che si occupa di salvare e caricare le risorse inserite tramite l'editor quindi gli sfondi, la grafica i suoni etc.

ScriptEngine:
Definisce il binding tra il linguaggio di script e le funzioni interne, si occupa inoltre di gestire la logica interna del motore.

Presentation:
Si occupa di renderizzare a video le immagini e gestire l'interazione con il giocatore.

Questa separazione è realizzata in modo che ogni strato o layer sia completamente trasparente per gli altri, questo vuol dire che per esempio quando tramite uno script viene utilizzata la funzione per caricare una locazione, lo strato dello ScriptEngine chiama una funzione dell'AssetManager che gli restituirà l'oggetto richiesto.
Come l'AssetManager esegue il suo compito è completamente trasparente per lo ScriptEngine e questo concetto si applica anche allo strato di Presentation. 
Quando lo ScriptEngine ad esempio deve visualizzare il personaggio, chiama un metodo del Presentation che in maniera totalmente indipendente si occuperò di visualizzarlo a schermo.

Questo approccio, noto in programmazione col termine MVC (Model-View-Controller) permette tra l'altro di poter modificare uno strato o layer in maniera indipendente dagli altri.
Ad esempio la Presentation attualmente sfrutta la libreria SFML ma se un domani volessi sostituirla con una diversa potrei riscrivere la parte di Presentation senza toccare minimamente le altre parti dell'engine.

Nelle prossime puntate descriverò in dettaglio ogni layer dell'applicativo approfondento un po'di più le scelte implementative.
 
Copyright 2010 Alone in the Code