FAI DA TE IL TUO SIMULATORE DI GIOCO ELETTRONICO

Molti spesso mi chiedono come programmo i miei simulatori.
Beh, spero che questo breve tutorial sia loro utile affinchè possano capire quanto questo tipo di programmazione sia semplice, stimolante e divertente!
Per prima cosa sappiate che io programmo con Delphi 4.0 per Windows 95 della Borland, quindi questo tutorial sarà utile sopratutto agli sviluppatori Delphi.

REQUISITI

Per realizzare il vostro simulatore la prima cosa di cui avete bisogno è il videogioco che vorrete replicare.
Potreste anche avere solo le scansioni, i campioni audio e una descrizione molto dettagliata del funzionamento del giochino originale; ma state sicuri che il simulatore che ne risulterà sarà mooolto differente dal gioco originale!
Lo hardware richiesto è alla portata di tutti: un PC ed uno scanner a colori. Inoltre, se volete usare dei campioni audio dei suoni originali, avrete anche bisogno di una scheda audio e di un microfono.

Io lavoro con un PC con Pentium 166MMX, 32MB RAM, uno scanner da tavolo, una scheda audio SB16 compatibile e un microfono da poche lire.
Il software che uso è: Win95, Delphi 4.0 (della Borland/Inprise), il registratore di suoni di Win95, GoldWave 3.02 (di Chris Craig), Paint Shop Pro 5.0 (della Jasc Software), Microangelo 2.1 (della Impact Software).


CAPITOLO UNO: acquisire le immagini

Partiamo acquisendo con lo scanner le immagini del gioco elettronico.
La prima cosa che dobbiamo considerare è che il gioco non è affatto piatto, quindi lo scanner deve avere una qualche funzione di rilevazione di oggetti 3D attivata, altrimenti non riuscirete a prendere delle buone immagini dello schermo LCD. Per fortuna molti degli scanner più recenti hanno questa funzione.

Ora dobbiamo scegliere il settaggio dei DPI (dots per inch) delle scansioni.
Consiglio importante: salvate le immagini scansionate nel formato bitmap a 24-bit, così non perderanno alcun dettaglio! Dovrete convertirle in formato JPEG o GIF solo alla fine della fase di programmazione, ovvero quano sarete ben sicuri di aver concluso tutto il fotoritocco!

La maggior parte degli utenti di questi simulatori ha il desktop impostato ad 800x600, quindi la vostra immagine non deve essere più grande di questa misura. Comunque, molto dipende dalle dimensioni del gioco elettronico.
Per esempio, l'immagine di sfondo del mio simulatore di Motor Cross supera gli 800 pixels di altezza, ma comunque lo schermo LCD è molto più piccolo! Potete giocarlo a 640x480 o a 800x600 e avrete comunque una buona visione dello schermetto LCD (che è la cosa che conta di più).
Io normalmente scansiono a 80-150 DPI: il mio obiettivo è di avere il background largo 750 o alto 580 pixels. Tutavia siete liberi di scegliere la risoluzione che preferite, ma vi faccio notare che maggiori sono le dimensioni dello schermo LCD, maggiore sarà il dettaglio degli sprites sulo scherno di gioco.

OK, detto questo possiamo passare alla fase di scansione.
Normalmente due scansioni bastano per la gran parte dei giochi.
Fate la prima con il gioco spento (per acquisire lo sfondo dello schermo LCD senza sprites sopra) e la seconda con il gioco acceso (per acquisire gli sprites).
Posizionate il gioco elettronico sul vetro dello scanner, e fate la prima scansione. Ora procedete con la seconda: quella con tutti gli sprites visibili.

Gli schermi LCD normalmente hanno un filtro polarizzante, che dà una certa "direzione" agli sprites perche vengano visualizzati meglio. Posizionate il gioco in modo che la luce dello scanner provenga dal lato superiore del giochino (questo farà sì che i cristalli liquidi degli sprites vengano illuminati dalla giusta direzione!)

