DevTutorial #13 – Creiamo il nostro primo gioco, Pong! (Parte I)

Eccoci con un nuovo appuntamento dei DevTutorial. Oggi iniziamo con una serie di tutorial che ci permetteranno di creare il nostro primo vero gioco per iPhone! Si tratta di un classico, molto in voga negli anni ’80: stiamo parlando di Pong! Chi non lo conosce?

In questa prima puntata vedremo come realizzare la parte grafica, e come implementare l’algoritmo che si occupa del movimento della pallina senza discostarci dall’obiettivo principale, che resta sempre quello di fornirvi le spiegazioni dettagliate per capire bene tutti i passaggi ed assimilare il codice, in maniera tale da riuscire a ricreare questo gioco secondo i vostri gusti.

1. Creiamo un nuovo progetto

Aprimo Xcode, selezioniamo “File -> New Project”. Nel menù che ci appare selezioniamo “View-based Application”, clicchiamo su “Choose…” e immettiamo come nome “PongTutorial” e fate clic su “Save”. Abbiamo così creato il nostro nuovo progetto.

Il gioco che vogliamo realizzare riprende il classico Pong, un gioco molto di moda negli anni 80. Ecco una semplice bozza del gioco che andremo a realizzare:

Immagine 1

Facciamo un rapido riepilogo dei componenti che ci servono:

  • 3 immagini: una per ogni barra dei giocatori e una per la pallina (saranno di tipo UIImageView);
  • 3 label di testo: due per i punteggi e una per avviare la partita;

Ora che abbiamo definito tutti i componenti possiamo scrivere il codice necessario! Apriamo il file “PongTutorialViewController.h” e inseriamo le seguenti dichiarazioni:

#import <UIKit/UIKit.h>

@interface PongTutorialViewController : UIViewController {
	//i tre componenti per le immagini necessarie
	IBOutlet UIImageView *barraUno;
	IBOutlet UIImageView *barraDue;
	IBOutlet UIImageView *pallina;

	//label per iniziare la partita
	IBOutlet UILabel *textInizia;
	//label per il conteggio dei punti
	IBOutlet UILabel *puntiUno;
	IBOutlet UILabel *puntiDue;

	//stato della partita: in corso o ferma
	NSInteger statoPartita;

	//la velocità della pallina
	CGPoint velocitaPalla;
}

@property (nonatomic, retain) IBOutlet UIImageView *barraUno;
@property (nonatomic, retain) IBOutlet UIImageView *barraDue;
@property (nonatomic, retain) IBOutlet UIImageView *pallina;
@property (nonatomic, retain) IBOutlet UILabel *textInizia;
@property (nonatomic, retain) IBOutlet UILabel *puntiUno;
@property (nonatomic, retain) IBOutlet UILabel *puntiDue;

@property (nonatomic) NSInteger statoPartita;
@property (nonatomic) CGPoint velocitaPalla;

@end

Potete notare che abbiamo dichiarato i componenti che ho descritto poco sopra, insieme ad altre due variabili: una è “statoPartita”, che ci informerà dello stato della partita, ovvero se è in corso oppure è stata terminata; la seconda variabile è “velocitàPalla”, un componente che conterrà due valori: la velocità sull’asse X quella sull’asse Y. Questa variabile ci servirà per far muovere la nostra pallina, che per ora avrà una velocità fissa, non seguirà quindi nessuna particolare legge oraria.

Salviamo ora il nostro file, assicurandoci che l’icona in XCode sia bianca (segno che abbiamo salvato il file, passaggio fondamentale per impostare correttamente la parte grafica).

2. Impostiamo la struttura grafica

Prima di impostare i componenti grafici dobbiamo importare nel progetto le due immagini che ci serviranno: quelle delle barre e della pallina. Potete creare le vostre immagini personalizzate, oppure utilizzare quelle che trovate qui di seguito:

pallina

barra

Salvate le immagini e inseritele nel progetto, semplicemente trascinando le immagini nel progetto di XCode e cliccando “Add” alla schermata che vi apparirà:

Immagine 3

