Programmare la GP2X - parte 1
posted in programmazione, c++, sdl, gp2x |La GP2X è una splendida console portatile basata su standard aperti, in particolare GNU/Linux. Su gp2xdev.net è iniziata un’ottima serie di articoli sulla programmazione della GP2X in C con le librerie SDL. Nella lezione 1 vengono introdotti i rudimenti della programmazione SDL, corredati da un esempio volutamente semplice con la classica pallina che rimbalza ai quattro lati dello schermo. Raccogliendo l’invito degli autori a modificare i sorgenti e a sperimentare, ho voluto aggiungere un po’ di struttura individuando ed implementando alcune classi. Ho sfruttato così l’occasione anche per studiare un po’ di C++, provenendo io dal Java. Ovviamente una struttura del genere è superflua per un esercizio così semplice, ma diventa indispensabile con progetti appena più ambiziosi, o anche soltanto per estendere un po’ le funzionalità previste inizialmente dalla simulazione. Per quanto concerne l’installazione degli strumenti di sviluppo rimando alla lezione 0 della serie.
Nell’esempio originale tutta la logica risiede nel metodo main(), che si occupa di inizializzare l’ambiente SDL e far muovere lo sprite della pallina. In prima approssimazione ho ritenuto utile individuare e separare il concetto di corpo che si muove in uno spazio. Tale spazio è l’ambiente con cui il corpo interagisce e alle cui regole deve sottostare, per esempio quando ne raggiunge i confini. Di qui le classi Corpo e Ambiente.
La classe Corpo possiede alcune proprietà, come la posizione, la velocità e la direzione di spostamento. In base a queste caratteristiche il corpo si muove, cioè cambia la sua posizione.
class Corpo { public: Corpo(); SDL_Rect posizione() const { return m_posizione; } SDL_Rect velocita() const { return m_velocita; } SDL_Surface* surface() const { return m_surface; } void setDirezione(SDL_Rect direzione) { m_direzione = direzione; } void move(); private: SDL_Surface* m_surface; // struttura delle sdl che conterra’ le coordinate dello sprite SDL_Rect m_posizione; // vettore per la velocita’ del corpo SDL_Rect m_velocita; // vettore per la direzione di movimento del corpo SDL_Rect m_direzione; };
La classe Ambiente incapsula l’ambiente SDL e detta le leggi fisiche alle quali obbedisce il corpo, ad esempio come varia la sua velocità nel tempo e cosa succede quando raggiunge i bordi.
class Ambiente { public: Ambiente(); void addCorpo(Corpo* corpo) { m_corpo = corpo; } void loop(); private: SDL_Surface* m_schermo; SDL_Surface* m_sfondo; Corpo* m_corpo; int m_esci; };
Il metodo addCorpo() permette di inserire il corpo nell’ambiente, che attraverso il metodo loop() darà il via all’interazione.
Diamo uno sguardo alle implementazioni, iniziando dalla classe Corpo. Nel costruttore vengono semplicemente inizializzate le proprietà, fra le quali la superficie SDL che rappresenta il corpo. L’unico vero metodo è move(), responsabile di far muovere l’oggetto.
void Corpo::move() { m_posizione.x += m_velocita.x * m_direzione.x; m_posizione.y += m_velocita.y * m_direzione.y; }
Il metodo non fa altro che variare la posizione del corpo in base al proprio stato interno, sommando semplicemente al vettore che individua la posizione corrente il vettore con la velocità, tenendo conto della direzione di spostamento.
Per quanto riguarda Ambiente, il costruttore si occupa fra le altre cose delle inizializzazioni SDL. Il metodo dove risiede tutta la logica di interazione con il corpo è loop(), che in un ciclo while fa muovere il corpo modificandone la direzione quando raggiunge gli estremi dello schermo e occupandosi delle operazioni SDL necessarie a visualizzare la scena.
void Ambiente::loop() { SDL_Rect direzione; direzione.x = 1; direzione.y = 1; //loop principale while(!m_esci) { /* per prima cosa disegnamo lo sfondo sullo schermo, l’operazione che copia il nostro sprite sullo schermo si chiama “blit” */ SDL_BlitSurface(m_sfondo,NULL,m_schermo,NULL); // movimento del corpo SDL_Rect posizione = m_corpo->posizione(); if (posizione.x < 0) direzione.x = 1; //lato sinistro if (posizione.x + 25 > 320) direzione.x = -1; //lato destro if (posizione.y < 0) direzione.y = 1; //lato superiore if (posizione.y + 25 > 240) direzione.y = -1; //lato inferiore m_corpo->setDirezione(direzione); m_corpo->move(); //disegnamo il corpo alle coordinate calcolate SDL_BlitSurface(m_corpo->surface(), NULL, m_schermo, &(m_corpo->posizione())); //infine facciamo apparire il frame creato sullo schermo SDL_Flip(m_schermo); } SDL_Quit(); }
A questo punto il main diventa molto semplice:
int main(int argc, char *argv[]) { Ambiente ambiente; Corpo corpo; ambiente.addCorpo(&corpo); ambiente.loop(); exit(0); }
Si istanziano ambiente e corpo, si inserisce il corpo nell’ambiente e si dà il via al loop d’interazione.
Nell’archivio sono contenuti i sorgenti. Rispetto al pacchetto originale ho creato due makefile: uno di sviluppo che compila per la macchina GNU/Linux su cui programmo (Kubuntu Feisty) lanciando make; l’altro per creare l’eseguibile per la GP2X con make -f Makefile.gp2x (cambiare i path della toolchain come richiesto dal proprio ambiente).
Nelle prossime puntate vedremo come questa semplice ristrutturazione ci permetta di rendere la simulazione della pallina un po’ più elaborata.