Ora cercate di avere TUTTI gli sprites visualizzati.
Molti giochi hanno il bottone ACL, che viene usato in fabbrica per controllare se lo schermo funziona bene. Questo bottone di norma fa mostrare al gioco tutti gli sprites LCD per un momento o per molti minuti.
Se il vostro gioco ha un bottone ACL , sarà probabilmente più facile acquisire tutti gli sprites LCD con una sola passata.
Ma nel caso non ci sia un bottone ACL, o se questo bottone SPEGNE gli sprites (come in Las Vegas della Bandai), dovrete lavorare più duramente per avere le immagini di tutti gli oggetti: avrete bisogno di più scansioni e dopo dovrete riunire tutti gli sprites per ottenere uno schermo completo di tutti gli sprites (usate un programma di grafica come Paint Shop Pro per il ritocco; se non lo avete, anche MS PaintBrush può andare bene).
Alcuni giochi elettronici mostrano tutti i loro sprites premendo TUTTI i bottoni insieme; potete usare un pezzetto di scotch per tenerli tutti premuti nel momento della scansione. Tanto non importa se il gioco viene coperto dallo scotch: quello che vi interessa è solo lo schermo LCD!
Altrimenti potete cercare di mandare in crash la CPU del gioco inserendo e togliendo le batterie dal gioco ripetutamente: la CPU si ferma, e normalmente molti sprites sono visualizzati contemporaneamente.

Ora controllate le immagini così acquisite. Sono abbastanza dettagliate? Se lo sono, andate al Capitolo 2, altrimenti leggete qui di seguito.

Gli sprites possono sembrare troppo confusi e mescolati con lo sfondo; se vi sembra che sia questo caso, aprite il gioco elettronico e cercate di piazzare un foglietto di carta bianca rettangolare tra il fondo del gioco e lo schermo LCD. Così facendo lo sfondo bianco crea un contrasto maggiore, che dovrebbe consentirvi di catturare MOLTI più dettagli!
Se il colore degli sprites non è completamente nero o grigio scuro può essere che il filtro polarizzante sia rovinato; non vi resta che andare da un fotografo, comprarne un altro e sostituirlo.
Poi fate le altre scansioni che vi servono, mantenendo gli stessi DPI utilizzati in quelle precedenti.

Se il gioco si serve di LED (o VFD) e non di LCD, questa procedura non servirà a nulla: la luce dei LED disturberà lo scanner e otterrete delle immagini inutilizzabili. Usate una macchina fotografica digitale.
Ora possiamo passare alla fase di ritocco delle immagini.


CAPITOLO DUE: ritoccare le immagini acquisite

Aprite tutte le immagini con un qualsiasi programma di disegno e controllatele bene.
Il vostro obiettivo è ottenere DUE immagini:
1) un'immagine di "sfondo" del gioco SPENTO, avente risoluzione XxY;
2) un'immagine di "sprites" del gioco ACCESO, avente la stessa risoluzione XxY.
Questo significa che dovrete prendere l'immagine di sfondo e incollarci sopra tutti gli sprites, (state attenti a metterli nella posizione giusta!); quindi questa immagine "mescolata" sarà la sorgente sia per gli sprites e sia per indicarvi la loro posizione relativa all'immgine di sfondo.

Ora prendete il colore di uno degli sprites (la funzione "dropper" di Paint Shop Pro) ed annotate le sue caratteristiche su un foglio di carta: questo sarà il vostro colore di riferimento per tutti gli sprites. Lo useremo dopo. Selezionate un colore vivo (rosso, blu... dipende dal livello di contrasto che gli sprites hanno sul fondale), poi prendete la funzione "pen" e ritracciate con quel colore tutti i contorni di ogni sprite. Questo può essere il lavoro più lungo e noioso, ma il risultato è garantito!

