JOGLnoid

12
Università degli Studi di Trento Facoltà di Scienze MM.FF.NN Corso di Laurea Specialistica in Informatica A.A. 2007-2008  Relazione del progetto del corso di “Principi di Computer Grafica”, Prof. Raffaele De Amicis, Prof. Giuseppe Conti Massimo Santini  matr.130531 1 Introduzione 1.1 JOGLnoid L'applicazione descritta in questa relazione, denominata simpaticamente “JOGLnoid”, corrisponde ad un clone del celebre videogioco arcade “Arkanoid”. JOGLnoid, infatti, è un semplice gioco in cui l'obiettivo principale dell'utente è quello di abbattere un determinato numero di mattoncini, posti all'interno di una scena bidimensionale, tramite l'uso di una sfera e di una piccola barra di gioco. La barra serve infatti a far rimbalzare la sfera di gioco contro i mattoncini, evitando che quest'ultima cada nella porzione di schermo sottostante alla barra stessa, causando così la perdita della partita. Il gioco è stato sviluppato tramite l'ausilio della libreria grafica OpenGL, e premette all'utente di giocare partite composte da un massimo di 10 livelli, interagendo con l'applicazione tramite l'uso della tastiera del computer. 2 Componenti principali della finestra principale dell'applicazione 2.1 La schermata di gioco La finestra di gioco principale, di dimensione 1200x900 pixels,  si compone sostazialmente di due parti principali: sul pannello di sinistra troviamo la scena di gioco renderizzata tramite OpenGL, mentre sul pannello di destra è disponibile un'interfaccia utente necessaria per gestire e controllare il gioco. Figura 1: La schermata principale di JOGLnoid

description

The project described in this report, called affectionately "JOGLnoid", corresponds a clone of the famous arcade game "Arkanoid". The game was developed through the assistance of the OpenGL graphics library.

Transcript of JOGLnoid

Page 1: JOGLnoid

Università degli Studi di TrentoFacoltà di Scienze MM.FF.NN

Corso di Laurea Specialistica in InformaticaA.A. 2007­2008

 Relazione del progetto del corso di “Principi di Computer Grafica”, Prof. Raffaele De Amicis, Prof. Giuseppe Conti

Massimo Santini  matr.130531

1 Introduzione

1.1 JOGLnoidL'applicazione descritta in questa relazione, denominata simpaticamente “JOGLnoid”, corrisponde ad un clone del celebre videogioco arcade “Arkanoid”. JOGLnoid, infatti, è un semplice gioco in cui l'obiettivo principale dell'utente è quello di abbattere un determinato numero di mattoncini, posti all'interno di una scena bidimensionale, tramite l'uso di una sfera e di una piccola barra di gioco. La barra serve infatti a far rimbalzare la sfera di gioco contro i mattoncini, evitando che quest'ultima cada nella porzione di schermo sottostante alla barra stessa, causando così la perdita della partita.Il gioco è stato sviluppato tramite l'ausilio della libreria grafica OpenGL, e premette all'utente di giocare partite composte da un massimo di 10 livelli, interagendo con l'applicazione tramite l'uso della tastiera del computer.

2 Componenti principali della finestra principale dell'applicazione

2.1 La schermata di gioco La finestra di gioco principale, di dimensione 1200x900 pixels,  si compone sostazialmente di due parti principali: sul pannello di sinistra troviamo la scena di gioco renderizzata tramite OpenGL, mentre sul pannello di destra è disponibile un'interfaccia utente necessaria per gestire e controllare il gioco.

Figura 1: La schermata principale di JOGLnoid

Page 2: JOGLnoid

2.1.1 L'interfaccia di controllo del giocoL'interfaccia utente sulla sinistra della schermata di gioco,  permette sostazialmente di effettuare tutte   quelle   operazioni   necessarie   all'avvio   di   una   parti.   Infatti,   tramite   una   serie   di   pulsanti etichettati e di menu a tendina, è possibile avviare una nuova partita, selezionandone il livello dal quale si vuole iniziare, oppure chiuderne a sua volta una già iniziata od, infine, chiudere l'intera applicazione.

