Labirinto

Da Tesine Linguaggi e Traduttori.

Jump to: navigation, search

Contents

INTRODUZIONE

Il progetto prevede la realizzazione di un videogioco in cui il personaggio, a partire da una data posizione all'interno di una mappa, deve raggiungere l'uscita evitando cadute da altezze troppo elevate e collisioni con le pareti presenti nell'ambiente.

Per generare dapprima l'ambiente di gioco ed in seguito i movimenti del personaggio, il programma è in grado di analizzare un file in input in cui sono definiti tutti i parametri necessari. Questo file è composto di tre parti:

  • Un header, in cui si possono trovare il tempo d'inizio della partita ed una serie di dati generali sul personaggio e sul livello di gioco.
  • Una sezione del livello, per definire le altezze della mappa di gioco (scalini, muri...).
  • Una sezione dei movimenti, che continene la lista dei movimenti da far eseguire al personaggio.

Il programma consiste in uno scanner Jflex ed un parser CUP che analizzano il file in input, ne controllano la correttezza sintattica e semantica ed eseguono i comandi in esso contenuti, fino ad ottenere l'esito della partita.


SCANNER

Esegue l'analisi del file in input, individuando le parole chiave ed i valori numerici da inviare al parser. In base alla sezione del file che sta analizzando, lo scanner si aspetta di trovare determinate funzioni e valori. Le diverse sezioni del file sono divise tra loro dalla coppia di simboli "%%".


PARSER

Il parser riceve i token dallo scanner e verifica che questi siano coerenti con la grammatica. Il codice Java associato alla grammatica esegue tutte le funzioni di gioco e produce in output l'esito della partita.


FUNZIONAMENTO DEL PROGRAMMA

Durante l'analisi dei simboli presenti nell'header, il programma parser memorizza i valori iniziali necessari per il gioco e prepara la matrice d’altezze. L'header ha la seguente struttura:

  • Nome del personaggio: stringa alfanumerica contenente al massimo 8 simboli.
  • Data e ora d’inizio della partita: nel formato "GG/MM/AAAA, HH:MM:SS".
  • Posizione iniziale x e y del personaggio: nel formato "REAL, REAL", dove REAL è un numero reale.
  • Nome del livello: stringa alfanumerica di lunghezza qualsiasi.
  • Dimensione del livello: nel formato "REAL, REAL, REAL, REAL", dove i quattro valori reali corrispondono rispettivamente alle coordinate xmin, ymin, xmax e ymax dell'area rettangolare di gioco. In caso d’inserimento dei valori in ordine diverso da quello specificato (per esempio se xmin > xmax), il programma parser li riordina automaticamente.
  • Granularità della mappa: nel formato "REAL", dove il numero reale rappresenta la dimensione reale di una cella della matrice.
  • [Opzionale] Commento: una stringa qualsiasi compresa tra le due sequenze di simboli "<!" e "!>".


In base ai comandi presenti nella successiva sezione del livello, il programma è in grado di modificare i valori nella matrice creando rettangoli che possono rappresentare dislivelli più o meno alti (compresi tra i valori reali 0 e 255). Questa sezione del file di input può contenere le seguenti funzioni:

  • Plane: per creare un rettangolo di altezza nella mappa di gioco.
  Plane(xmin, ymin, xmax, ymax, height);
  • Exit: per creare la zona d’uscita della mappa.
  Exit(xmin, ymin, xmax, ymax);

Come visto in precedenza per la definizione dell'area di gioco, anche nel caso di Plane ed Exit, se le coordinate x e y minime e massime non sono in ordine, il programma le riordina in modo corretto.


