Advertisement
  1. Game Development
  2. Roguelike
Gamedevelopment

Come creare il vostro primo Roguelike

by
Difficulty:IntermediateLength:LongLanguages:

Italian (Italiano) translation by Chip (you can also view the original English article)

I giochi Roguelikes di recente sono stati sotto i riflettori, con giochi come Dungeons of Dredmor, Spelunky, The Binding of Isaac ed FTL che sta raggiungendo un vasto pubblico e ricevendo il plauso della critica. Dopo aver a lungo divertito una piccola nicchia di giocatori incalliti, gli elementi dei roguelike in varie combinazioni ora contribuiscono a portare maggiore profondità e rigiocabilità a molti generi esistenti.

Wayfarer a 3D roguelike currently in development
Wayfarer, un roguelike 3D attualmente in fase di sviluppo.

In questo tutorial, imparerete a fare un roguelike tradizionale utilizzando JavaScript ed il motore di gioco HTML5 Phaser. Alla fine, avrete un semplice gioco roguelike completamente funzionante, giocabile nel vostro browser! (Per i nostri scopi un roguelike tradizionale è definito come un single-player, randomizzato, a turni dungeon-crawler con permadeath.)

Click to play the game
Clicca per giocare.

Nota: Anche se il codice in questo tutorial utilizza JavaScript, HTML e Phaser, si dovrebbe essere in grado di utilizzare la stessa tecnica e concetti in quasi qualsiasi altro linguaggio di programmazione e motore di gioco.


Prepararsi

Per questo tutorial, avrete bisogno di un editor di testo e di un browser. Io uso Notepad++ e preferisco Google Chrome per i suoi ampi strumenti di sviluppo, ma il flusso di lavoro sarà più o meno lo stesso con qualsiasi editor di testo e browser scegliate.

Si dovrebbe quindi scaricare i sorgenti ed iniziare con la cartella init; questa contiene i file Phaser, HTML e JS di base per il nostro gioco. Scriveremo il nostro codice di gioco nel file rl.js per ora vuoto.

Il file index.html semplicemente carica Phaser ed il nostro file precedente col codice del gioco:


Inizializzazione e definizioni

Per il momento, useremo la grafica ASCII per il nostro roguelike, in futuro potremmo sostituirla con grafica bitmap, ma per ora, utilizzando semplici ASCII avremo vita facile.

Definiamo alcune costanti per la dimensione del carattere, le dimensioni della nostra mappa (ovvero, il livello), e quanti personaggi si riprodurranno al suo interno:

Avviamo anche l'inizializzare di Phaser e l'attesa per eventi della tastiera key-up (rilascio del tasto), creando un gioco a turni vogliamo agire una volta per ogni tasto premuto:

Dal momento che i font a spaziatura fissa predefinita tendono ad essere circa il 60% più larghi rispetto alla loro altezza, abbiamo inizializzato le dimensioni del canvas a 0,6 * la dimensione del carattere * il numero di colonne. Stiamo anche dicendo a Phaser che dovrebbe richiamare la nostra funzione di create() immediatamente dopo che è finita l'inizializzazione, a quel punto inizializziamo i controlli della tastiera.

È possibile visualizzare il gioco fino a qui, non che ci sia molto da vedere!


La Mappa

La tile map rappresenta la nostra area di gioco: una discreta (al contrario di continuo) gamma di piastrelle 2D, o celle, ognuna rappresentata da un carattere ASCII che può significare sia una parete (#: blocca il movimento) o un pavimento (.: non blocca il movimento):

Usiamo la forma più semplice di generazione procedurale per creare le nostre mappe: decidere a caso quale cella dovrebbe contenere un muro, e quale un pavimento:

Questo ci dovrebbe dare una mappa in cui l'80% delle celle sono pareti ed il resto pavimento.

Inizializziamo la nuova mappa per il nostro gioco nella funzione create(), subito dopo aver impostato i listener di eventi della tastiera:

È possibile visualizzare la demo qui, anche se, ancora una volta, non c'è niente da vedere, visto che ancora non abbiamo il rendering della mappa.


Lo Schermo

È il momento di disegnare la nostra mappa! Il nostro schermo sarà una matrice 2D di elementi di testo, ciascuno contenente un singolo carattere:

Disegnare la mappa comporta riempire lo schermo con i valori contenuti nella mappa, poiché entrambi sono semplici caratteri ASCII:

Infine, prima di disegnare la mappa dobbiamo inizializzare lo schermo. Torniamo alla nostra funzione create():

Ora dovreste vedere una mappa casuale visualizzata quando si esegue il progetto.

Click to view the game so far
Clicca per vedere il gioco fino a qui.

Attori

Dopo in linea ci sono gli attori: il nostro personaggio, ed i nemici da sconfiggere. Ogni attore sarà un oggetto con tre campi: x e y per la sua posizione nella mappa, e hp per i suoi punti ferita.

Manteniamo tutti gli attori nella matrice actorList (di cui il primo elemento è il giocatore). Manteniamo anche un array associativo con le posizioni degli attori come chiave per la ricerca rapida, in modo da non dover iterare l'intero elenco degli attori per trovare quale attore occupa una certa posizione; questo ci aiuterà per il codice movimento e combattimento.

Creiamo tutti i nostri attori e per ciascuno assegnamogli una posizione libera casuale nella mappa:

E' il momento di mostrare gli attori! Stiamo per disegnare tutti i nemici come una e ed il personaggio del giocatore, come il suo numero di punti ferita:

Facciamo uso delle funzioni che abbiamo appena scritto per inizializzare e disegnare tutti gli attori nella nostra funzione create():

Ora possiamo vedere il carattere del nostro giocatore ed nemici sparsi nel livello!

Click to view the game so far
Clicca per vedere il gioco fino a qui.

Tiles di blocco e calpestabili

Dobbiamo fare in modo che i nostri attori non corrano fuori dallo schermo e attraverso i muri, quindi cerchiamo di aggiungere questo semplice controllo per vedere in quali direzioni un determinato attore può camminare:


Movimento e combattimento

Siamo finalmente arrivati a una certa interazione: movimento e combattimento! Dal momento che, nei roguelikes classici, l'attacco di base è innescato muovendosi dentro un altro attore, gestiamoli entrambi nello stesso punto, la nostra funzione moveTo(), che prende un attore e una direzione (la direzione è la differenza desiderata in x e y per la posizione dove l'attore sta camminando):