Sono inoltre presenti degli indicatori, necessari per visualizzare il punteggio corrente della partita, il numero di vite rimaste ed ovviamente il livello corrente gioco durante la partita.

2.1.2 La scena di giocoLa scena di gioco è visualizzata sulla sinistra della finestra principale, all'interno di un pannello di dimensioni   600x400 pixels ed è renderizzata tramite l'utilizzo della liberia  Jogl  (binding Java di OpenGL). Nella porzione superiore della scena vengono rappresentati i  mattoncini da abbattere, colorati in maniera casuale, mentre nella parte inferiore sono presenti la sfera e la barra di gioco, entrambe colorate con tonalità di grigio. Inoltre il colore di queste componenti presenta  sfumature (shading) del colore sui vertici.

3 Giocare a JOGLnoid

3.1 Gestione di una partita a JOGLnoidUna   partita   a   JOGLnoid   consiste   consiste   di   10   livelli   di   gioco   ognuno   dei   quali   presenta caratteristiche differenti. Tuttavia, l'utente non è obbligato ad iniziare necessariamente dall livello 1. Vi è infatti la possibilità di scegliere il livello iniziale, selezionando la voce corretta nel menù a tendina relativo ai livelli di gioco. Se tale scelta non viene effettuata si avvia di “default” una partita dal   livello   1.   Lo   scopo   del   gioco,   come   detto   precedentemente,   è   quello   di   abbattere   tutti   i mattoncini presenti nella scena, in modo da superare il livello e passare al successivo.Ogni   livello   presenta   un   numero   di   mattoncini   differenti.   In   particolare,   il   numero   totale   dei mattoncini corrisponde a 160, e ad ogni livello ne vengono disegnati esclusivamente un numero pari alla percentuale asseganta al livello in questione. Ciò significa che, ad esempio, se si vuole superare 

Figura 2: L'interfaccia di controllo del gioco

Page 3: JOGLnoid

il primo livello sarà necessario abbattere un numero di mattoncini pari al 10% del totale (ovvero 16); il superamento del secondo invece necessiterà l'abbattimento del 20% del totale e cosi' via, fino al livello 10, il quale conterrà il 100% dei mattoncini, ovvero in numero pari al totale possibile (160).L'abbattimento di un mattoncino comporta un bonus sul punteggio totale di 10 punti. Di seguito è mostrato il metodo init_grid(int n_lines, int level)appartenente alla classe GLRenderer, ovvero il metodo che si occupa di riempire la scena di gioco con il numero adeguato di mattoncini.

/*** * Inizializza la griglia da abbattere * @param n_lines numero delle linee di mattoncini che compongono la scena  * da abbattere */private void init_grid(int n_lines, int level) {

box Box;int num_mattoncini;int num_mattoncini_left;double index;

//il numero totale dei mattoncini da abbattere per livellonum_mattoncini = ((20*8)*(level*10)/100);

// numero box per lineaint numBxL = (int)(4.0f / 0.50f);

STACK_BOX.clear();

for (int i=1; i<=n_lines; i++) {for (int j=1; j<=numBxL;j++) {

Box = new box((0.50f*j)­2.25f,((float)­i*(0.10f))+2.05f);STACK_BOX.addElement(Box);num_boxes++;

}}

//calcolo il num di mattoncini da levarenum_mattoncini_left = 160 ­ num_mattoncini;

for (int k=0; k < num_mattoncini_left; k++) {index =(double) Math.random() * (STACK_BOX.size()­1);index = Math.round(index);STACK_BOX.removeElementAt((int)index);num_boxes = num_boxes ­ 1;

}

}