Apriamo ora il file “PongTutorialViewController.xib”, che avvierà Interface Builder. Ora dobbiamo ricreare il layout che abbiamo abbozzato in precedenza. Inseriamo nella vista un componente UIImageView, assegnandoci l’immagine della barra (vi basterà selezionarla dal menù “Attribute Inspector”:

Immagine 4

Rimpicciolite poi i bordi di tale elemento, in modo che i puntini mostrati da IB corrispondano, più o meno, ai bordi dell’immagine. Per capirci, dovrete avere un risultato come questo:

Immagine 5

Inseriamo poi i componenti mancanti, personalizzandoli come preferiamo. Il risultato finale sarà più o meno come questo:

Immagine 6

Ora dobbiamo collegare gli elementi che abbiamo appena inserito con quelli che abbiano dichiarato in precedenza in XCode. Per far ciò, clicchiamo, ad esempio, sulla pallina. Se apriamo, poi, la scheda “Connections Inspector” vediamo che non c’è nessun collegamento:

Immagine 7

Notiamo, però, un pallino, che ci permette di creare nuovi collegamenti. Prendiamo il pallino a fianco di “New Referencing Outlet” e trasciniamolo su “File’s Owner”, nella finestrella che ci mostra tutti i componenti della vista:

Immagine 8

Nel menù a discesa che ci appare selezioniamo, ovviamente, l’elemento “pallina”. Avremo così creato la connessione desiderata. Se avete eseguito i passaggi in maniera corretta avrete un risultato come questo (ovviamente all’interno di “Connections Inspector” della pallina):

Immagine 9

Ripetete ora il procedimento con tutti gli altri elementi, ovvero con le due barre, le due label per il punteggio e la label per avviare la partita.

Salvate poi il tutto e uscite da Interface Builder, tornando ad XCode.

3. Inseriamo le costanti

Ora dobbiamo iniziare a scrivere il codice che permetterà alla nostra pallina di muoversi. Andiamo nel file “PongTutorialViewController.m” e inseriamo il seguente codice:

#import "PongTutorialViewController.h"

//stato della partita
#define kPartitaInCorso 1
#define kPartitaFerma 2

//velocità della pallina sui due assi
#define kVelocitaPallaX 10
#define kVelocitaPallaY 20

@implementation PongTutorialViewController

Abbiamo dichiarato quattro costanti, ovvero delle variabili a cui non potremo cambiare valore durante il corso del nostro programma. Le prime due costanti si riferiscono allo stato della partita, mentre le seconde due alla velocità con cui la pallina si deve muovere. Perchè due valori della velocità? Perchè il nostro gioco è bidimensionale, e quindi ha due componenti: la componente X, data dal movimento orizzontale, e la componente Y, ovvero il movimento verticale. Questi due valori sono modificabili a nostro piacimento, potrete, quindi, variare la velocità con cui la pallina si muove.

Nota teorica: avremmo anche potuto non utilizzare le costanti, ma come vedrete il loro utilizzo ci semplificherà molto il codice, rendendolo più leggibile. Ad esempio, se vogliamo controllare se la partita è in corso dovremo fare:

if (partita == kPartitaInCorso) …

Come potete notare è molto leggibile e immediato. Senza costanti avremmo dovuto scrivere così:

if (partita == 1) …

Il codice non è cambiato, fa sempre lo stesso controllo. Ma sicuramente risulta meno comprensibile, soprattutto se rileggete il codice qualche settimana dopo averlo scritto.

4. Scriviamo i metodi necessari

La prima operazione da compiere è quella di importare gli elementi. Inseriamo, quindi, la seguente istruzione:

@implementation PongTutorialViewController

@synthesize barraUno, barraDue, pallina, textInizia, puntiUno, puntiDue, statoPartita, velocitaPalla;

Dobbiamo adesso definire il metodo che imposterà la aprtita all’avvio del gioco. Per fare questo dobbiamo utilizzare il metodo “viewDidLoad”, che si avvia proprio dopo il caricamento della vista. Inseriamo il seguente codice:

// metodo eseguito al caricamento della vista
- (void)viewDidLoad {
	[super viewDidLoad];
	//impostiamo lo stato iniziale della partita su "fermo"
	self.statoPartita = kPartitaFerma;
	//settiamo la velocità della palla in un componente a due dimensioni
	velocitaPalla = CGPointMake(kVelocitaPallaX, kVelocitaPallaY);
	//avviamo un timer per il movimento della pallina
	[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(gameLoop) userInfo:nil repeats:YES];
}

Potete leggere nei commenti che abbiamo eseguito semplici operazioni di inizializzazione, che ci permettono di iniziare una nuova partita. L’istruzione che merita un po’ più di attenzione è l’inizializzazione di un componente NSTimer (riga 9). Questo elemento si occupa di ripetere l’azione “gameLoop” ogni X secondi, che noi abbiamo settato a 0.05. Quando avremo creato anche il restante codice, provate a modificare tale valore: vedrete che la velocità della pallina cambierà, in quanto l’azione viene ripetuta un numero maggiore o minore di volte. Quindi, con un valore di 1 la pallina sarà molto lenta, mentre se lo portiamo a 0.01 sarà ancora più veloce!

Ora dobbiamo implementare l’algoritmo che fa muovere la nostra pallina. Sempre nel file “PongTutorialViewController.m” scriviamo il seguente metodo:

-(void)gameLoop{
	//controlliamo se la partita è in corso
	if (statoPartita == kPartitaInCorso){
		//muoviamo il centro della pallina, spostandolo con i valori della velocità
		pallina.center = CGPointMake(pallina.center.x + velocitaPalla.x, pallina.center.y + velocitaPalla.y);
		//se il centro è oltre le dimensioni orizzontali della vista, invertiamo la direzione (sempre sull'asse X)
		if (pallina.center.x > self.view.bounds.size.width || pallina.center.x < 0){ 			velocitaPalla.x = -velocitaPalla.x; 		} 		//se il centro è oltre le dimensioni verticali della vista, invertiamo la direzione (sempre sull'asse Y) 		if (pallina.center.y > self.view.bounds.size.height || pallina.center.y < 0){
			velocitaPalla.y = -velocitaPalla.y;
		}
	} else {
		//se la partita è ferma facciamo ricomparire la label per avviare il gioco
		if(textInizia.hidden){
			textInizia.hidden = NO;
		}
	}
}