In sostanza:

  1. Ci assicuriamo che l'attore stia cercando di entrare in una posizione valida.
  2. Se vi è un altro attore in quella posizione, attacchiamo (e uccidiamo, se il suo conteggio HP raggiunge 0).
  3. Se non c'è un altro attore nella nuova posizione, ci spostiamo lì.

Si noti che mostriamo anche un semplice messaggio di vittoria una volta che l'ultimo nemico è stato ucciso e torniamo false o true a seconda se non siamo riusciti ad eseguire una mossa valida.

Ora, torniamo alla nostra funzione onKeyUp() e modifichiamola in modo che, ogni volta che l'utente preme un tasto, cancelliamo la posizione precedente dell'attore dallo schermo (disegnandoci sopra la mappa), spostiamo il personaggio del giocatore nella nuova posizione e quindi ridisegnamo gli attori:

Presto useremo la variabile acted per sapere se i nemici debbano agire ad ogni ingresso del giocatore.

Click to view the game so far
Clicca per vedere il gioco fino a qui.

Intelligenza Artificiale di base

Ora che il nostro personaggio si muove ed attacca, diamo anche la probabilità che i nemici agiscano seguendo un semplice percorso di ricerca fino a quando il giocatore dista sei passi o meno da loro. (Se il giocatore è più lontano, il nemico passeggia in modo casuale.)

Si noti che il nostro codice di attacco non si preoccupa che l'attore stia attaccando; questo significa che, se l'allineamento è giusto, i nemici si attaccano a vicenda nel tentativo di inseguire il personaggio del giocatore, in stile Doom!

Abbiamo anche aggiunto un messaggio di fine gioco, che è mostrato se uno dei nemici uccide il giocatore.

Ora tutto quello che resta da fare è rendere i nemici capaci di agire ogni volta che il giocatore si muove, il che richiede l'aggiunta di quanto segue alla fine della nostra funzione onKeyUp() , giusto prima di disegnare gli attori nella loro nuova posizione:

Click to view the game so far
Clicca per vedere il gioco fino qui.

Bonus: Versione Haxe

Originariamente ho scritto questo tutorial in un Haxe, un grande linguaggio multi-piattaforma che compila in JavaScript (oltre altri linguaggi). Anche se ho tradotto la versione sopra a mano per assicurarmi una idiosincrasia con il JavaScript, se, come me, preferite Haxe al JavaScript, è possibile trovare la versione Haxe nella cartella haxe nel download dei sorgenti.

È necessario installare prima il compilatore haxe ed è possibile utilizzare qualsiasi editor di testo desiderato, compilare il codice haxe chiamando build.hxml o fare doppio clic sul file build.hxml. Ho anche incluso un progetto FlashDevelop se si preferisce un bel IDE ad un editor di testo e la linea di comando; aprite solo rl.hxproj e premete F5 per eseguire.


Sommario

Questo è tutto! Ora abbiamo una roguelike semplice e completo, con generazione casuale della mappa, il movimento, il combattimento, AI e tutte le condizioni per vincere o perdere.

Ecco alcune idee per nuove funzionalità che è possibile aggiungere al tuo gioco:

  • Livelli multipli
  • Potenziamenti
  • Inventario
  • Materiali di consumo
  • Equipaggiamento

Divertitevi!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.