È inoltre possibile che un mattoncino abbattuto contenga una specie di sorpresa, ovvero ciò che nel gioco  originale  è   chiamato  “power­up”.  Questi  power­up,  non sono altro   che  degli  oggetti   che precipitano verso il settore inferiore dell'area di gioco e che vengono eliminati non appaena escono da quest'ultima. Se uno di questi oggetto viene intercettato tramite la sbarra di gioco, allora il gioco subisce   alcune   variazioni   che   possono   rivelarsi   in   alcuni   casi   favorevoli   oppure   sfavorevoli all'utente. I power­up possono essere di cinque tipi diversi, a seconda del colore assegnatogli:

● Rosso: Allarga le dimensioni della barra di gioco, facilitando l'intercettazione della sfera;● Verde: Restringe le dimensioni della barra di gioco, rendendo l'intercettazione della sfera 

più difficile. Rallenta la velocità della sfera di gioco;

Page 4: JOGLnoid

● Blu: Aumenta la velocità della sfera;● Nero: Riempie nuovamente la scena di gioco con un numero di mattoncini pari a quelli  

assegnati al livello corrente;● Viola: Trasforma la sfera di gioco in una “super­sfera”, in grado di abbattere i mattoncini 

senza provocare collisioni;

Infine, l'abbattimento di tutti i mattoncini, consente il passaggio al livello successivo.Ad ogni partita vengono assegnate un numero di vite pari a tre. Ovviamente, quando la sfera di gioco finisce nella zona sottostante la barra di gioco, la partita viene fermata e ciò  comporta la perdita di una vita. L'esaurimento di tutte le vite disponibili comporta la fine della partita corrente.

3.2 L'interazione tramite la tastieraLo   strumento   principale   di   interazione   con   JOGLnoid   è   ovviamente   la   tastiera   del   computer. Sostanzialmente i tasti necessari al gioco possono essere divisi in due categorie: quelli relativi al controllo della barra di gioco e quelli relativi all'orientamento della telecamera virtuale.

3.2.1 Tasti per il controllo del giocoI tasti utilizzati per muovere la barra di gioco sono esclusivamente due efanno parte del tastierino direzionale:

● RIGHT_KEY ( ) : Sposta la barra verso destra;● LEFT_KEY   ( ) : Sposta la barra verso sinsitra;

A questi due tasti va inoltre aggiunta la barra spaziatrice, la quale permette di avviare la partita, ogni qualvolta questa viene fermata.

● SPACEBAR  : Lancia la pallina;

3.2.2 Tasti per il controllo della telecamera virtualeI tasti in questione permettono di muovere la telecamera virtuale in maniera da poter vedere il gioco da punti  di  vista  differenti.  Oltre  a  ciò,  è  possibile   ruotare  la  scena di  gioco in  senso orario  e antioratio tramite l'utilizzo del mouse, ovvero tenendo premuto il tasto sinistro e trascinando verso destra o verso sinistra.Tra i tasti di controllo della telecamera virtuale vi sono:

● D_KEY  : Ruota la telecamera verso destra;● A_KEY  : Ruota la telecamera verso sinistra;● S_KEY  : Sposta la telecamera indietro;● W_KEY : Sposta la telecamera in avanti;● Q_KEY  : Sposta la telecamera in alto;● E_KEY  : Sposta la telecamera in basso;● PAG_UP  : Ruota la telecamera verso l'alto;● PAG_DOWN : Ruota la telecamera verso il basso.

4 Le componenti principali di JOGLnoid

La struttua di JOGLnoid è sostanzialmente organizzata in packages (pacchetti). Ad ognuno di questi è assegnato un compito ben preciso ed ogni package contiene le classi necessarie per il suo scopo.I package di maggiore interesse sono senz'altro gt.events, physics, math, game.components, texture, 

Page 5: JOGLnoid

texture.loader, custom.events e render.Di seguito verrà proposta una descrizione degli aspetti principali di tali pacchetti.

