cerca
Giochino del Sottomarino
modifica cronologia stampa login logout

Wiki

Tools

Categorie

Help

edit SideBar

Utenti.GiochinoSottomarino-ClassiPrincipali History

Hide minor edits - Show changes to output

Added line 9:
Added lines 12-13:

La classe '''Graphics''' è quella che si trova in '''org.newdawn.slick.Graphics'''. Se NetBeans ritiene altrimenti, non dategli retta:)
Changed lines 122-123 from:
private Nave nave;
to:
private Nave player;
Changed line 126 from:
nave = new Nave(100, 100);
to:
player = new Nave(100, 100);
Added lines 1-170:
(:title Giochino del Sottomarino:)

<<|[[Giochino Sottomarino]]|>>

%titolo%''':: Giochino del Sottomarino - Progetto ::'''

!!Update e Render
In linea generale e teorica, tutto ciò che "vive" all'interno di un videogioco può vedere la propria attività divisa in due parti distinte: la progressione della logica e la rappresentazione a schermo. Lo stesso GameState di Slick presenta questa dualità tramite i metodi che sono segnati così:
public void update(GameContainer container, StateBasedGame game, int delta);
public void render(GameContainer container, StateBasedGame game, Graphics g);

!!!Update
In '''Update''' si aggiorna la logica dell'entità di gioco. Si analizza l'input, le eventuali condizioni ambientali, si eseguono i calcoli, si muta di stato, si stabilisce in base a tutto ciò e ad altro ancora la propria posizione sullo schermo.

Per ottenere questo obiettivo è necessario avere la nozione del tempo: quanto tempo è passato dall'ultima volta che ho dovuto prendere decisioni, in altre parole, dalla '''update''' scorsa?

La firma del metodo ci dice che c'è il parametro '''delta''', il quale rappresenta il numero di millisecondi trascorso dall'ultimo update.

Nella costruzione dell'applicazione avevamo scritto:

app.setVSync(true);

Questo significa quindi che, se tutto va liscio, tra un '''update''' e l'altro dovrebbe passare praticamente lo stesso numero di millisecondi. Nel caso di una frequenza di aggiornamento di 60Hz, allora avremo 1000 / 60 = 16 millisecondi circa. '''delta''' varrà 16.

Gli altri parametri della chiamata servono per recuperare informazioni sulla finestra di gioco etc. etc.

!!!Render
Durante la '''render''' si disegna effettivamente a schermo. Si prenderanno le immagini etc. e in base alle informazioni trovate nella '''update''' (ma anche in base ad altri criteri) si deciderà che cosa disegnare, a schermo, e dove.

Facciamo il caso di un sottomarino nemico: nella '''update''' aggiornerà la propria posizione in funzione della sua velocità e del tempo trascorso. Nella '''render''' disegnerà la propria figura sullo schermo a seconda della posizione calcolata nella '''update'''

!!Entity
Dal momento che questi due metodi sono così importanti, ho deciso che ci occorre un'interfaccia che li racchiuda, e che tutte le entità del gioco debbano implementare questa interfaccia. Siccome parlo di entità, con molta fantasia l'interfaccia si chiamerà '''Entity''':

public interface Entity {
public void update(GameContainer container, StateBasedGame game, int delta);
public void render(GameContainer container, StateBasedGame game, Graphics g);
}

!!La Nave
La '''Nave''' deve essere un'entità, e quindi implementerà l'interfaccia '''Entity'''.

Che cosa deve sapere una nave? Deve sapere la propria posizione, e deve sapere in che direzione sta andando, e anche a che velocità. La posizione della '''Nave''' verrà governata dal giocatore, in un modo che vedremo poi. Quindi, in astratto, alla nave diremo: "vai a destra", oppure: "vai a sinistra", o ancora: "fermati".

Alla luce di questa ''dettagliata'' descrizione, possiamo cominciare a buttare giù la nostra classe '''Nave'''

public class Nave implements Entity {

private float x;
private float y;
private float speed;

Quando costruisco la '''Nave''' le dico dove deve posizionarsi nel mondo, in coordinate schermo.

public Nave(float x, float y) {
this.x = x;
this.y = y;

this.speed = 0f;
}

Poi ci metto i metodi che servono per governare la '''Nave''' dall'esterno:

public void goLeft() {
this.speed = -100f / 1000f;
}

public void goRight() {
this.speed = 100f / 1000f
}

public void stop() {
this.speed = 0f;
}

Quando dico alla '''Nave''' di fermarsi, chiamo '''stop''' e ok, la velocità viene impostata a 0. Se invece le dico di andare a sinistra o a destra, la velocità è settata in modo diverso.

Per esempio, per andare a destra la velocità è data da 100f / 1000f. Velocità = spazio / tempo, quindi vuol dire che la nave percorrerà 100 pixel nello spazio di 1000 millisecondi (1 secondo). Prima infatti dicevo che il metodo '''update''' passa il delta in millisecondi.

Passiamo allora al metodo '''update''':

public void update(GameContainer container, StateBasedGame game, int delta) {

x += speed * delta;

}

Facile, no? Moltiplico per il tempo ed ottengo lo spostamento dall'ultima update.

!!!E come la disegno?
Già, come la disegno? In attesa che trovi delle immagini adatte, ho deciso di sfruttare le forme geometriche che Slick ci offre.

Occorre dichiarare una nuova variabile:

private Rectangle box;

che chiamo '''box''' perché poi sarà usata come una scatola. CTRL-SHIFT-I dovrebbe far importare automaticamente questo file, dove è definito il '''Rectangle''':

import org.newdawn.slick.geom.Rectangle;

Nel costruttore aggiungo sta riga:

box = new Rectangle(x, y, 200, 32);

in cui dico che la box partirà da '''x''' e '''y''', passati come parametro al costruttore; sarà larga 200 e alta 32. Sto praticamente duplicando le variabili '''x''' e '''y''', ma forse poi ci verranno buone così.

Nella '''update''' aggiungo questa riga:

box.setLocation(x, y);

e così facendo aggiorno la posizione della scatola in funzione di '''x''' e '''y''' calcolati nell''''update'''. Beh, in realtà solo la '''x''' viene calcolata, la '''y''' per ora rimane ferma.