Dopo aver tracciato ogni contorno, usate "fill" (riempimento) sullo sprite con il colore di riferimento, ma potreste anzi preferire di usare un colore leggermente più scuro per l'interno ed un colore leggermente più chiaro per il contorno (o viceversa): a voi l'ardua sentenza.

Quando tutti gli sprites sono stati ritoccati, svuotate l'immagine così ottenuta, riempiendo di bianco ciò che no vi interessa. Selezionate un rettangolo che contenga tutti gli sprites ritoccati, poi copiatene ("copy") il contenuto negli appunti di Windows. Infine incollate ("paste") come "transparent selection" sull'immagine contenente il solo sfondo, sistemando il rettangolo nella giusta posizione!

Ora potete salvare questa immagine come una sorta di sorgente per tutti i vostri sprites.

A questo punto, avrete DUE immagini di sfondo quasi uguali: la prima senza alcuno sprite (chiamiamola BASE.BMP) e la seconda con tutto il set di LCD (chiamiamola SPRITES.BMP).

Il prossimo passo è creare dei singoli files per ogni sprite: un'immagine per ogni sprite.
Selezionate uno sprite da solo, fate un "image crop" e dopo abbassate la profondità di colore a DUE (o 16, in base a quanti colori vi servono per definire i vostri sprites) colori, ovvero 1-bit. Otterrete un'immagine in bianco e nero. Ora editate la palette dei colori attiva ed inserite in questa il colore di riferimento (che dovreste aver annotato) dei vostri sprites. Infine assegnate quel colore al vostro sprite e salvate l'immagine come bitmap 1-bit (o 4-bit) (che occupa meno memoria di una JPG o GIF 8 o 24-bit!). Il bianco (contorno) sarà considerato trasparente da Delphi, e il solo sprite sarà visibile sul fondale del gioco!

Ripetete questa procedura per ogni sprite e salvate tutti i files BMP in una singola cartella.
Avrete anche bisogno dell'intero set di numeri in formato LCD: prendete lo sprite del numero "8" e fate tutte le possibili combinazioni con le linee LCD, fino ad ottenere tutti i 10 numeri (e, casomai, alcune lettere se ve ne servissero). Salvate anche queste immagini.

Adesso potete mettervi al lavoro sulla musica...


CAPITOLO TRE: acquisire e ripulire i suoni

E' giunto il momento di usare il vostro microfono.
Per prima cosa dovrete selezionare il volume di registrazione. Io normalmente uso un volume di registrazione abbastanza alto e l'opzione "+20db" disabilitata. Fate alcune prove e poi scegliete...
Accendete il gioco elettronico e iniziate una partita. Posizionate un microfono vicino allo speaker del giochino e cominciate a registrare (il registratore di suoni di Windows andrà benone) a qualità 44Khz e 16-bit, modo stereo.
Cercate di far riprodurre al gioco tutti i suoni: musichetta di inizio partita se ci fosse, i beeps durante il gioco, musiche di errore e di game over. Ci possono anche essere alcune musichette di bonus. Registratele tutte!

Ora ascoltate i campioni registrati e controllateli tutti. Se il volume del file WAV è troppo basso, potete alzarlo finché non raggiunge un livello adeguato, ma controllate sempre che il suono non venga troppo distorto.
Adesso potete abbassare la qualità del file WAV. Questo aspetto dipende dalla qualità dei suoni del gioco originale. Se state simulando un gioco stereo... beh, i vostri file WAV dovranno essere stereo, se no scegliete voi.
Io trovo che 22Khz, 16-bit, mono è un buon compromesso. Ma se una qualità inferiore vi sembrasse comunque accettabile, allora utilizzate quella, così risparmierete più memoria.

Procediamo quindi con la pulizia del suono, usando un programma come GoldWave o CoolEdit. Spezzettate il file audio contenente più suoni, salvateli e otterrete alcuni WAV. Ogni WAV deve contenere un solo beep o una sola musichetta; notare che non ci deve essere silenzio tra l'inizio del file WAV ed il reale inizio del suono, altrimenti questo non sarà sincronizzato col gioco quando verrà suonato!