4.1 Il package gt.eventsIl   package   gt.events   contiene   le   classi   statiche  GameStatus,  KeyNavigator  e MovementStatus. Le ultime due classi citate si occupano esclusivamente di gestire la mappatura dei controlli della tastiera.   Il   loro  scopo è   quindi  unicamente  quello  di   interfacciare   la   tastiera  del   computer   con l'applicazione JOGLnoid.La classe   GameStatus riveste, invece, un ruolo maggiormente interessante, in quanto le sue variabli   statiche   si  occupano  di  memorizzare   lo   stato   corrente  del  gioco.  Tutto   ciò  è   utile  dal momento che, gestendo i vari eventi che accadono durante la partita, questa classe permette sempre di sapere qual'è lo stato corrente della partita che si sta giocando. Tra queste caratteristiche figurano, ad esempio, il numero di vite rimaste, il livello corrente, il punteggio corrente ecc... Di seguito viene mostrata l'implementazione di tale classe.

package gt.events;

/*** * Classe GameStatus, costituisce un listener che permette ad ApplicationStarter * di conoscere lo stato del gioco in GLRenderer * @author Massimo Santini 130531 * */public class GameStatus {

public static int num_lives = 3;public static int current_level = 1;public static int game_score = 0;public static boolean new_game = false;public static boolean reset = false;public static boolean game_is_working = true;public static boolean setLevelBoxes = false;public static boolean collision_wall_sound = false;public static boolean collision_box_sound = false;public static boolean collision_bar_sound = false;

}

4.2 I package texture e texture.loderQuesti due package contengono classi dedite esclusivamente alla gestione ed al caricamento delle texture del gioco. Per un maggiore approfondimento si rimanda al codice sorgente dell'applicazione.

4.3 Il package custom.eventsJOGLnoid implementa un meccanismo di “design pattern” che permette alla classe  GLRenderer di  generare un evento personalizzato ogni qual'volta accade qualcosa nella scena di gioco.  Tale evento   è   implementato   dalla   classe  RenderEvent,   appartenente   a   questo   package,  e   viene intercettato   dalla   classe   che   gestisce   l'interfaccia   utente.   Tutto   ciò   permette   all'interfaccia   di controllo di essere sempre aggiornata sullo stato corrente del gioco, in maniera da poter poi settare i valori corretti nei suoi indicatori, come ad esempio il punteggio corrente oppure il numero delle vite rimaste. L'evento personalizzato   RenderEvent contiene alcune proprietà   quali, in particolare, punteggio  e  lives,   che   vengono   istanziate   al   momento   della   creazione   dell'oggetto   evento.   In particolare oggetti di questo tipo vengono creati ogni qualvolta accade nella scena di gioco qualcosa tipo l'abbattimento di un mattoncino, una collisione, un'intercettazione di un power­up, ecc...

Page 6: JOGLnoid

Di seguito viene presentata l'implementazione della classe  RenderEvent.

package custom.events;import java.util.EventObject;public class RenderEvent extends EventObject {

int punteggio;int lives;boolean wall_sound = false;boolean box_sound = false;boolean bar_sound = false;

public RenderEvent(Object source, int points, int lives_left, boolean w_sound, boolean b_sound, boolean br_sound) {

super(source);// TODO Auto­generated constructor stubpunteggio = points;lives = lives_left;wall_sound = w_sound;box_sound = b_sound;bar_sound = br_sound; 

}

public int getPoints() {return punteggio;

}

public int getLivesLeft() {return lives;

}

public boolean getWall_sound() {return wall_sound;

}public boolean getBox_sound() {

return box_sound;}

public boolean getBar_sound() {return bar_sound;

}}