Quindi, per disegnarla, vado nel metodo '''render''' e aggiungo sta riga:

g.draw(box);

et voilà!

!!Usiamo la Nave
Torniamo al nostro '''StatoGioco'''. Ci creiamo una variabile

private Nave nave;

Andiamo al metodo '''enter''' e tiriamo su la '''Nave''':

nave = new Nave(100, 100);

posizionandola quindi nel punto 100, 100 dello schermo

Nel metodo '''update''' dello '''StatoGioco''' chiamiamo la '''update''' della '''Nave''':

player.update(container, game, delta);

Nel metodo '''render''' chiamiamo la '''render''' della '''Nave''':

player.render(container, game, g);

Se facciamo partire il progetto, vedremo disegnato un rettangolo di 200x32 pixel nella posizione 100, 100:) Ovviamente ancora non si muove. Per prova, provate a mettere la '''speed''' iniziale della nave ad un valore diverso da 0 per vederla muovere:)


!!La Nave la voglio muovere io
Ok. Torniamo allo '''StatoGioco'''. Creiamo una variabile così:

private Input input;

e nel metodo '''setInput''' mettiamo sta riga:

this.input = input;

Così facendo abbiamo detto allo stato di gioco di tenere via un riferimento al sistema di input fornito dalla libreria Slick.

L'idea basica del movimento è questa: se premo la freccia a destra, muovo la nave a destra. Se premo la freccia a sinistra, muovo la nave a sinistra. Se non premo niente, la nave sta ferma dov'è.

Andiamo nel metodo '''update''' dello '''StatoGioco'''. Come facciamo a sapere se un tasto è premuto? Così:

if (input.isKeyDown(Input.KEY_LEFT)) {
player.goLeft();
} else if (input.isKeyDown(Input.KEY_RIGHT)) {
player.goRight();
} else {
player.stop();
}

Stiamo chiedendo al sistema di input lo stato del tasto '''KEY_LEFT''' e lo stato del tasto '''KEY_RIGHT''', e facciamo esattamente quello che volevamo.
Provate adesso a fare andare il gioco e vedrete che muoverete la nave con le freccette:)

<<|[[Giochino Sottomarino]]|>>

----
[[!Guide]]