Prendete nota della durata di ogni suono: è utile per misurare la velocità del gioco! Esempio: registrate alcuni beep-beep all'inizio della partita; quindi registrate altri beep-beep dopo cinque minuti. Se la velocità del gioco è aumentata, provate a misurare la lunghezza dei due WAV e avrete qualche informazione in più sulle routine che fanno diventare il gioco progressivamente più veloce. Potete anche utilizzare questo tipo di procedura per capire le differenza tra "game A" e "game B", che sono spesso diversi nella velocità di gioco. Semplice, no?

Ora siete pronti per procedere con Delphi.


CAPITOLO QUATTRO: preparare il form principale

Prima di incominciare, settate la proprietà scaled del vostro form su "false", così non sarà ridimensionato da Windows nei computers di chi usa il desktop con "fonts grandi"; usate come risoluzione 96DPI. Non settate il formstyle su "resizable", ma usate "single" o "none" a vostra scelta, e poi fate sparire le icone maximize e minimize dalla barra superiore! Così facendo sarete sicuri che il form sarà sempre visto nella risoluzione corretta!

Posizionate nel form l'immagine BASE.BMP, e lasciate che questa lo ricopra completamente. Adesso potete piazzare tutti gli sprites sul di essa. Aprite SPRITES.BMP con un programma di disegno (Paint Shop Pro va bene), e prendete nota sulle coordinate di ogni immagine; poi create tutte le immagini degli sprite LCD sull'immagine di base sul form Delphi, e assegnate loro le stesse coordinate che avevano in SPRITES.BMP. Spero che questo punto sia abbastanza chiaro.

Potreste simulare la pressione dei bottoni usando un effetto grafico (bottone che cambia colore alla pressione del tasto corrispondente). Dovrete allora prendere una parte di BASE.BMP che contenga quel solo bottone, e salvarla come JPG separata (con fattore di compressione dell'1%, chiamiamola BUTTON1.JPG). Questa la userete per la procedura Image.OnMouseDown di quel pulsante.
Ora considerate di nuovo BASE.BMP ed aumentate o diminuite la luminosità di quel bottone, poi salvatela e sostituitela a quella nel form di Delphi.
Posizonate quindi BUTTON1.JPG sull'immagine di background nella giusta posizione: questa coprirà il bottone schiarito (o scurito) nell'immagine di sfondo.

Potreste decidere che il simulatore possa venir trascinato sul desktop cliccandoci sopra: fate una procedura Form.OnMouseDown ed una Form.OnMouseMove. Queste procedure DEVONO essere associate ad OGNI sprite sullo schermo LCD ed alla grafica di background, ma NON ai bottoni o agli switch!
La cosa migliore è associare quelle procedure alla sola immagine di sfondo e ad un'immagine vuota che creerete appositamente e posizionerete in modo da farle coprire tutti gli sprites, così eviterete di associare la stessa procedura a tutti gli sprites (cosa lunga, noiosa e molto esosa di risorse!).


CAPITOLO CINQUE: iniziare il gioco

Avrete bisogno di molte variabili globali: modalità orologio/demo/gioco, punteggio, records, vite residue, livello corrente; ma dovrete anche definire alcune variabili per abilitare/disabilitare i controlli (che sono sempre legati agli eventi della partita) e per far capire al simulatore quando state giocando oquando il gioco è nella modalità "demo" o "orologio".

Dovrete mettere TUTTE le inizializzazioni richieste nella procedura Form.OnCreate:
1) dovete settare tutti gli "array of TImage" (e "of Integer", ovviamente) se ne usate (e probabilmente vi converrà usarne parecchi);
2) fate sì che ogni componente MediaPlayer carichi un solo file WAV e lo tenga alloccato in memoria: avrete bisogno di molti MediaPlayers, sprecando pochi Kbyte ma guadagnando MOLTO in termini di prestazioni durante il gioco, visto che il simulatore caricherà quei files solo all'avvio del simulatore e non dovrà più leggere dall'HD!
3) inizializzate tutte le variabili che riguardano i controlli e le modalità orologio/gioco.