4.4 Il package game.componentsIl   package   game.components   include   tutte   quelle   classi   che   permettono   di   creare   le   varie componenti  grafiche  del  gioco,  quali   la   sfera,   la  barra  di  gioco,   i  power­up  e   i  mattoncini  da abbattere. Ognuna delle precedenti componenti è implementata rispettivamente dalle classi  Ngon, bar, box e surprise.In   particolare   ognuno   di   queste   classi   implementa   il   metodo  draw(GLAutoDrawable gLDrawable),il   quale  permette  di  disegnare   l'oggetto   in  questione  all'interno  della   scena  di gioco. Di particolare interesse è la classe che implementa la sfera di gioco, descritta nel paragrafo 4.4.1. Infine è necessario sottolineare che ognuna delle componenti descritte fino ad ora presenta alcune  proprietà   particolari,   chiamate  bound_box[]:   queste   proprietà   permettono  di   definire quella regione relativa all'oggetto da disegnare, detta bounding box, la quale risulta necessaria per la gestione delle collisioni tra gli oggetti stessi. 

4.4.1 La classe NgonLa   classe  Ngon  implementa   la   sfera   di   gioco.   Tale   sfera   viene   implementata   disegnando   una particolare primitiva geometrica, ovvero un poligono di dimensione n, che viene poi fatto ruotare di 

Page 7: JOGLnoid

360°     lungo   l'asse  y.    In   questa  maniera   è   possibile   ottenere   un'approssimazione  di  una   sfera abbastanza precisa. Tale precisione dipende ovviamente dal numero di lati che possiede il poligono ed in questa applicazione si è scelto di utilizzare un decagono (poligono di 10 dimensioni). Nelle prossime righe è mostrata la procedura si occupa della creazione della sfera di gioco.

for (int j=0; j<=360.0f; j++) {gl.glRotatef(j, 0.0f, 1.0f, 0.0f);gl.glBegin(GL.GL_POLYGON);for (int i=0; i<=size; i++) {

if (red) {gl.glColor3f(1.0f, 0.0f, 0.0f);

}else {

gl.glColor3f(0.6f,0.6f,0.6f);}

gl.glVertex2d(radius*(Math.cos(angle_inc*i)),radius*(Math.sin(angle_inc*i)));}gl.glEnd();j++;

}  

4.5 Il package physicsIl  package  physics  contiene un'unica classe,  nominata  collision.  Tale classe si  occupa della gestione delle collisioni fra gli oggetti della scena. Una collisione viene rilevata sostanzialmente quando la bounding box   della sfera di gioco “entra” letteralmente nella bounding box dell'oggetto con cui sta per collidere.In particolare, la classe collision implementa otto diversi metodi, ognuno dei quali è preposto ad individuare un particolare tipo di collisione. Questi metodi sono:

● isCollidingWithSXWall(Ngon ball)Questo metodo si occupa di rilevare eventuali collisioni della sfera con la delimitazione sinistra dell'area di gioco;

● isCollidingWithDXWall(Ngon ball)Questo metodo si occupa di rilevare eventuali collisioni della sfera con la delimitazione destra dell'area di gioco;

● isCollidingWithUpperWall(Ngon ball)Questo metodo si occupa di rilevare eventuali collisioni della sfera con la delimitazione superiore dell'area di gioco;

● isCollidingWithGameBar(Ngon ball, bar gameBar)Questo metodo si occupa di rilevare le collisioni della sfera con la barra di gioco;

● isCollidingWithBoxRight(Ngon ball, box mattoncino)Questo metodo si occupa di rilevare le collisioni della sfera con un mattoncino, nel caso in cui la sfera lo colpisca sul suo lato destro;

● isCollidingWithBoxLeft(Ngon ball, box mattoncino)Questo metodo si occupa di rilevare le collisioni della sfera con un mattoncino, nel caso in cui la sfera lo colpisca sul suo lato sinistro;

● isCollidingWithBoxUp(Ngon ball, box mattoncino)

Page 8: JOGLnoid

Questo metodo si occupa di rilevare le collisioni della sfera con un mattoncino, nel caso in cui la sfera lo colpisca sul suo lato superiore;

