Ci sono alcuni indie che è sempre bello seguire, e tra questi quel tizio che risponde al nick di Adamatomic, o Mr.Canabalt per i più.
In occasione della ventunesima edizione del Ludum Dare, il buon Adam ha sfornato uno dei 509 giochi presentati. Bomber Planet non è il migliore nè il peggiore, possiamo anzi dire che si mescola tra i tanti, ma è uno di quelli che ho potuto provare (sì, ho provato anche quello di Notch e no, non ne parlerò) e devo dire che mi ha lasciato quel piacevole senso di deja vù.
Ricorda moltissimo un gioco che ho amato nell'Amiga 500: Bomberman. Il gameplay è pressochè identico e il titolo un chiaro richiamo, oltre alla grafica in pixel art. L'unica differenza è che, anzichè farsi strada livello dopo livello nella vecchia concezione arcade, in Bomber Planet occorre esplorare un complesso di caverne per trovare l'uscita (in tema con il titolo del contest: Escape), sfasciando blocchi di pietra e strane creature mediante bombe ad orologeria.
In definitiva un buon coffeebreak game, che ha avuto il merito di riuscire a rievocare davvero il retrogaming, almeno al sottoscritto.
mercoledì 31 agosto 2011
mercoledì 24 agosto 2011
Il servizio web che forse non conoscete: Twitch TV!
Quando ero piccolo e andavo al mare con i miei passavo ore ed ore al bar nella zona cabinet. All'epoca i PC, o meglio i loro antenati, erano poco diffusi e io, neanche a dirlo, non ce l'avevo. Escludendo le sale giochi, che erano per i grandi e irraggiungibili con i miei mezzi di locomozione e la mia età, le uniche mie parentesi videoludiche erano rappresentate da quegli affari ingombranti e luccicosi che trovavo nei bar del mare. Ogni stabilimento ne aveva almeno due o tre, e non esistevano i video poker, ma solo i Wonder Boy, i Final Fight, i Bubble Bobble e gli Altered Beast.
I miei ovviamente non capivano perchè mai volessi stare davanti a quegli affari anzichè in acqua e al sole, e il più delle volte mi toccava obbedire e andare a sguazzare. Ma quando la guardia si abbassava ecco che tornavo in quell'angolino proibito, dove c'era sempre qualche ragazzo più grande che pigiava sui tre tasti colorati.
Giocare costava. 100 lire all'inizio dei miei ricordi, poi 200. Quando iniziò a costare 500 ero già più grande, avevo l'Amiga a casa ed ero più sensibile ad altri richiami da spiaggia. Ai tempi delle 200 lire raccattavo gli spicci in giro e riuscivo a garantirmi tre o quattro partite, ma di quelle partite (sempre troppo brevi) ricordo poco. Ricordo invece quanto fosse bello guardare gli altri giocare. E non ero il solo. Quando arrivava il giocatore quello bravo, si formava un capannello di ragazzini attorno al cabinet. Qualcuno strisciava per terra le sedie fino ai giochi e ci saliva sopra, per vedere meglio da sopra le teste degli altri.
"Dove è arrivato?" domandava qualcuno di passaggio, per il quale vedere lo schermo era ormai impossibile. "Al terzo mostro" rispondeva un altro, senza voltarsi. L'adrenalina saliva. Nuovi ragazzini si accalcavano. Il foglietto attaccato con lo scotch sulla testa del cabinet, quello con la scritta "record:" e il numero inarrivabile, riceveva gli sguardi di tutti man mano che lo score sul display cresceva.
"Sesto schema!" annunciava qualcuno. Chi non aveva mai visto il sesto schema sgomitava per raggiungere un varco visivo allo schermo. Qualcuno dal bar si lamentava per la cagnara e per un po' si procedeva bisbigliando. In spiaggia, dove c'era il sole, l'acqua e la sabbia e il mondo degli adulti era rimasto agli anni '60, giungevano le voci di corridoio più improbabili. Qualcuno stava finendo il gioco. Con quanti gettoni? Uno. Uno? Uno!
Non ho mai visto finire un gioco al mare. Però, in un paio di epiche occasioni, ho visto il barista farsi strada tra una dozzina di ragazzini in costume eccitati e saltellanti e cambiare il numero sul foglietto "record".
Ora, quei giorni sono finiti. Ma c'è un sito in cui questo può accadere di nuovo. Su Twitch TV ci sono infatti i video di migliaia di videogiocatori. Il sito è navigabile per gioco, quindi interessante per vedere il gameplay del tal gioco o ammirare l'abilità di quello bravo, o magari capire come superare un certo punto a noi impossibile.
Certo, non è proprio la stessa cosa. Anche perchè noi, da ragazzini, non sapevamo nemmeno cosa fosse il gameplay.
I miei ovviamente non capivano perchè mai volessi stare davanti a quegli affari anzichè in acqua e al sole, e il più delle volte mi toccava obbedire e andare a sguazzare. Ma quando la guardia si abbassava ecco che tornavo in quell'angolino proibito, dove c'era sempre qualche ragazzo più grande che pigiava sui tre tasti colorati.
Giocare costava. 100 lire all'inizio dei miei ricordi, poi 200. Quando iniziò a costare 500 ero già più grande, avevo l'Amiga a casa ed ero più sensibile ad altri richiami da spiaggia. Ai tempi delle 200 lire raccattavo gli spicci in giro e riuscivo a garantirmi tre o quattro partite, ma di quelle partite (sempre troppo brevi) ricordo poco. Ricordo invece quanto fosse bello guardare gli altri giocare. E non ero il solo. Quando arrivava il giocatore quello bravo, si formava un capannello di ragazzini attorno al cabinet. Qualcuno strisciava per terra le sedie fino ai giochi e ci saliva sopra, per vedere meglio da sopra le teste degli altri.
"Dove è arrivato?" domandava qualcuno di passaggio, per il quale vedere lo schermo era ormai impossibile. "Al terzo mostro" rispondeva un altro, senza voltarsi. L'adrenalina saliva. Nuovi ragazzini si accalcavano. Il foglietto attaccato con lo scotch sulla testa del cabinet, quello con la scritta "record:" e il numero inarrivabile, riceveva gli sguardi di tutti man mano che lo score sul display cresceva.
"Sesto schema!" annunciava qualcuno. Chi non aveva mai visto il sesto schema sgomitava per raggiungere un varco visivo allo schermo. Qualcuno dal bar si lamentava per la cagnara e per un po' si procedeva bisbigliando. In spiaggia, dove c'era il sole, l'acqua e la sabbia e il mondo degli adulti era rimasto agli anni '60, giungevano le voci di corridoio più improbabili. Qualcuno stava finendo il gioco. Con quanti gettoni? Uno. Uno? Uno!
Non ho mai visto finire un gioco al mare. Però, in un paio di epiche occasioni, ho visto il barista farsi strada tra una dozzina di ragazzini in costume eccitati e saltellanti e cambiare il numero sul foglietto "record".
Ora, quei giorni sono finiti. Ma c'è un sito in cui questo può accadere di nuovo. Su Twitch TV ci sono infatti i video di migliaia di videogiocatori. Il sito è navigabile per gioco, quindi interessante per vedere il gameplay del tal gioco o ammirare l'abilità di quello bravo, o magari capire come superare un certo punto a noi impossibile.
Certo, non è proprio la stessa cosa. Anche perchè noi, da ragazzini, non sapevamo nemmeno cosa fosse il gameplay.
lunedì 22 agosto 2011
HowTo: Guitar recording in linux
La settimana di ferragosto ha sacrificato in parte le attività di codelicks, ma mi ha dato modo di fare qualche esperimento casalingo con la mia fida Fedora.
L'HowTo di oggi si discosta per un momento dalla programmazione e dai videogiochi e si concentra invece sul come riuscire a registrare la propria chitarra, con tanto di batteria, usando software free e open source disponibile nei repository.
Il mio obiettivo era infatti questo: avevo bisogno di costruire una traccia di batteria, anche minimale, e di registrare una base di accompagnamento in modo da poterci poi suonare sopra, per esercizio, assoli, improvvisazioni e quant'altro.
Ci sono riuscito, ma c'è stato bisogno del lavoro sinergico di ben 4 software! Eccoli:
Hydrogen supporta due concetti: pattern e song. Il primo rappresenta il mattoncino col quale costruire il brano, ovvero la song. Il pattern è solitamente piccolo, una o due battute, e lo si edita tramite la griglia in basso. La song è l'unione consecutiva di uno o più pattern, e la si crea tramite la griglia in alto, dove le righe sono i pattern.
In questo modo è veramente possibile creare basi di batteria anche complesse con il minimo sforzo, utilizzando pochi semplici pattern.
Nel mio caso specifico, ho creato un solo pattern di una battuta con un 4/4 basilare di cassa e rullante, quindi una song di una battuta.
Al termine è possibile esportare la song in formato audio.
E' possibile costruirsi il proprio rack o provarne le decine di preimpostati (dai nomi evocativi come "Satriani", "Jazzy", "Metal tone" ecc.). Gli effetti possono venire spenti/accesi, regolati nei vari parametri, riordinati come sequenza, sostituiti con altri.
Nella mia esperienza ho notato però alcune cosucce:
Lo apro e importo come traccia audio la song esportata da Hydrogen, quindi in effetti->ripeti la faccio ripetere per 30 volte, ottenendo un bel 4/4 di 30 battute.
Nella toolbar ho un paio di combobox in cui specificare le sorgenti di input e output. Cerco JACK e lo imposto, quindi come input seleziono rakarrack (che mi viene mostrato grazie a JACK) e come output quello di sistema.
Faccio REC e suono: la mia chitarra distorta appare come linea bella frastagliata nella nuova traccia audio!
Al termine della registrazione mi rendo conto che il tutto è fuori tempo rispetto alla batteria... ricordate il problemino del ritardo? Già...
Ma niente paura, mi posiziono sul primo attacco della mia traccia di chitarra, seleziono tutto quel che segue, taglio e sposto il cursore con le frecce sul battere di cassa corretto. Incolla e via, il brano è di nuovo perfettamente a tempo.
Tutto il resto, ovvero registrare una buona traccia, è (purtroppo) un'altra storia...
L'HowTo di oggi si discosta per un momento dalla programmazione e dai videogiochi e si concentra invece sul come riuscire a registrare la propria chitarra, con tanto di batteria, usando software free e open source disponibile nei repository.
Il mio obiettivo era infatti questo: avevo bisogno di costruire una traccia di batteria, anche minimale, e di registrare una base di accompagnamento in modo da poterci poi suonare sopra, per esercizio, assoli, improvvisazioni e quant'altro.
Ci sono riuscito, ma c'è stato bisogno del lavoro sinergico di ben 4 software! Eccoli:
JACK
Il primo software di cui avrete bisogno è JACK, un server audio che si prefigge lo scopo di intercettare l'output audio di una applicazione e indirizzarlo come input in una seconda applicazione. Sembra complicato, ma per quel che dovremo fare noi sarà sufficiente scaricare JACK e il suo client (io ne ho usato uno basato su QT) e avviarlo. Al resto penserà lui.Hydrogen
Il secondo software ci permetterà di editare la nostra batteria: Hydrogen. Si tratta di una drum machine veramente semplice da utilizzare e al tempo stesso molto flessibile. Editando la griglia nella parte bassa possiamo piazzare i colpi col suono del pezzo in riga: cassa, rullante, charleston (aperto e chiuso), tom alto e basso, piatti ecc. Supporta naturalmente ritmi binari e ternari e la possibilità di variare facilmente la velocità, espressa in bpm.Hydrogen supporta due concetti: pattern e song. Il primo rappresenta il mattoncino col quale costruire il brano, ovvero la song. Il pattern è solitamente piccolo, una o due battute, e lo si edita tramite la griglia in basso. La song è l'unione consecutiva di uno o più pattern, e la si crea tramite la griglia in alto, dove le righe sono i pattern.
In questo modo è veramente possibile creare basi di batteria anche complesse con il minimo sforzo, utilizzando pochi semplici pattern.
Nel mio caso specifico, ho creato un solo pattern di una battuta con un 4/4 basilare di cassa e rullante, quindi una song di una battuta.
Al termine è possibile esportare la song in formato audio.
Rakarrack
Ecco chi fa la vera magia: trasformare il nostro pc in un rack per chitarra, con amplificazione ed effettistica! Rakarrack fa esattamente questo. E' sufficiente inserire la chitarra nella presa microfono (senza alcuna preamplificazione), assicurarsi che JACK rilevi Rakarrack e suonare. Dalle casse uscirà il suono modificato dal rack di effetti caricati.E' possibile costruirsi il proprio rack o provarne le decine di preimpostati (dai nomi evocativi come "Satriani", "Jazzy", "Metal tone" ecc.). Gli effetti possono venire spenti/accesi, regolati nei vari parametri, riordinati come sequenza, sostituiti con altri.
Nella mia esperienza ho notato però alcune cosucce:
- Senza specificare nelle opzioni di preferenza l'abilitazione automatica degli effetti non ottenevo alcun suono: l'abilita/disabilita manuale sembrava non funzionare
- Per ottenere una migliore qualità del suono ho dovuto abbassare il livello di input (-20 circa) ed aumentare leggermente quello di output (+10 circa): così facendo ho eliminato una fastidiosa e non voluta distorsione, specie sugli accordi
- Probabilmente dipenderà dal mio portatile e dalla sua non proverbiale potenza, ma il segnale audio in uscita ha un ritardo di circa 1 secondo.
Audacity
Ed è finalmente giunto il momento di unire il tutto! Serve un software per fare editing multitraccia. Il più semplice, quasi banale, che conosco è Audacity.Lo apro e importo come traccia audio la song esportata da Hydrogen, quindi in effetti->ripeti la faccio ripetere per 30 volte, ottenendo un bel 4/4 di 30 battute.
Nella toolbar ho un paio di combobox in cui specificare le sorgenti di input e output. Cerco JACK e lo imposto, quindi come input seleziono rakarrack (che mi viene mostrato grazie a JACK) e come output quello di sistema.
Faccio REC e suono: la mia chitarra distorta appare come linea bella frastagliata nella nuova traccia audio!
Al termine della registrazione mi rendo conto che il tutto è fuori tempo rispetto alla batteria... ricordate il problemino del ritardo? Già...
Ma niente paura, mi posiziono sul primo attacco della mia traccia di chitarra, seleziono tutto quel che segue, taglio e sposto il cursore con le frecce sul battere di cassa corretto. Incolla e via, il brano è di nuovo perfettamente a tempo.
Tutto il resto, ovvero registrare una buona traccia, è (purtroppo) un'altra storia...
venerdì 12 agosto 2011
Sviluppare giochi per Google+
Google+ non necessita ormai più di presentazioni. Ad ormai due mesi dal suo lancio la piattaforma social di Google ha guadagnato una notevole fetta di utenti che, per chissà quale motivo, sembrano essere in maggioranza tecnici e creativi del web: programmatori, grafici, musicisti e, naturalmente, tanti sviluppatori indie.
David Glazer, un responsabile di progetto di Google, ha annunciato sul suo profilo l'apertura di un interessante blog: the Google+ Platform blog.
Scopo del Platform Blog sarà quello di introdurre gli sviluppatori volenterosi alle API di integrazione di Google+, e aprire quindi la strada ad una nuova generazione di applicazioni e, quel che interessa a noi, giochi. E' infatti quel che viene promesso in questo post del blog ufficiale di G+.
Una nuova corsa all'oro quindi. Resta da capire se G+ opterà per un sistema di scrematura in stile Apple (che non sembra comunque aver dato i risultati attesi, si vedano le FartApp...) o se lascerà aperte le frontiere di questo nuovo far west.
mercoledì 10 agosto 2011
Il gioco indie che forse non conoscete: Legends of Yore!
Legends of Yore è un altro roguelike grafico ben fatto, ricco e profondo, che giunge in un momento di grande vitalità per il genere (Desktop Dungeons, Dungeons of Dredmor, Cardinal Quest, solo per citarne alcuni). Si può scegliere tra tre personaggi: l'immancabile guerriero e la sua controparte, il mago, più l'arciere, che va a riempire lo spazio solitamente occupato da classi quali il ladro.
I tre personaggi offrono opzioni, abilità e stili di gioco differenti, risultando comunque ben calibrate. Il mondo di gioco appare solido e la grafica a 8 bit, molto curata e coerente, aumenta la piacevole sensazione di trovarsi davanti ad un gioco completo.
I livelli dei dungeon sono generati proceduralmente ogni volta che vi ci accede, mentre le "esterne" (città, villaggi, boschi, pianure ecc.) sono formate da mappe fisse.
Lo sviluppatore sembra aver ovviato al problema del field of view del personaggio optando per una risoluzione video veramente infima: si gioca in un rettangolino di finestra degno di uno smartphone, e forse non a caso: Legends of Yore è infatti disponibile, oltre che per PC, per iOS e Android.
(NB: La versione per desktop contiene anche l'opzione per visualizzare a 800x600, ma in questo caso la mancata implementazione del fields of view risulta in un'area visualizzata troppo ampia che può, in parte, togliere il gusto dell'esplorazione.)
Altro punto a favore è dato dallo sviluppo ancora in corso del progetto, che anzi rilascia continui aggiornamenti (scaricati e installati automaticamente all'avvio del gioco). Potete seguire le vicende delle Leggende sul forum del sito e sul canale twitter.
In definitiva un altro bel colpo messo a segno da un singolo indie!
I tre personaggi offrono opzioni, abilità e stili di gioco differenti, risultando comunque ben calibrate. Il mondo di gioco appare solido e la grafica a 8 bit, molto curata e coerente, aumenta la piacevole sensazione di trovarsi davanti ad un gioco completo.
I livelli dei dungeon sono generati proceduralmente ogni volta che vi ci accede, mentre le "esterne" (città, villaggi, boschi, pianure ecc.) sono formate da mappe fisse.
Lo sviluppatore sembra aver ovviato al problema del field of view del personaggio optando per una risoluzione video veramente infima: si gioca in un rettangolino di finestra degno di uno smartphone, e forse non a caso: Legends of Yore è infatti disponibile, oltre che per PC, per iOS e Android.
(NB: La versione per desktop contiene anche l'opzione per visualizzare a 800x600, ma in questo caso la mancata implementazione del fields of view risulta in un'area visualizzata troppo ampia che può, in parte, togliere il gusto dell'esplorazione.)
Altro punto a favore è dato dallo sviluppo ancora in corso del progetto, che anzi rilascia continui aggiornamenti (scaricati e installati automaticamente all'avvio del gioco). Potete seguire le vicende delle Leggende sul forum del sito e sul canale twitter.
In definitiva un altro bel colpo messo a segno da un singolo indie!
lunedì 8 agosto 2011
Tutorial: Scriviamo un gioco in C++... Tris! (parte 5)
La volta scorsa abbiamo implementato le funzionalità di menu, permettendo di raggiungere la schermata di gioco, tornare indietro e uscire. La stato di gioco mostrava però solo una schermata nera... ben poco entusiasmante!
Oggi colmeremo questa lacuna, giungendo finalmente ad implementare il gioco. Fino ad ora, infatti, abbiamo analizzato e scritto solo codice di contorno. Quel che faremo in questo post sarà riempire invece di istruzioni la classe
Poca roba. I tre puntatori che vengono inizializzati a null sono puntatori a
Osservare il distruttore è un po’ come leggere i titoli di coda di un film prima di aver visto il film! Possiamo capire chi erano gli attori e intuire quali parti recitavano. Vediamo infatti la liberazione dalla memoria delle tre
Beh, qui in effetti qualche nodo giunge al pettine, e si scopre cosa sia il famigerato
Ok, niente di nuovo, semplicemente alla pressione di ESC mandiamo alla classe principale il segnale
Uh! Questo è un bel pezzo di codice! Corposo e denso di significati... in effetti si tratta della gestione del click del mouse, ovvero il cuore del gameplay. Qui è, in sostanza, il posto dove si fa il gioco.
Scopo di questa funzione è aggiornare lo stato dell’oggetto
Il primo controllo che viene fatto è per capire se il click del mouse rientra nell’area in cui abbiamo disegnato la griglia (come avviene nel metodo Draw, naturalmente). Le costanti hardcodate (19, 94 e 99) sono una piccola vergogna che ho voluto lasciare, un po’ per far nascere nel lettore il giusto senso di ribrezzo, un po’ per non appesantire la leggibilità del codice con troppi nomi. Rappresentano comunque la distanza della griglia dal bordo (19 pixel) e la dimensione del lato di ogni cella (94 pixel). 99 è invece l’offset verticale (sempre in pixel) da cui parte la griglia. Non perdeteci tempo, sono solo numeri.
Una volta stabilito che il click è ricaduto all’interno della griglia, si tratta di decidere in quale cella. A questo scopo vi è il piccolo calcolo che porta a valorizzare le due variabili
Se il player non ha ancora vinto si procede invece con la mossa del computer. Questo è il punto in cui dovremo tornare in un secondo momento, quando si tratterà di sviluppare la AI. Per ora il computer è veramente sciocco e si limita a piazzare il suo segno in un punto a caso, scegliendolo pure in modo non troppo furbo (ci sarebbe potenzialmente un deadlock, ma sono talmente poche le possibilità che il prima o poi uno spiazzo vuoto lo trova dovrebbe portare via pochi cicli).
Viene infine incrementato un contatore delle mosse: già, perchè le partite finiscono anche in parità, quando nessuno fa tris ma non esistono più celle disponibili.
Il caso di vittoria del computer è, naturalmente, speculare a quello già visto per il player.
Mmm, ok, lo ammetto... Tris è veramente un gioco povero! La funzione Update ce lo dimostra...
Ecco svelati i segreti dietro ai numeretti hardcodati! Lascio a voi l’analisi di questa funzione, che altro non fa che disegnare la griglia (usando delle chiamate a
Nel caso di vittoria di qualcuno, poi, viene mostrato il testo all’interno di un box nero, al centro dello schermo.
L’implementazione dello stato di gioco ha reso necessaria l’introduzione di un ulteriore metodo virtuale puro nella classe base:
Ed ecco infine le tre funzioni che verificano se qualcuno ha vinto. Sono tre, ma in realtà è una, come vedete. Il controllo è banale: semplicemente si verificano tutte le possibilità, senza scienze particolari.
Nella prossima puntata vedremo come istruire il computer per essere un po’ meno tonto... sì, parleremo di AI!
Buon coding!
Oggi colmeremo questa lacuna, giungendo finalmente ad implementare il gioco. Fino ad ora, infatti, abbiamo analizzato e scritto solo codice di contorno. Quel che faremo in questo post sarà riempire invece di istruzioni la classe
PlayGameState
. La struttura di PlayGameState
è naturalmente la stessa di TitleScreenGameState
, ereditando entrambe da AbstractGameState
. Vediamo, metodo per metodo, come cambia invece l’implementazione.Il Costruttore
PlayGameState::PlayGameState(ApplicationMessageHandler* pMessageHandler) : AbstractGameState(pMessageHandler) { //ctor m_pX = 0; m_pO = 0; m_pWinText = 0; }
Poca roba. I tre puntatori che vengono inizializzati a null sono puntatori a
SDL_Surface
e conterranno le immagini rispettivamente del simbolo X (del player), del simbolo O (del computer) e del rendering di un testo che mostreremo in caso di vittoria di qualcuno.Il Distruttore
PlayGameState::~PlayGameState() { //dtor SDL_FreeSurface(m_pX); SDL_FreeSurface(m_pO); TTF_CloseFont(m_pFont); if(m_pWinText) { SDL_FreeSurface(m_pWinText); } }
Osservare il distruttore è un po’ come leggere i titoli di coda di un film prima di aver visto il film! Possiamo capire chi erano gli attori e intuire quali parti recitavano. Vediamo infatti la liberazione dalla memoria delle tre
SDL_Surface
e la chiusura di un inedito TTF_Font
. Load
int PlayGameState::Load() { int result = 0; result = LoadOptimizedImage("tris_x.bmp", &m_pX); result += LoadOptimizedImage("tris_o.bmp", &m_pO); m_pFont = TTF_OpenFont("arial.ttf", 24); return result; }
Beh, qui in effetti qualche nodo giunge al pettine, e si scopre cosa sia il famigerato
m_pFont
: SDL_ttf ci permette infatti di creare un oggetto in grado di disegnare del testo su una surface con un certo font e una certa dimensione, prendendo le informazioni da uno standard file ttf. Se non avete mai affrontato il problema del rendering del testo in altri contesti grafici, non sapete quanto questo sia utile!HandleKeyboardInput
void PlayGameState::HandleKeyboardInput(const SDLKey& key, const SDL_EventType& type) { if(type == SDL_KEYDOWN) { switch(key) { case SDLK_ESCAPE: m_pMessageHandler->HandleMessage(EMT_TITLE); break; } } }
Ok, niente di nuovo, semplicemente alla pressione di ESC mandiamo alla classe principale il segnale
EMT_TITLE
, che servirà a cambiare lo stato corrente da Play a TitleScreen.HandleMouseInput
void PlayGameState::HandleMouseInput(const int x, const int y, Uint8 button, const SDL_EventType& type) { SDL_Rect gridRect; gridRect.h = 282; gridRect.w = 282; gridRect.x = 19; gridRect.y = 99; // se qualcuno ha già vinto non si gioca più if(m_PlayerWins || m_ComputerWins) return; // ho fatto click dentro la griglia? if(IsPointInRect(x, y, gridRect)) { // tasto sinistro? if(button == SDL_BUTTON_LEFT && type == SDL_MOUSEBUTTONUP) { // quale quadrante? int gridx = (x - 19) / 94; int gridy = (y - 99) / 94; if(m_Grid[gridy][gridx] != EGS_NONE) return; m_Grid[gridy][gridx] = EGS_X; if(CheckPlayerVictory()) { m_PlayerWins = true; if(m_pWinText) { SDL_FreeSurface(m_pWinText); } SDL_Color textColor = {0,255,0}; m_pWinText = TTF_RenderText_Solid(m_pFont, "Player Wins!", textColor); } else { // eseguo la mossa del computer if(m_SymbolsPlacedCount < 8) { bool ok = false; while(!ok) { gridx = rand()%3; gridy = rand()%3; if(m_Grid[gridy][gridx] == EGS_NONE) { ok = true; m_Grid[gridy][gridx] = EGS_O; } } m_SymbolsPlacedCount += 2; } if(CheckComputerVictory()) { m_ComputerWins = true; if(m_pWinText) { SDL_FreeSurface(m_pWinText); } SDL_Color textColor = {255,0,0}; m_pWinText = TTF_RenderText_Solid(m_pFont, "Computer Wins!", textColor); } } } } }
Uh! Questo è un bel pezzo di codice! Corposo e denso di significati... in effetti si tratta della gestione del click del mouse, ovvero il cuore del gameplay. Qui è, in sostanza, il posto dove si fa il gioco.
Scopo di questa funzione è aggiornare lo stato dell’oggetto
m_Grid
, una griglia 3x3 di un enumerativo che descrive i tre stati in cui si può trovare una cella: vuota, con una X o con un O. Ci sono anche un paio di booleani che tengono conto del fatto che qualcuno tra player o computer possa aver vinto la partita. Il primo controllo che viene fatto è per capire se il click del mouse rientra nell’area in cui abbiamo disegnato la griglia (come avviene nel metodo Draw, naturalmente). Le costanti hardcodate (19, 94 e 99) sono una piccola vergogna che ho voluto lasciare, un po’ per far nascere nel lettore il giusto senso di ribrezzo, un po’ per non appesantire la leggibilità del codice con troppi nomi. Rappresentano comunque la distanza della griglia dal bordo (19 pixel) e la dimensione del lato di ogni cella (94 pixel). 99 è invece l’offset verticale (sempre in pixel) da cui parte la griglia. Non perdeteci tempo, sono solo numeri.
Una volta stabilito che il click è ricaduto all’interno della griglia, si tratta di decidere in quale cella. A questo scopo vi è il piccolo calcolo che porta a valorizzare le due variabili
gridx
e gridy
, con le quali possiamo accedere alla matrice m_Grid
e, se la cella è libera, segnarla con il simbolo del player, la X. Subito dopo parte una procedura che verifica se la mossa sia stata vincente per il player e, nel caso, imposta il booleano a guardia di questo evento e crea la SDL_Surface con il testo “Player Wins!” di colore verde.Se il player non ha ancora vinto si procede invece con la mossa del computer. Questo è il punto in cui dovremo tornare in un secondo momento, quando si tratterà di sviluppare la AI. Per ora il computer è veramente sciocco e si limita a piazzare il suo segno in un punto a caso, scegliendolo pure in modo non troppo furbo (ci sarebbe potenzialmente un deadlock, ma sono talmente poche le possibilità che il prima o poi uno spiazzo vuoto lo trova dovrebbe portare via pochi cicli).
Viene infine incrementato un contatore delle mosse: già, perchè le partite finiscono anche in parità, quando nessuno fa tris ma non esistono più celle disponibili.
Il caso di vittoria del computer è, naturalmente, speculare a quello già visto per il player.
Update
void PlayGameState::Update() { }
Mmm, ok, lo ammetto... Tris è veramente un gioco povero! La funzione Update ce lo dimostra...
Draw
void PlayGameState::Draw() { SDL_Surface* screen = SDL_GetVideoSurface(); // sbianco lo schermo SDL_FillRect(screen, 0, 0xffffff); // disegno la griglia di gioco 3x3 // linee verticali SDL_Rect grid; grid.h = 282; grid.w = 3; grid.x = 19+94; grid.y = 99; SDL_FillRect(screen, &grid, 0x000000); grid.h = 282; grid.w = 3; grid.x = 19+94+94; grid.y = 99; SDL_FillRect(screen, &grid, 0x000000); // linee orizzontali grid.h = 3; grid.w = 282; grid.x = 19; grid.y = 99+94; SDL_FillRect(screen, &grid, 0x000000); grid.h = 3; grid.w = 282; grid.x = 19; grid.y = 99+94+94; SDL_FillRect(screen, &grid, 0x000000); // disegno i simboli in griglia SDL_Rect dst; for(int r=0; r<3; ++r) { for(int c=0; c<3; ++c) { dst.h = 94; dst.w = 94; dst.y = 99 + (r*94); dst.x = 19 + (c*94); switch(m_Grid[r][c]) { case EGS_X: SDL_BlitSurface(m_pX, 0, screen, &dst); break; case EGS_O: SDL_BlitSurface(m_pO, 0, screen, &dst); break; case EGS_NONE: break; } } } if(m_PlayerWins || m_ComputerWins) { dst.h = m_pWinText->h; dst.w = m_pWinText->w; dst.x = 160 - (m_pWinText->w / 2); dst.y = 240 - (m_pWinText->h / 2); SDL_Rect box; box.h = dst.h * 2; box.w = 320; box.x = 0; box.y = dst.y - (dst.h / 2); SDL_FillRect(screen, &box, 0x000000); SDL_BlitSurface(m_pWinText, 0, screen, &dst); } }
Ecco svelati i segreti dietro ai numeretti hardcodati! Lascio a voi l’analisi di questa funzione, che altro non fa che disegnare la griglia (usando delle chiamate a
SDL_FillRect
e disegnando con esse le quattro linee necessarie) e interpretare i dati nella matrice m_Grid
per piazzare i giusti simboli all’interno delle celle.Nel caso di vittoria di qualcuno, poi, viene mostrato il testo all’interno di un box nero, al centro dello schermo.
Reset
void PlayGameState::Reset() { m_SymbolsPlacedCount = 0; m_PlayerWins = m_ComputerWins = false; if(m_pWinText) { SDL_FreeSurface(m_pWinText); } m_pWinText = 0; for(int r=0; r<3; ++r) { for(int c=0; c<3; ++c) { m_Grid[r][c] = EGS_NONE; } } }
L’implementazione dello stato di gioco ha reso necessaria l’introduzione di un ulteriore metodo virtuale puro nella classe base:
Reset
. Con Reset
si riportano alla situazione iniziale tutte le variabili membro dello stato. Viene chiamata da Tris ogni volta che uno stato diventa lo stato attuale, permettendo in questo caso partite successive.Condizioni di vittoria
bool PlayGameState::CheckComputerVictory() { return CheckVictoryForSymbol(EGS_O); } //----------------------------------------------------------------------------- bool PlayGameState::CheckPlayerVictory() { return CheckVictoryForSymbol(EGS_X); } //----------------------------------------------------------------------------- bool PlayGameState::CheckVictoryForSymbol(PlayGameState::GridSymbols sym) { if(m_Grid[0][0] == sym) { if(m_Grid[0][1] == sym && m_Grid[0][2] == sym) return true; if(m_Grid[1][1] == sym && m_Grid[2][2] == sym) return true; if(m_Grid[1][0] == sym && m_Grid[2][0] == sym) return true; } if(m_Grid[1][0] == sym) { if(m_Grid[1][1] == sym && m_Grid[1][2] == sym) return true; } if(m_Grid[2][0] == sym) { if(m_Grid[2][1] == sym && m_Grid[2][2] == sym) return true; } return false; }
Ed ecco infine le tre funzioni che verificano se qualcuno ha vinto. Sono tre, ma in realtà è una, come vedete. Il controllo è banale: semplicemente si verificano tutte le possibilità, senza scienze particolari.
Nella prossima puntata vedremo come istruire il computer per essere un po’ meno tonto... sì, parleremo di AI!
Buon coding!
mercoledì 3 agosto 2011
Il gioco indie che forse non conoscete: Continuity!
Continuity è un originale puzzle game sviluppato dagli svedesi Ragtime Games nel 2009, vincitore di ben due prestigiosi premi: il Best Student Game alll’Independent Games Festival (2010) e il Gameplay Innovation Award all’IndieCade (2010).
Una tale abbondanza di titoli non giunge mai a caso, e Continuity non sembra aver rubato proprio nulla. Il gameplay è una via di mezzo tra un platform, un puzzle e il cubo di rubik! Già al secondo dei trentadue livelli saremo costretti a capire e padroneggiare i (pochi) meccanismi necessari a risolvere il problema. Che è lo stesso, in tutti i livelli: raccogliere la chiave rossa e raggiungere la porta rossa, nella buona vecchia tradizione del minimalismo indie.
In questi giorni è disponibile anche Continuity 2 per iPhone e iPad, ovviamente su AppStore.
Una tale abbondanza di titoli non giunge mai a caso, e Continuity non sembra aver rubato proprio nulla. Il gameplay è una via di mezzo tra un platform, un puzzle e il cubo di rubik! Già al secondo dei trentadue livelli saremo costretti a capire e padroneggiare i (pochi) meccanismi necessari a risolvere il problema. Che è lo stesso, in tutti i livelli: raccogliere la chiave rossa e raggiungere la porta rossa, nella buona vecchia tradizione del minimalismo indie.
In questi giorni è disponibile anche Continuity 2 per iPhone e iPad, ovviamente su AppStore.
Iscriviti a:
Post (Atom)