Infine, il programma esamina l'ultima sezione ed elabora i movimenti del personaggio, verificando che questo non oltrepassi i limiti della mappa di gioco, che non si scontri con dislivelli superiori ad una certa soglia e che non cada da altezze troppo elevate. Le funzioni per muovere il personaggio sono le seguenti:

  • MoveFW: fa camminare in avanti il personaggio e verifica eventuali collisioni/cadute.
  MoveFW ( MOVE_VALUE );
  • MoveBW: fa camminare all’indietro il personaggio e verifica eventuali collisioni/cadute.
  MoveBW ( MOVE_VALUE );
  • Jump: fa saltare in avanti il personaggio. In questo caso, le altezze della mappa non influenzano il movimento del personaggio, che giunge sempre a destinazione senza collisioni e cadute.
  Jump ( MOVE_VALUE );
  • Rotate: ruota il personaggio fino all’angolo assoluto indicato nel parametro della funzione.
  Rotate ( ANGLE_VALUE );
  • RotateLeft: ruota il personaggio a sinistra in base all’angolo indicato nel parametro della funzione.
  RotateLeft ( ANGLE_VALUE );
  • RotateRight: ruota il personaggio a destra in base all’angolo indicato nel parametro della funzione.
  RotateRight ( ANGLE_VALUE );
  • Speed: imposta la velocità (in m/s), del personaggio.
  Speed ( REAL );
  • Wait: mantiene immobile il personaggio per un certo numero di secondi.
  Wait ( REAL );


Il campo MOVE_VALUE può avere le seguenti forme:

  • "REAL M": indica un valore reale in metri.
  • "REAL S": indica un valore reale in secondi.

L'angolo delle funzioni di rotazione è rappresentato dal campo ANGLE_VALUE, che può avere le seguenti forme:

  • "REAL": numero reale in radianti.
  • "REAL PI": numero reale da moltiplicare con il valore di PI.
  • "FRACT PI": frazione da moltiplicare con il valore di PI. La frazione FRACT ha la forma "REAL / INT", dove il denominatore deve essere un numero intero maggiore di zero, mentre il numeratore può essere un numero reale qualsiasi.


Nella sezione dei movimenti possono essere presenti anche i costrutti IF e FOR (non annidati) nel seguente formato:

 if ( COND ) [
   ...
 ]

COND è la condizione del costrutto IF e può avere le seguenti forme:

  • "M COMP REAL": si confronta il numero reale con la distanza in metri, calcolata sul piano xy, tra la posizione attuale del personaggio ed il centro (0, 0).

oppure

  • "S COMP REAL": si confronta il numero reale con il tempo in secondi trascorso dall’inizio della partita.

COMP può essere "<" oppure ">". La sequenza di funzioni di movimento interne al costrutto IF deve sempre iniziare con Speed e non deve essere eseguita se la condizione risulta falsa.

 for ( NUM ) [
   ...
 ]

NUM deve essere un numero intero positivo. La sequenza di funzioni di movimento interne al costrutto FOR deve sempre iniziare con Speed.


In assenza di collisioni e cadute, se al termine della partita il personaggio è all'interno dell'area d'uscita del livello, il programma comunica all'utente l'avvenuta vittoria e produce a schermo gli esiti del gioco, riportando:

  • La posizione (x,y,z) finale del personaggio.
  • L'angolo e la velocità finali del personaggio.
  • La durata della partita, come somma dei secondi trascorsi dall'inizio del gioco e della data ed ora iniziali.

Sia in caso di vittoria che di sconfitta, il programma genera un'immagine bitmap che rappresenta i movimenti effettuati dal personaggio durante la partita.


VINCOLI SUI VALORI NUMERICI ED ERRORI

Il programma è in grado di rilevare determinate incoerenze nei valori numerici presenti nel file di input. Alcuni esempi di vincoli sui valori sono:

  • La posizione iniziale del personaggio non deve essere esterna all'area di gioco.
  • La dimensione della mappa di gioco, le altezze da inserire nella mappa ed il numero di celle utilizzabili nella matrice del livello non possono superare certi valori predefiniti (in questo caso è però possibile modificare questi valori nei sorgenti del programma).

Se non si rispettano queste condizioni, il programma genera un errore e s'interrompe.

Vi sono però alcune situazioni in cui l'esecuzione può continuare anche in presenza di errori:

  • Nel caso già visto in precedenza della sequenza di valori "xmin, ymin, xmax, ymax" non in ordine: il programma provvede a correggere l'errore e prosegue con la normale esecuzione.
  • In caso di funzioni di movimento prive di parametro (per esempio "MoveFW();"): il programma scrive a schermo l'errore, salta l'istruzione sbagliata e prosegue con l'esecuzione dell'istruzione successiva. Per far questo, il sottoalbero della grammatica che riguarda le funzioni di movimento prevede l'utilizzo del simbolo error.