● isCollidingWithBoxDown(Ngon ball, box mattoncino)Questo metodo si occupa di rilevare le collisioni della sfera con un mattoncino, nel caso in cui la sfera lo colpisca sul suo lato inferiore;

Ognuno  dei  metodi   visti   sopra   ritorna  un  valore  di   tipo  booleano   il   quale  determina,   in   caso affermativo, l'avvenuta collisione con l'oggetto in questione. Per quanto riguarda le collisioni della sfera con le delimitazioni dell'area di gioco, la condizione che determina l'avvenuta collisione è determinata da un controllo sulle coordinate della   bounding box della   sfera;   di   fatto,   non   appena   tali   coordinate   oltrepassano   i   valori   delle   coordinate   delle delimitazioni, viene rilevato un urto con una di quest'ultime e si procede ad inserire sullo stack la matrice di riflessione relativa al tipo di urto, in maniera da modificare adeguatamente la traiettoria della sfera durante il gioco. Le seguenti righe di codice, ad esempio, mostrano come viene gestita un'ipotetica collisione con la delimitazione superiore della scena di gioco.

/*** * Controlla se avviene una collisione con la delimitazione superiore * dell'area di gioco * @param ball pallina del gioco * @return true or false valore di ritorno (vero o falso) */public static boolean isCollidingWithUpperWall(Ngon ball) {

// La sfera di gioco collide con la delimitazione superiore dell'area di gioco

if (ball.bound_box[3] >= 2.0f) {//System.out.println("collisione soffitto");return(true);}

else {return(false);

}}

Le   collisioni   con   i   mattoncini   invece,   vengono   trattate   in   modo   simile,   anche   se   sono   stati introddotti alcuni controlli necessari, soprattutto per identificare con quale lato del mattoncino si sta collidendo. Sostanzialmente l'idea fondamentale consiste nel verificare quale dei lati della bounding box della sfera sta “letteralmente” entrando all'interno dell'area del mattoncino in questione. Una volta determinato quale lato della bounding box della sfera sta per collidere, si procede ad inserire sullo   stack   la   matrice   di   riflessione   associata   a   quel   particolare   tipo   di   urto,   modificando opportunamente la traiettoria della sfera.Inoltre,  viene introdotto un'ulteriore controllo che assicuri  che la sfera stia per collidere con un particolare mattoncino e non con altri, posti nella scena di gioco, le cui coordinate delle bounding boxes potrebbero potenzialmente rendere valida la condizione di controllo sulla collisione. Questo impedisce che, ad esempio, nel caso di una collisione sul lato sinistro di un mattoncino, vengano eliminati tutti quei mattoncini che si trovano più a sinistra del mattoncino in questione. Di seguito è riportato un'esempio di gestione di un urto con il lato sinistro di un mattoncino del gioco.

/*** * Controlla se avviene una collisione con il lato sinistro di un  * mattoncino * @param ball pallina del gioco * @param mattoncino mattoncino su cui viene valutata la collisione * @return true or false valore di ritorno (vero o falso) */

Page 9: JOGLnoid

public static boolean isCollidingWithBoxLeft(Ngon ball, box mattoncino) {

if ((ball.bound_box[1]>=mattoncino.bound_box[0])&(ball.bound_box[1]<mattoncino.bound_box[1])&

((ball.getY()<mattoncino.bound_box[3])&(ball.getY()>mattoncino.bound_box[2])))

{System.out.println("isCollidingWithBoxLeft");return(true);

}else  {

return(false);}

}

4.6 Il package mathIl  package  math  contiene due  classi  che permettono l'utilizzo,  dal punto di vista matematico di matrici numeriche. In particolare queste ultime servono per la gestione di tutte quelle matrici che permettono a JOGLnoid di muovere tutte le sue componenti grafiche. Fanno parte di questo package le classi matrix e matrixOperations. La prima classe implementa la struttura di una matrice numerica di dimensione 4x4, con in aggiunta alcuni metodi di servizio che, ad esempio, permettono di modificare valori in determinate posizioni della matrice oppure di trasformare quest'ultima in una matrice identità.La classe  matrixOperations, invece, si occupa esclusivamente, di calcolare il prodotto fra due matrici.

4.7 Il package renderQuest'ultimo package costituisce il motore grafico vero e proprio di  JOGLnoid.  Infatti contiene la classe GLRenderer, il cui unico scopo è quello di disegnare gli oggetti nella scena di gioco.La scena di gioco è disegnata all'interno di un frustum ottenuto da un volume di vista creato con un'angolo   di   apertura   di   45°,     dove   il  front   clipping   plane  e   il  far   clipping   plane  posti rispettivamente a distanza di 1 unità e 800 unità dall'origine del volume di vista.Questa   classe  presenta  molteplici   aspetti   interessanti;   tra  questi  è   tuttavia  utile   soffermarsi   sul metodo display(GLAutoDrawable gLDrawable), nel quale vi risiedono tutte le istruzioni per il disegno degli oggetti nella scena. Per quanto riguarda il movimento della sfera, questo avviene scaricando utilizzando uno stack sul quale vengono caricate in maniera opportuna le matrici di traslazione o di riflessione. Il movimento è quindi dato da una serie di trasformazioni affini che permettono di disegnare la sfera nelle sue coordinate corrette. Infatti, ogni qual volta è necessario traslare la sfera, si procede all'inserimento sullo stack di una matrice di traslazione, con i relativi valori settati opportunamente. Analogamente un   urto   comporta   la   riflessione  della   traiettoria   della   sfera,   e   ciò   viene   effettuato   inserendovi un'apposita  matrice di  riflessione.  Ovviamente questi   inserimenti  sono condizionati  dai  risultati delle operazioni di rilevamento delle collisioni, le quali determinano la traiettoria che la sfera di gioco deve seguire.Le righe di codice che seguono mostrano ad esempio, la fase di controllo di una possibile collisione della sfera con la delimitazione superiore di un mattoncino. In caso affermativo, la corrsipondente matrice di riflessione viene caricata sullo stack.

Page 10: JOGLnoid

// Check delle collisioni con i mattoncinifor (int j=0;j<STACK_BOX.size();j++) {

tmp_box = STACK_BOX.get(j);xsorp = tmp_box.getX();ysorp = tmp_box.getY();

if (collision.isCollidingWithBoxDown(ball, tmp_box)) {if (tmp_box.surprise == 1.0f) {

creasorpresa(xsorp, ysorp);}YReflectionMatrix.setIdentity();YReflectionMatrix.setIndex(1, 1, ­1.0f);if (collision_srp) {

STACK_MATRIX.addElement(YReflectionMatrix);}GameStatus.collision_box_sound = true;GameStatus.game_score = GameStatus.game_score + 10;fireRenderEvent();STACK_BOX.remove(j);

}

Al momento del disegno vero e proprio, tale stack viene scaricato e moltiplicando la matrice di trasformazione corrente con quella in cima allo stack, siamo in grado di ottenere la matrice che determinerà le coordinate in cui la sfera dovrà essere disegnata. Di seguito è mostrata la procedura che si occupa di tale attività.

//svuoto lo stack e disegno la pallinafor (int k=0; k<STACK_MATRIX.size(); k++) {

tmp = STACK_MATRIX.get(k);currentMatrix = 

matrixOperations.multiplyMatrix(currentMatrix,tmp);ball.setX(currentMatrix.getValue(0, 2));ball.setY(currentMatrix.getValue(1, 2));ball.draw(gLDrawable);tmp.setIdentity();

}