Non è niente di difficile, i passaggi sono tutti commentati nel codice. Comunque, se la partita è in corso dobbiamo muovere la nostra pallina (controllo alla riga 3), e questo lo facciamo aumentando le coordinate del centro della stessa con i valori che abbiamo impostato alle velocità (ecco percè c’era una componente per l’asse X e una per l’asse Y). Se il centro risulta essere esterno alla vista (riga 7) invertiamo la velocità, in modo da variare la direzione con cui si muove la pallina.

L’ultima azione (per questo tutorial) che dobbiamo implementare riguarda la gestione dell’avvio della partita, ovvero quando l’utente tappa sulla stringa a centro schermo la partita deve cominciare. Aggiungiamo, quindi, il seguente metodo:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
	//se la partita è ferma facciamola iniziare
	if(statoPartita == kPartitaFerma){
		textInizia.hidden = YES;
		statoPartita = kPartitaInCorso;
	}
}

La gestione è un po’ semplificata, in quanto con questo metodo ci basterà cliccare su una parte qualsiasi dello schermo per iniziare la partita. Ma a noi ora basta così.

Completiamo, infine, il metodo “dealloc”, che libera la memoria da noi utilizzata:

- (void)dealloc {
    [super dealloc];
    [pallina release];
    [barraUno release];
    [barraDue release];
    [puntiUno release];
    [puntiDue release];
    [textInizia release];
}

È molto importante gestire nella maniera migliore la memoria, soprattutto quando si sviluppano videogiochi. Un gioco lento e scattoso, infatti, non potrà mai avere successo.

5. Proviamo il gioco!

È giunto il momento di provare il nostro gioco! Clicchiamo su “Build and Go!” e gustiamoci la nostra pallina che vaga per lo schermo!

Immagine 16

Se Avete Problemi, questo è il nostro file di progetto.

La guida è stata creata da Andrea Busi per “iSpazio.net” e “Bubi Devs”. La versione originale inglese del tutorial è disponibile a questo indirizzo: “iPhone Game Programming Tutorial, Part 1 – iCodBlog“. I meriti delle rispettive versioni, quindi, sono dei legittimi autori.

Ingegnere informatico e sviluppatore freelance, mi occupo da anni di sviluppo per iOS (ma non solo). Dal 2008 scrivo su questo piccolo blog (con qualche lunga pausa), in cui parlo di programmazione e di qualsiasi altra cosa che mi diverta.

Leave a reply:

Your email address will not be published.

Site Footer