Create alcune procedure per simulare tutte le pressioni dei bottoni, poi cominciate a lavorare sui "timers".
Comnciate con la procedura "avvio gioco", poi passate a quelle dei movimenti.


CAPITOLO SEI: il componente TTimer

Il componente TTimer è delle risorse più importanti per questo tipo di programmazione.
Un timer esegue un certo numero di operazioni (quelle incluse nella sua procedura OnTimer) ogni tot di millisecondi (dichiarati a priori da voi e che possono essere variati in qualunque momento del gioco).
Per esempio, se il vostro form contiene un timer chiamato "Timer_A", avente la proprietà interval settata a 400, e una procedura come questa:

procedure Timer_ATimer (Sender: TObject);
begin
  Img_LeftSprite.visible:=NOT Img_LeftSprite.visible;
end;

il risultato è che ogni 0.4 secondi l'immagine "Img_LeftSprite" passerà da visibile a invisibile e viceversa, ripetutamente.

Ricordate: i timers possono essere attivi o inattivi, dipende da che cosa volete fare con essi (proprietà enabled impostata come vera=attiva o falsa=inattiva). Ricordate anche che la proprietà interval può essere ridefinita ogni volta che volete, permettendo ad un singolo oggetto timer di avere durata variabile senza dovere usare un altro timer solo per avere durata differente!
Comunque, per un simulatore di gioco elettronico potrete avere bisogno anche di 20 differenti timers o molti di più!


CAPITOLO SETTE: il componente TMediaPlayer

Se volete includere campioni dell'audio del gioco originale, il componente TMediaPlayer è necessario.
Avrete bisogno di molti MediaPlayers: il mio consiglio è di creare un componente mediaplayer per OGNI file WAV che vorrete includere nel simulatore.
Infatti se ogni componente MediaPlayer condivide più files WAV, la vostra applicazione avrà bisogno di caricare il file WAV subito prima di suonarlo, facendo sì che il gioco acceda al HDD molte volte durante la partita! Questo renderà sicuramente il vostro simulatore MOLTO lento e scattoso!

Dovrete nascondere il componente MediaPlayer, impostando la sua proprietà visible come falsa: vedere una barra di un MediaPlayer sul gioco non è per niente utile e ne rovinerebbe la grafica!

Fate caricare e aprire ai MediaPlayes tutti i loro files WAV nella procedura Form.OnCreate in una volta sola:

MPlay_MusicStart.FileName:='.\SOUND\START.WAV';
MPlay_MusicStart.Open;
MPlay_MusicBeep3.FileName:='.\SOUND\BEEP3.WAV';
MPlay_MusicBeep3.Open;

e così di seguito...

Poi dovrete semplicemente piazzare istruzioni come

MPlay_<????>.Play;

dove <????> è il nome del file WAV da suonare durante quel certo momento del gioco. Questo tipo di istruzioni andranno messe all'interno delle diverse procedure di gioco, ogni volta che quel file WAV deve essere suonato. Facile no?


CAPITOLO OTTO: muovere gli sprite del personaggio

Per prima cosa , impostate la proprietà keypreview del form come vera, altrimenti le procedure Form.OnKeyPress, Form.OnKeyDown e Form.OnKeyUp non potranno essere utilizzate. Avete bisogno di queste procedure per controllare il movimento dello sprite del vostro personaggio.

Potete usare Form.OnKeyDown e Form.OnKeyUp in combinazione o la Form.OnKeyPress da sola, questo dipende dalle caratteristiche del gioco.
Io vi mosterò il primo metodo, che è quello più utile per questo tipo di giochi.