if (game_started) {STACK_MATRIX.clear();

}

Inoltre una serie di  flag  booleane permette di controllare il flusso attraverso il codice durante il disegno dei frames, a seconda che ci si trovi in una situazione in cui il gioco è fermo o viceversa.Un'altro aspetto interessante di questa classe è rappresentato dalle righe che seguono:

/*** * Permette il firing di eventi dalla classe GLRenderer * */protected synchronized void fireRenderEvent() {

RenderEvent evt = new RenderEvent(this, GameStatus.game_score, GameStatus.num_lives, GameStatus.collision_wall_sound, GameStatus.collision_box_sound, GameStatus.collision_bar_sound);

Object[] listeners = RenderEventListeners.getListenerList();// loop through each listener and pass on the event if neededint numListeners = listeners.length;for (int i = 0; i<numListeners; i+=2) {

if (listeners[i] == RenderEventListener.class) {

Page 11: JOGLnoid

// pass the event to the listeners event dispatch method((RenderEventListener)listeners[i

+1]).RenderEventReceived(evt);}            

}}

Le righe precedenti   implementano il  metodo  fireRenderEvent(),  ovvero quella  possibilità descritta   precedentemente,   che   permette   alla   classe  GLRenderer  di   creare   un   evento personalizzato ogni qualvolta qualcosa accade nella scena di gioco.Un'altro   aspetto   interessante   è   rappresentato   dalla   gestione   dei   cosiddetti  power­up   ,descritti precedentemente. La loro intercettazione è ovviamente un'altro tipo di collisione che deve essere gestito. Di seguito è mostrata la parte di codice dedita a tale operazione.