ESEMPIO DI FILE DI INPUT CHE PRODUCE UNA VITTORIA

 NomePers
 10/01/2008, 23:59:59
 -18, -18.0
 NomeLivello
 -20.0, -20.0, 20.0, 20.0
 0.5
 <! Partita 1 !>
 
 %%
 
 Exit( 18, -2, 20, 2);
 Plane(-20, -10, -9.5 , 10, 1.5);
 Plane(-20, -6, -9.5, 6, 3);
 Plane(-20, -2, -9.5, 2 , 4.5);
 Plane (-6, 5.0, 6, 20, 5);
 Plane(15, 10.0, 17 , -10, 6.0);
 Plane(-6, 0.0, -2, -5, 2.0);
 Plane (2, 0.0, -2, -5, 4);
 Plane (6, 0.0, 2, -5, 6.0);
 
 %%
 
 Speed();
 Speed(1);
 
 Wait( 4 );
 RotateLeft(1/2 PI);
 for ( 4)[
     Speed( 0.1);
     MoveFW(9 M);
     RotateRight(1/2 PI);
     MoveFW(1.1 M);
     RotateLeft(0.5 PI);
     MoveBW(3 M);
     RotateLeft(1/2 PI);
     MoveFW(2.2 M);
     RotateRight(1/2 PI);
     MoveFW(3 M);
     RotateLeft(1/2 PI);
     MoveBW(1.1 M);
     RotateRight(0.5 PI);
 ]
 
 Wait( 1);
 Rotate(0 );
 Speed( 0.5);
 Jump(22 s );
 
 Wait( 1);
 RotateLeft(1/2 PI);
 if(s > 10)[
     Speed( 2 );
     RotateRight(1 PI);
 ]
 
 MoveFW(10 S);
 MoveFW();
 RotateRight(1/2 PI);
 Speed (4);
 MoveBW( 11 m);
 
 for(2 )[
     speed(1);
     RotateLeft(1/2 PI);
 ]
 
 if(m < 10)[
     Speed( 1 );
     Jump (4 m);
 ]
 
 RotateRight();
 Rotate(-1/2 PI);
 Wait(3);
 Speed( 3);
 moveFw(2 S);
 rotateLeft(1/2 PI);
 
 for(2) [
     Speed(1);
     Jump(5.5 m);
 ]
 
 RotateRight( 1/ 2 PI);
 Speed(8);
 MoveBW (1 s);

Utilizzando questo file in input, il programma produce la seguente immagine bitmap, che ritrae le caratteristiche del livello:

  • La zona in blu è l'uscita.
  • La scala di grigi è usata per le altezze: dal nero (che rappresenta l'altezza 0) al bianco (che è la maggiore altezza presente nel livello).
  • I movimenti effettuati dal personaggio sono MoveFW (verde), MoveBW (giallo) e Jump (rosso).
  • Le azioni di rotazione, di cambio della velocità e di attesa non possono ovviamente essere rappresentate nell'immagine.
  • La X verde rappresenta la posizione iniziale del personaggio.
Bitmap prodotta.
Enlarge
Bitmap prodotta.

ESEMPI DI GAME OVER

Qui di seguito sono riportati alcuni esempi di file di input e relative immagini risultanti, in cui si possono vedere delle sconfitte per tre diverse motivazioni:

  • Primo esempio con errore: il personaggio collide con un muro troppo alto ed il gioco termina con game over.
Bitmap prodotta.
Enlarge
Bitmap prodotta.


  • Secondo esempio con errore: il personaggio esce dalla zona della mappa ed il gioco termina con game over.
Bitmap prodotta.
Enlarge
Bitmap prodotta.


  • Terzo esempio con errore: il personaggio cade da un'altezza troppo elevata ed il gioco termina con game over.
Bitmap prodotta.
Enlarge
Bitmap prodotta.


FILE DEL PROGETTO

Il seguente archivio contiene i file del progetto ed alcuni esempi di file di input: http://www.skenz.it/traduttori/tesine/materiale/labirinto/TesinaLT-GiocoDelLabirinto.rar


NOTE PER LA COMPILAZIONE DEL PROGRAMMA

Per la compilazione in ambiente Windows, sono sufficienti i seguenti comandi:

 jflex scanner.jflex
 java java_cup.Main parser.cup
 javac Main.java Lexer.java parser.java sym.java
 java Main esempio.txt


LINK UTILI

Jflex

CUP

Sun Java 2

Personal tools