La procedura Form.OnKeyDown deve contenere TUTTE le routines dei movimenti; se il vostro sprite può solamente muoversi da destra a sinistra e viceversa, la vostra procedura includerà qualcosa di simile a questo:

if (GameStarted=true) and (Controls=true) then
Controls:=false;
//disabilita i controli finchè il tasto non viene rilasciato;
//se non fate così, gli sprites si muoveranno alla velocità della tastiera,
//che non corrisponde di certo a quella del gioco originale!!!

if key=VK_LEFT then
  if Position>1 then
    begin
      Char_Sprite[position].visible:=false;
//nasconde lo sprite nella posiz. precedente
      Position:=Position-1; //aggiorna la posizione dello sprite
      Char_Sprite[position].visible:=true; //mostra lo sprite nella nuova posizione
    end;

if key=VK_RIGHT then
  if Position<3 then
    begin
      Char_Sprite[position].visible:=false;
//nasconde lo sprite nella posiz. precedente
      Position:=Position+1; //aggiorna la posizione dello sprite
      Char_Sprite[position].visible:=true; //mostra lo sprite nella nuova posizione
    end;

la procedura Form.OnKeyUp serve solo a riportare la variabile Controls su vero (ma solo se si sta giocando ed il giocatore non si trova nel bel mezzo di una routine di errore o altro):

if (GameStarted=true) and (Controls=false) then
  Controls:=true;


CAPITOLO NOVE: lavorare coi numeri LCD

La conversione da numeri (Integer, interi) in una sequenza di numeri LCD (TImage, immagini) è abbastanza difficile, e richiede una buona conoscenza di alcune funzioni aritmetiche come mod e div.

La prima cosa che dovete fare è piazzare le immagini dei numeri sul form, e poi nasconderli (es: Number5.visible:=false;.
Quindi posizionate alcune immagini VUOTE, immagini dove devono apparire i numeri LCD a comporre ora o punteggio (es: NumberPosition2: TImage.
Ogni volta che deve apparire un qualche numero sul display LCD servirà una procedura di questo tipo:

NumberPosition2.picture:=Number5.picture; // (*)

Il modo migliore di richiamare le immagini è associarle ad un array of TImage e dunque indicizzarle con dei numeri.
Probabilmente avrete chiamato le immagini dei numeri Number1, Number2 e così di seguito.
Dichiarate un Number_Array: array [0..9] of TImage nella sezione delle dichiarazioni delle variabili, dopodichè associate ogni numero-immagine ad un elemento di quell'array nella procedura Form.OnCreate.

procedure TForm1.FormCreate(Sender: TObject);
begin
  Number_Array[0]:=Number0;
  Number_Array[1]:=Number1;
  <...>
  Number_Array[9]:=Number9;
end;

così la precedente istruzione (*) diventa

Number_Position2.picture:=Number_Array[5].picture;

Il prossimo passo è quello di dividere il punteggio nelle sue unità, decine, centinaia e così di seguito: imparate ad usare le funzioni mod, div, ed eventualmente IntToStr e StrToInt: è tutto qua.


CAPITOLO DIECI: conclusioni

Spero vi sia piaciuto questo piccolo tutorial. La sua versione originale era stata scritta in inglese, e dunque la sua forma può risultare un po' forzata in questa traduzione. Spero tuttavia che le spiegazioni siano sufficientemente chiare.
A dirla tutta ho scoperto che ci sarebbero altre procedure che vi potrei spiegare, ma penso che questo tutorial sia comunque sufficiente per fornirvi almeno qualche elemento per iniziare il vostro progetto.
L'esperienza ed un buon uso della guida in linea di Delphi vi suggeriranno il modo migliore per procedere.

Se avete qualche domanda potete pure scrivermi, meglio se in italiano! ;)
Cercherò di essere il più chiaro possibile con chiunque avesse dubbi.

In bocca al lupo, amici programmatori!

MADrigal