// controllo eventuali collisioni con la barra o la necessita' di eliminare sorprese

if (((tmp_sorpresa.bound_box[2] <= ­1.80f)&(tmp_sorpresa.bound_box[3] >= ­1.90f)) 

&& ((tmp_sorpresa.getX() <= gameBar.bound_box[1])&(tmp_sorpresa.getX() >= 

gameBar.bound_box[0]))) {

System.out.println(tmp_sorpresa.surprise_type);switch ((int)tmp_sorpresa.surprise_type) {case 0:

//ricreo tutti i mattoncini da abbattereinit_grid(num_lines, GameStatus.current_level);collision_srp = true;gameBar.setDefaultWidth();ball_speed_Y =  0.07f;ball.setColorGray();GameStatus.game_score = GameStatus.game_score + 

20;break;

case 1://allargo la barracollision_srp = true;gameBar.setWidth(0.40f);ball_speed_Y = 0.07f;ball.setColorGray();GameStatus.game_score = GameStatus.game_score + 1;break;

case 2://aumento la velocita'collision_srp = true;gameBar.setDefaultWidth();ball_speed_Y =  0.09f;ball.setColorGray();GameStatus.game_score = GameStatus.game_score + 3;break;

case 3://restringo la barracollision_srp = true;gameBar.setWidth(0.15f);ball_speed_Y = 0.05f;ball.setColorGray();GameStatus.game_score = GameStatus.game_score + 10;break;

case 4:collision_srp = false;gameBar.setDefaultWidth();ball_speed_Y = 0.07f;ball.setColorRed();

Page 12: JOGLnoid

GameStatus.game_score = GameStatus.game_score + 5;break;

}fireRenderEvent();STACK_SURPRISE.removeElementAt(d);

}tmp_sorpresa.draw(gLDrawable);

}

La condizione descritta nel primo if  determina se la sorpresa in questione debba essere disegnata oppure no, mentre il membro alla destra dell'operatore condizionale && rileva un'eventuale collisione del power­up con la barra di gioco . In caso affermativo di procede alla valutazione del tipo di sorpresa che è stato intercettato, modificando di conseguenza i relativi parametri con i valori assegnati al  power­up.

5 Note tecniche sullo sviluppo dell'applicazione JOGLnoid

JOGLnoid  è stato sviluppando in  JAVA, utilizzando l'ambiente di sviluppo Eclipse, ed il binding OpenGL per JAVA, denominato Jogl. L'intera applicazione inoltre è stata creata su piattaforma i386, in ambiente GNU/Linux.