PDA

View Full Version : [JAVA][2D Programming, Game] Avoid Common Pitfalls...


banryu79
11-09-2008, 12:09
Consiglio questo breve articolo (http://www.acm.org/crossroads/xrds13-3/minueto.html) a tutti coloro che per vari motivi si trovano a programmare applicazioni/giochi in 2D in Java per cui la questione delle performance è importante.

Molto utile come punto di inizio per imparare a conoscere le strategie di base da utilizzare in merito. Ulteriori ricerche possono essere approfondite consultando il materiale citato (come il blog di Chet Haase).

Ciao :)

banryu79
11-09-2008, 12:15
L'articolo di cui sopra è stato scritto da uno studente che ha implementato un sdk per giochi 2D in Java che si chiama Minueto.
Per maggiori dettagli: Minueto (http://minueto.cs.mcgill.ca/)

Oceans11
11-09-2008, 12:19
Grazie mille!!!:)

banryu79
11-09-2008, 12:50
Ho dato un'occhiata a Minueto e alla sua documentazione (howTo e javadoc).
Mi sembra ben fatto e particolarmente adatto a chi si trova nella posizione di:

> implementare un'applicazione grafica 2D performante;
> non avere precedenti conoscenze in ambito di programmazione Java2D;
> essere da solo nell'implementare tale applicazione;
> essere un neofita.

Inoltre può risultare intereressante studiare le (poche) classi di tale libreria (non ho ancora controllato se i sorgenti sono disponibili) per capire che tipo di astrazione è stata costruita sulle classi messe a disposizione nel JDK della Sun e come è starta costruita.
In particolare, sembra che la focalizzazione sia mirata a sollevare l'utente dai dettagli derivanti dalla manipolazione e gestione diretta di quelle classi che normalmente vengono usate per gestire le immagini e il rendering in Java2D con la tecnica del double buffering e l'uso delle managed images.

Buona caccia :D

banryu79
16-12-2008, 13:40
GRAFICA, SPRITE & TOOLS

|> [Sprite] SpriteLib GPL (http://www.flyingyogi.com/fun/spritelib.html)
SpriteLib GPL, una raccolta di sprite statiche e animate distribuita con licenza GPL.

|> [Tool] Tiled, a generic tile map editor (http://mapeditor.org/)
Un general-purpose tile map editor scritto in Java.

|> [Sprite] Sprite Sheets (http://spritecity0.tripod.com/id4.html)
Raccolta di sprite a varie tematiche: fantasy generico, Halo sprites, Sapphire Unleashed, Inuyasha, Sesshomaru, il mitico Megaman e company, Sonic the Hedgehog, Gundam in tutte le salse, Heavy Arms, Medabots.

|> [Sprite] Lost Garden: free game graphics (http://lostgarden.com/labels/free%20game%20graphics.html)
Lost Garden è un blog dedicato all'arte e al game design, zeppo di interessantissimi articoli in merito. C'è anche qualche sprite liberamente scaricabile: Danc's Miraculously Flexible Game Prototyping Tiles (http://lostgarden.com/2007/05/dancs-miraculously-flexible-game.html).

TUTORIALS VARI

|> [Libro] Designig Arcade Computer Game Graphics (http://wiki.yoyogames.com/index.php/Ari_Feldman%27s_Book_on_Game_Graphics)
Autore: Ari Feldman. Libro fuori stampa, l'autore ne ha permesso la distribuzione in formato elettronico. Testo in lingua Inglese.
Il libro tratta della progettazione e dello sviluppo della grafica 2D di alta qualità per viodeogiochi di tipo "Arcade", ma include argomenti quali: il game design, la documentazione, l'uso appropriato dei colori e dei font più adatti. Liberamente scaricabile.

|> [Sito] Coke And Code (http://www.cokeandcode.com/tutorials)
Selezione di tutorial ben segmentati in capitoli che introducono e spiegano la programmazione di un gioco in Java un passo alla volta, costruendo un giochino completo in varie lezioni. Ottimo punto di partenza per chi conosce già il linguaggio ma parte da zero per quanto riguarda l'implementazione di un gioco.
Consigliato.

JAVA, VARIE ED EVENTUALI

|> Performance Tuning Threads (http://www.javagaming.org/index.php/board,20.0/sort,views/desc.html)
JavaGaming.org hosta un forum tutto centrato sul tema della creazione di giochi 2D/3D in ambiente Java e delle relative problematiche. Il forum è frequentato da molti utenti molto esperti nella materia (tanto per rendere l'idea, alcuni della crew di PuppyGames (http://www.puppygames.net/), se ho ben capito, più gente che a titolo più o meno vario è o è stata in stretto contatto con alcuni dei progetti dietro le librerie LWGL, JOGL, Java3D e compagnia bella).
Il forum è ovviamente in lingua inglese.
Consigliato solo a chi sa bene "le basi", e vuole invece sviscerare aspetti di nicchia molto avanzati.

|> Full-screen Eclusive Mode API (http://java.sun.com/docs/books/tutorial/extra/fullscreen/index.html)
Lezione sulla modalità esclusiva a schermo interno, funzionalità presente dalla versione 1.4 della piattaforma Java. Un must da usare nel contesto delle applicazioni graphics-intensive, come i giochi.

|> Java Games: Active Rendering (http://www.gamedev.net/reference/articles/article2418.asp)
Articolo che spiega la modalità nota come "active rendering"; uteriori informazioni per usarlo sia in windowed mode che in fullscreen exclusive mode.

gokan
17-12-2008, 11:57
Veramente interessante, soprattutto l'ultimo link..chi di noi non ha mai sognato di realizzare un gioco? :D
Io, ad esempio ho sempre sognato di realizzare un mio super mario :sofico:
Comunque scherzi a parte, si potrebbe pure trarre del profitto dallo sviluppo di giochini per cellulari. IMHO è un campo molto interessante!

banryu79
17-12-2008, 12:13
Veramente interessante, soprattutto l'ultimo link..chi di noi non ha mai sognato di realizzare un gioco? :D

[OT]
Questo "sogno nel cassetto" ce l'ho sempre avuto anch'io, pensa che c'era un gioco per il NES di cui mi ero innamorato: "Cip'n'Dale Rescue Rangers" e siccome leggevo Topolino, all'epoca, e il personaggio di Paperinik mi piaceva troppo, sognavo di fare un gioco analogo con Paperinik come protagonista...:D

All'epoca coinvolsi mia sorella per disegnare su carta con la matita i livelli e relizzammo i personaggi (Paperinik e qualche anonimo avversario) come figurine ritagliate sulla carta, da usare negli scenari creati:
finì tutto nella pattumiera il giorno dopo :D
[OT]

Per tornare in topic: sto seguendo i tutorial dell'ultimo link della lista; sono fatti bene, secondo me, approccio graduale, chiaro.
Sono corredati dai sorgenti completi del mini-gioco in oggetto, implementato in diversi modi (per esempio c'è space invaders in puro Java2D, poi in versione OpenGL 2D tramite JOGL e infine tramite LWJGL).

Penso di completare Space invaders per poi divertirmi ad estenderlo.


P.S.: nel sito puntato dall'ultimo link della lista c'è una sezione dedicata a Java Web Start che, tra l'altro, spiega come firmare i file .jar e come usare JNLP.

wingman87
18-12-2008, 04:00
Complimenti per il bel thread! L'ho salvato tra i preferiti, grazie!

franksisca
08-07-2009, 14:20
questo mi era sfuddito....conoscete qualche prodotto finito per vedere le potenzialità?

banryu79
08-07-2009, 14:30
questo mi era sfuddito....conoscete qualche prodotto finito per vedere le potenzialità?
Parli di prodotti che usano la libreria Minueto?
Qui c'è una pagina (http://minueto.cs.mcgill.ca/games.html) nel loro sito che ne illustra alcuni.
Ma dubito che sia usata per prodotti commerciali o di un certo rilievo, dato che come funzionailtà è piuttosto minimale se confrontata con altre famose librerie (tipo LWJGL o la GTGE).
Considera che il motivo primo della sua creazione era lo studio delle classi del JDK della Sun di Java2D, e come rendere certe operazioni più comode. Poi è venuta fuori una cosa carina e l'hanno pubblicata, o almeno questa è l'idea che mi sono fatto al riguardo.

Qui c'è
E qui i javadoc della API (http://minueto.cs.mcgill.ca/api/index.html): come vedi è facilmente abbordabile anche dal singolo programmatore novello, vista la ridotta quantità di classi. Con un po' di studio già solo sui javadoc si riesce ad avere una panoramica completa sulla libreria.

Caldwell83
17-07-2009, 13:28
[OT]
Questo "sogno nel cassetto" ce l'ho sempre avuto anch'io, pensa che c'era un gioco per il NES di cui mi ero innamorato: "Cip'n'Dale Rescue Rangers" e siccome leggevo Topolino, all'epoca, e il personaggio di Paperinik mi piaceva troppo, sognavo di fare un gioco analogo con Paperinik come protagonista...:D

All'epoca coinvolsi mia sorella per disegnare su carta con la matita i livelli e relizzammo i personaggi (Paperinik e qualche anonimo avversario) come figurine ritagliate sulla carta, da usare negli scenari creati:
finì tutto nella pattumiera il giorno dopo :D
[OT]

Per tornare in topic: sto seguendo i tutorial dell'ultimo link della lista; sono fatti bene, secondo me, approccio graduale, chiaro.
Sono corredati dai sorgenti completi del mini-gioco in oggetto, implementato in diversi modi (per esempio c'è space invaders in puro Java2D, poi in versione OpenGL 2D tramite JOGL e infine tramite LWJGL).

Penso di completare Space invaders per poi divertirmi ad estenderlo.


P.S.: nel sito puntato dall'ultimo link della lista c'è una sezione dedicata a Java Web Start che, tra l'altro, spiega come firmare i file .jar e come usare JNLP.

Che modifiche hai fatto sul gioco?
Io queste:
Aggiunto la possibilita' di definire una lista di immagini per ogni oggetto, in modo da avere una mini animazione.
Gli alieni sparano.
Quando i miei colpi e quelli degli alieni si incontrano si autodistruggono.
Quando gli alieni vengono colpiti "esplodono".
Sono modifiche molto spicciole.
Ora avevo intenzione di aggiungere i massi che pian piano si distruggono.

Scrivo questo post per poter magari confrontare le varie implementazioni di una stessa funzione e discuterne :)

banryu79
17-07-2009, 13:46
Scrivo questo post per poter magari confrontare le varie implementazioni di una stessa funzione e discuterne :)
Come noterai dalle date, è roba che avevo intenzione di fare mesi fa, e che per vari motivi non ho più portato avanti (anche se le idee c'erano). L'unica modifica che avevo introdotto, prima di dover interrompere, era avere un'immagine di background diversa (cambiava la tonalità del colore, ma l'immagine era la stessa) a seconda dell'atezza raggiunta dagli alineni nel loro procedere verso il fondo (avevo fatto in modo che acellerassero sempre di più la loro velocità di movimento ogni volta che completavano una fase di spostamento orizzontale) per sucitare un senso di maggiore fenesia al giocatore.
A, e poi avevo aggiunto una strombazzata (Toolkit.beep) ogni volta che si colpiva un alieno :D.

Caldwell83
17-07-2009, 13:51
Si si, la data dei post l'avevo vista, era per quello che pensavo fossi andato avanti :D
Comunque grazie per i link, davvero ottimi :mano:

banryu79
28-08-2009, 15:30
Un piccolo up.
Magari è una cosa scontata ma non si sa mai: dalla versione 1.4 della piattaforma JavaSE si può utilizzare la "Modalità esclusiva a schermo intero".

In pratica una sorta di undecorated window massimizzata a fullscreen dove si può bloccare la gestione del rendering da parte del "windowing system" del sistema operativo e ottenere pieno controllo del ciclo di rendering stesso. Non che prima non lo si avesse, ma ora il windowing system non "si intromette" più con le sue richieste di repaint.

Questa modalità, unita alle tecniche per manipolare immagini in modo efficiente è una manna per chi deve scrivere applicazioni graphics-intensive (per esempio videogiochi) ad alte prestazioni.

- The Java Tutorials - Lesson: Full-Screen Exclusive Mode API (http://java.sun.com/docs/books/tutorial/extra/fullscreen/index.html)

wingman87
29-08-2009, 00:22
Questo tuo post capita proprio a proposito, circa un mese fa mi ero impantanato con la gestione del fullscreen, non pensavo ci fosse un tutorial ufficiale. Sto facendo uno sparatutto a scorrimento verticale con degli amici, stiamo scrivendo sia l'engine che il videogioco, per ora ci stiamo concentrando più sul primo e volevo rendere semplice la gestione del fullscreen. Grazie per il link.

banryu79
31-08-2009, 16:59
@wingman87:
Ciao,
credo troverai questa pagina web una buona risorsa per informazioni circa la tecnica dell'active rendering sia in windowed mode che in full screen mode.
- Java Games: Active Rendering (http://www.gamedev.net/reference/articles/article2418.asp)

mone.java
01-09-2009, 11:11
Per tornare in topic: sto seguendo i tutorial dell'ultimo link della lista; sono fatti bene, secondo me, approccio graduale, chiaro.
Sono corredati dai sorgenti completi del mini-gioco in oggetto, implementato in diversi modi (per esempio c'è space invaders in puro Java2D, poi in versione OpenGL 2D tramite JOGL e infine tramite LWJGL).

Penso di completare Space invaders per poi divertirmi ad estenderlo.


P.S.: nel sito puntato dall'ultimo link della lista c'è una sezione dedicata a Java Web Start che, tra l'altro, spiega come firmare i file .jar e come usare JNLP.

bellissimi i tutorial fatti da kevin glass!!!! Io grazie a quello su java2D imparai abbastanza bene cosa significasse la programmazione a oggetti (era nemmeno un anno che programmavo e molte cose nn le avevo chiare). In seguito ho utilizzato la struttura usata per lo SpaceInvaders per fare un PuzzleBobble.

Caldwell83
02-09-2009, 17:25
Per chi ne avesse bisogno un'ottimo editor per mappe 2d:
http://mapeditor.org/
Un po' di immagini varie:
http://spritecity0.tripod.com/id4.html

PGI-Bis
02-09-2009, 20:41
Immagini liberamente usabili per motori tile-based si trovano anche qui:

http://lostgarden.com/labels/free%20game%20graphics.html

Alcune sono veramente spettacolari. Una volta ero lì che cercavo per l'ennesima volta di mettere insieme due pixel che non sembrassero la solita ciofeca quando sono capitato su quel sito e, be', a momenti mi mangio la tavoletta grafica con penn-harakiri di rimando.

Questo set ad esempio è meraviglioso:

http://lostgarden.com/uploaded_images/ExteriorTest-760306.jpg

Caldwell83
03-09-2009, 07:46
Pure io l'avevo trovato questo sito.
Sono tutti molto belli e ce ne sono per tutti i gusti.
Io ho intenzione di usare il set Hard Vacuum.
Edit:
Un bel progetto da cui sono partito: http://www.fabiensanglard.net/Prototyp/index.php
E' sviluppato tramite OpenGL con le librerie lwjgl.

banryu79
03-09-2009, 08:32
Grazie delle segnalazioni!
In effetti la pixel art è tutto fuori che una cosa scontata, è una vera e propria arte :)
Alcune sprite sono delle chicche grafiche meravigliose che a volte mi fanno rimpiangere i giochi pre-mondo3D.
Appena ho tempo riorganizzo in un post unico la raccolta di link.

P.S.: se qualcuno di voi conosce qualche risorsa di sprite libere a tema "X-Wing" e "Tie-Figther" gliene sarai veramente grato :)

shinya
03-09-2009, 08:52
P.S.: se qualcuno di voi conosce qualche risorsa di sprite libere a tema "X-Wing" e "Tie-Figther" gliene sarai veramente grato :)
Anche tu vuoi scriverti il tuo personale bullet hell shooter? :D

banryu79
03-09-2009, 09:07
Anche tu vuoi scriverti il tuo personale bullet hell shooter? :D
Solo a patto di poterlo ambientare nelle atmosfere uniche dei combattimenti spaziali di Star Wars.
Oltre che essere un patito di lunga data (film, libri, fumetti, 8 anni di sessioni a Star Wars rolepaly game con i miei cugini e uno zio) ricordo con grande nostalgia la scoperta a casa di mio cugino del mitico "X-Wing" e successivamente le ore passate a giocarci sul mio pc.

Far bene uno shooter 2D, per mio sfizio personale (vedere che faccia farebbe questo mio cugino di fronte all'eventuale gioco implementato) non mi dispiacerebbe :p
Se poi si impara pure qualcosa, tanto meglio.
L'unica risorsa che mi manca è il tempo: ma perchè noi esseri umani abbiamo per forza bisogno di tot ore di sonno ogni notte? :asd:

banryu79
03-09-2009, 13:09
Ho riorganizzato il post che raccoglie le risorse segnalate.
Si tratta del post #5 (http://www.hwupgrade.it/forum/showpost.php?p=25465338&postcount=5).

Caldwell83
04-09-2009, 11:29
P.S.: se qualcuno di voi conosce qualche risorsa di sprite libere a tema "X-Wing" e "Tie-Figther" gliene sarai veramente grato :)
Qualcosa un po' di tempo fa avevo trovato, ma erano modelli 3d.
Se ti interessa questa sera provo a ritrovare il sito.

banryu79
04-09-2009, 11:41
Qualcosa un po' di tempo fa avevo trovato, ma erano modelli 3d.
Se ti interessa questa sera provo a ritrovare il sito.
Mi basta un "canovaccio" di partenza: posso editare immagini grazie a Paint.NET ma alla fine devo produrre delle sprite2D.
Comunque potrebbero essermi utili: se trovi il link ti ringrazio.

Caldwell83
04-09-2009, 11:44
Se ti servono delle sprite 2d, potresti utilizzare un programma di modellazione 3d, caricarti i modelli e fare i render delle viste che ti servono :).
Sta sera vedo se riesco a ritrovarlo.

Caldwell83
04-09-2009, 17:09
Trovato:
http://www.vanishingpoint.biz/freestuff.asp?ClassificationID=1

wingman87
04-09-2009, 19:11
Se ti servono delle sprite 2d, potresti utilizzare un programma di modellazione 3d, caricarti i modelli e fare i render delle viste che ti servono :).
Mi ispira molto la tua idea, esiste qualche programma free per far questo?

Caldwell83
04-09-2009, 19:17
Mi ispira molto la tua idea, esiste qualche programma free per far questo?
http://www.blender.org/

PGI-Bis
04-09-2009, 19:28
Blender è bellissimo ma la sua interfaccia è progettata da gente per la quale GUI è il verso di un qualche misterioso uccello tropicale.

Di facilissimo c'è anim8or (http://www.anim8or.com/)

Papabile anche artofillusion (http://www.artofillusion.org/)

wingman87
04-09-2009, 23:14
Grazie a Caldwell e PGI. Li proverò il prima possibile

Caldwell83
09-09-2009, 18:57
Domanda:
Come faccio a riconoscere una precisa combinazione di tasti per fare una mossa speciale o cose del genere?
Mi faccio un'array o una lista degli ultimi n tasti premuti e poi controllo che esista quella combinazione?

Anche semplicemente una doppia pressione di un tasto, tipo il dodge di UT per intenderci.
Controllo il tempo intercorso tra le 2 pressioni?
Questo è il codice per il tasto sinistra:

KeyListener leftKeyEvent = new KeyListener() {
public void onKeyDown() { };
public void keyPressed() {
speed.x -= ACCELLERATION * tick / 1000;
if (speed.x < -MAX_SPEED)
speed.x = -MAX_SPEED;
};
public void onKeyUp() {
x_deceleration = DEFAULT_DECELERATION;
};
};
EventManager.instance().addListener(leftKey, leftKeyEvent);

Nel frattempo vi favorisco uno screen del gioco allo stato super-embrionale

http://img76.imageshack.us/img76/5664/jenad.th.jpg (http://img76.imageshack.us/i/jenad.jpg/)

PGI-Bis
09-09-2009, 19:11
Di solito i tasti si accumulano in un buffer. Una cosa tipo questa:

private int keystate = 0;
public static final int KEY_LEFT = 2;
public static final int KEY_RIGTH = 4;
public static final int KEY_UP = 8;
public static final int KEY_DOWN = 16;

public void keyPressed(KeyEvent e) {
final int code = e.getKeyCode();
switch(code) {
case KeyEvent.VK_LEFT: keystate |= KEY_LEFT; break;
case KeyEvent.VK_RIGHT: keystate |= KEY_RIGHT; break;
case KeyEvent.VK_UP: keystate |= KEY_UP; break;
case KeyEvent.VK_DOWN: keystate |= KEY_DOWN; break;
}
}

public void keyReleased(KeyEvent e) {
final int code = e.getKeyCode();
switch(code) {
case KeyEvent.VK_LEFT: keystate &= ~KEY_LEFT; break;
case KeyEvent.VK_RIGHT: keystate &= ~KEY_RIGHT; break;
case KeyEvent.VK_UP: keystate &= ~KEY_UP; break;
case KeyEvent.VK_DOWN: keystate &= ~KEY_DOWN; break;
}
}

public boolean isOn(int controlCode) {
return (keyState & controlCode) == controlCode;
}

Cioè quando premi un tasto attivi il corrispondente bit nella "maschera" keystate e quando lo rilasci lo disattivi. Con questo gestisci la pressione di più tasti. Se premo A e B il bit di A e il bit di B diventano "vero" e hai i due tasti.

Caldwell83
09-09-2009, 19:35
Facendo in questo modo quindi ad ogni ciclo di "update" dovrei controllare con la funzione isOn quali tasti sono premuti giusto?

PGI-Bis
09-09-2009, 19:36
Esatto.

Caldwell83
10-09-2009, 09:33
Per la pressione dei tasti in contemporanea sono ok.
Per riconoscere una precisa sequenza di tasti invece come si potrebbe fare?

Queste sono le classi che uso per l'input da tastiera:
public class EventManager {

//Singleton variable and methods:
private EventManager(){};
private static EventManager instance;

public static EventManager instance() {
if (instance == null)
instance = new EventManager();
return instance;
}

private ArrayList<KeyListener> listeners = new ArrayList<KeyListener>();

public void addListener(int key,KeyListener listener) {
listener.setKeyMonitored(key);
listeners.add(listener);
}

public void removeListener(KeyListener listener) {
listeners.remove(listener);
}

public void clear() {
listeners.clear();
}

void checkEvents() {
for(KeyListener listener: listeners) {
listener.checkKey();
}
}
}


public class KeyListener {

private int keyMonitored;
private boolean keyMonitoredWasPressed;

public void setKeyMonitored(int keyMonitored) {
this.keyMonitored = keyMonitored;
}

public void onKeyDown(){}; // This is triggered exactly when the key is pressed.
public void keyPressed(){}; // This is triggered will the key is being pressed.
public void onKeyUp(){}; // This is triggered exactly when the key is released.

public void checkKey() {
if(Keyboard.isKeyDown(keyMonitored)) {
if(keyMonitoredWasPressed)
keyPressed();
else {
keyMonitoredWasPressed = true;
onKeyDown();
}

} else {
if (keyMonitoredWasPressed) {
onKeyUp();
keyMonitoredWasPressed = false;
}
}
}
}

Ad ogni ciclo chiamo il metodo checkEvents.

Per fare come ha detto PGI-Bis dovrei fare un "merge" fra queste due classi ed invece che chiamare il metodo checkEvents, ogni classe che ha bisogno di input dall'utente chiamare un nuovo metodo isKeyPressed(key). Giusto?

PGI-Bis
10-09-2009, 09:56
Devi solo accumulare i tasti in un buffer. Ad ogni passaggio nel ciclo del motore di gioco quando sei nella fase di raccolta dell'input se è passato un periodo di tempo soglia impili lo stato attuale dei pulsanti in una pila - o un anello se vuoi limitare le dimensoni del buffer.

Nella fase di gestione dell'input esamini la coda. Una sequenza di tre pulsanti esaminerà i primi tre elementi della pila-buffer: se la sequenza è A,B,C, e dalla pila ricavi K0,K1,K2 verificherai se in K0 risulti premuto C, in K1 risulti premuto B e in K2 A.

Caldwell83
10-09-2009, 10:08
Perfetto grazie, come l'avevo pensata anch' io.

franksisca
11-09-2009, 11:02
ragazzi, io sto facendo una specie di fps 3d e ho un grossissimo problema (per il momento ultimo problema).


la gestione del movimento del mio personaggio


ditemi se volete che posto qui o se preferite che apro un thread apposito.

banryu79
11-09-2009, 12:16
ragazzi, io sto facendo una specie di fps 3d e ho un grossissimo problema (per il momento ultimo problema).


la gestione del movimento del mio personaggio


ditemi se volete che posto qui o se preferite che apro un thread apposito.
Per me non ci sono problemi: puoi postare qui.

PGI-Bis
11-09-2009, 13:39
Spara, siamo qui pronti coi quaternioni in canna!

franksisca
11-09-2009, 13:48
praticamente io ho implementato tutto manualmente il movimento (codice scritto 2 anni fà, poi per probleemi familiari non l'ho più toccato, ora vorrei fare l'esame e quindi ci ho rimesso mano) quindi ci saranno acnhe castronerie grosse...allora io ho fatto 2 implementazioni del movemento, una mi risulta scattosa (praticamente il movimento del mio ogetto3d non è fluido) mentre l'altra non interagisce con gli altri oggetti (nemici, muri, pozioni)


vi posto tutto il src perchè così vi rendete conto di tutto il codice (copiare solo porzioni credo ceh renderebbe complessa l'operazione)


se vi servono info ditemi pure...e non commentate le scelte cromatiche e le altre cose....ne vedrete delle belle (in tutti i sensi) :D

http://www.megaupload.com/?d=DP9N2YMS

banryu79
11-09-2009, 16:40
http://www.megaupload.com/?d=DP9N2YMS
Il nuovo (e severissimo) firewall aziendale non mi permette di connettermi con www.megaupload.com

mindwings
11-09-2009, 18:41
@banryu79 bel thread :) (articoli moolto interessanti)

PGI-Bis
11-09-2009, 20:14
frank ho visto il codice.

Non riesco a trovare il punto in cui fai il controllo delle collisioni.

Mi aspetterei di trovarlo nei dintorni dell'aggiornamento delle posizioni.

Cioè mi aspetterei una cosa di questo genere:

1. adesso muovo il giocatore
2. il giocatore si muova in avanti di un metro
3. c'è qualcosa nella posizione in cui si trova il giocatore dopo essersi mosso in avanti di un metro?
3.1 Sì, c'è un muro: torna indietro di un metro
3.2 Sì, c'è un mostro: muori
3.3 Non c'è nulla: conferma il movimento.

C'è ma non lo vedo?

P.s: m'aspetterei anche uno pelo di documentazione sulla struttura del programma, così tanto per non dover andare in giro per il codice a tentoni, con una candela fioca, in una notte senza luna con il temporale che imperversa :D

franksisca
11-09-2009, 21:10
frank ho visto il codice.

Non riesco a trovare il punto in cui fai il controllo delle collisioni.

Mi aspetterei di trovarlo nei dintorni dell'aggiornamento delle posizioni.

Cioè mi aspetterei una cosa di questo genere:

1. adesso muovo il giocatore
2. il giocatore si muova in avanti di un metro
3. c'è qualcosa nella posizione in cui si trova il giocatore dopo essersi mosso in avanti di un metro?
3.1 Sì, c'è un muro: torna indietro di un metro
3.2 Sì, c'è un mostro: muori
3.3 Non c'è nulla: conferma il movimento.

C'è ma non lo vedo?

P.s: m'aspetterei anche uno pelo di documentazione sulla struttura del programma, così tanto per non dover andare in giro per il codice a tentoni, con una candela fioca, in una notte senza luna con il temporale che imperversa :D

hai perfettamente ragione, infatti nella prossima settimana è la prima cosa che farò.

prenderò classe per classe e aggiungerò la documentazione.


questo weekend non ci osno, ma da lunedì mi ci rimetto a lavoro.


per il discorso movimento, nella classe DJPack metodo setNavigato mi sembra... cambia il navigato (sono commentati ) e vedrai che succede (se non lo hai già fatto).


cmq ripeto lunedì inizio a lavorarci seriamente e vi aggiorno....tanto poi spero di darvelo completo :D

cdimauro
12-09-2009, 05:18
Meglio aggiungere una buona batteria di test (http://www.hwupgrade.it/forum/showthread.php?t=1017489) che della documentazione, così il codice si autodocumenta. ;)

PGI-Bis
12-09-2009, 09:06
Sai già che considero i test inutili e l'autodocumentazione una chimera ma, vecchio birbante, non mi trascinerai sul ring! :D

franksisca
12-09-2009, 09:23
Meglio aggiungere una buona batteria di test (http://www.hwupgrade.it/forum/showthread.php?t=1017489) che della documentazione, così il codice si autodocumenta. ;)
dopo che junit e jtest mi hanno fatto perdere 5 punti all'esame di Ingegneria del software (quando l'ho fatto io ancora non erano utilizzzzati...l'anno dopo, quando ho sostenuto l'esame si e sono rimasto:ciapet: ) mi sono ripromesso di non utilizzarli :asd: :asd:
Sai già che considero i test inutili e l'autodocumentazione una chimera ma, vecchio birbante, non mi trascinerai sul ring! :D

la documentazione potrebbe essere utile...cmq ora scappo...lunedì lavvoro sul codice e appena ho news posto tutto qui

cdimauro
12-09-2009, 11:49
Sai già che considero i test inutili
Sì, lo so come la pensi. Ma vedi, senza la preziosissima batteria di test in dotazione a Python, per realizzare questo (http://code.google.com/p/wpython/) non avrei impiegato 3 mesi, ma 3 anni (ma molto probabilmente l'avrei interrotto prima).

Non hai idea di quanti bug, anche estremamente subdoli, sia riuscito a individuare e correggere. :read: :Prrr:
e l'autodocumentazione una chimera ma,
Perché, la documentazione non lo è? :asd:
vecchio birbante, non mi trascinerai sul ring! :D
Veramente sto ancora aspettando le tue dissertazioni sul C++. :fiufiu:
dopo che junit e jtest mi hanno fatto perdere 5 punti all'esame di Ingegneria del software (quando l'ho fatto io ancora non erano utilizzzzati...l'anno dopo, quando ho sostenuto l'esame si e sono rimasto:ciapet: ) mi sono ripromesso di non utilizzarli :asd: :asd:
Vabbé, e sarebbe colpa dei test? :stordita:

PGI-Bis
12-09-2009, 12:21
Be', è un episodio di utilità dei test. Possiamo assumerlo come testimone di una generale utilità dei test? No, così come non possiamo dire che siccome una mela è caduta tutte le mele cadono.

Comunque è un discorso che abbiamo fatto più e più volte - l'ultima è stata quella in cui siamo finiti su godel se non ricordo male - non vale la pena ri-prendersi a cornate.

p.s: su python aspetto con trepidazione l'uscita della versione di Jython per la JVM 1.7. Dai primi test sembra che JRuby risulti del 500% più rapido.

cdimauro
12-09-2009, 21:01
Be', è un episodio di utilità dei test. Possiamo assumerlo come testimone di una generale utilità dei test? No, così come non possiamo dire che siccome una mela è caduta tutte le mele cadono.
Non è l'unico episodio che m'è capitato. Anzi, posso dirti che, nella mia esperienza, più è grosso e "complicato" il progetto, più una batteria di test aiuta quando si fanno delle modifiche. E tanto più pesanti sono le modifiche, tanto più comodi si rivelano i test perché riescono a far saltare fuori moooolto più facilmente le nuove falle che vengono introdotte.
Comunque è un discorso che abbiamo fatto più e più volte - l'ultima è stata quella in cui siamo finiti su godel se non ricordo male - non vale la pena ri-prendersi a cornate.
Me ne rendo conto. Infatti io riporto soltanto la mia (limitata) esperienza e non pretendo di generalizzare il ragionamento alla totalità del codice prodotto.

Non riporto neppure una dimostrazione perché si tratta di esperimenti empirici. Pratiche che POSSONO aiutare, ma fermiamoci qui. Un po' come la programmazione a oggetti che PUO' aiutare nello sviluppo & mantenimento del codice, ma non è affatto dimostrato che lo faccia.
p.s: su python aspetto con trepidazione l'uscita della versione di Jython per la JVM 1.7. Dai primi test sembra che JRuby risulti del 500% più rapido.
Risultati così grossi mi fanno pensare all'introduzione di apposite istruzioni per gestire il dynamic binding e la runtime execution. Quindi promette molto bene.

L'unica fregatura con la JVM è che succhia (memoria) come una donna di facili di costumi. :ciapet:

Vedremo quando arriverà finalmente la JVM 1.7, che si fa attendere da un bel pezzo ormai (mi sa che l'acquisizione da parte di Oracle sta portando un po' di sfiga ai progetti più rinomati di Sun... :stordita: ).

Y3PP4
12-09-2009, 21:34
Cioè mi aspetterei una cosa di questo genere:

1. adesso muovo il giocatore
2. il giocatore si muova in avanti di un metro
3. c'è qualcosa nella posizione in cui si trova il giocatore dopo essersi mosso in avanti di un metro?
3.1 Sì, c'è un muro: torna indietro di un metro
3.2 Sì, c'è un mostro: muori
3.3 Non c'è nulla: conferma il movimento.


Linguaggio a parte, io mi aspetterei:
1. chiedo al programma di muovere il personaggio di una unità nella direzione voluta
2. c'è qualcosa nella posizione in vuole muoversi il giocatore?
2.1 : Si, collide con un oggetto: non si muove.
2.2 : No, si muove di una unità nella direzione desiderata.

Non mi sembra che i vari sistemi di gioco facciano il "passo avanti" poi se incontra un oggetto torna indietro.
Altrimenti il primo passo contro un muro ti vedi il pg che ci "entra" e poi viene slittato fuori (ahimè di sistemi di collisione imperfetti ce ne sono e non è raro vedere il pg con un braccio nel muro).

Ovviamente è anche certo che la collisione è più complessa di quanto descritto e ci sono vari e numerosi metodi d'implementazione.

Chiedo scusa all'autore per l'OT e a PGI-Bis per l'inutilità di questo mio post, ma volevo scriverlo e l'ho fatto :D (A)

PGI-Bis
12-09-2009, 21:54
Il passo avanti-indietro avviene in una fase che precede il rendering ed è in verità una proiezione del volume del giocatore nella posizione che assumerebbe se il movimento fosse libero. Se quella proiezione del volume non collide con niente significa che il giocatore può fare quel movimento.

Non so se ci siano altre tecniche per la gestione delle collisioni, io ho studiato solo questa.

franksisca
13-09-2009, 21:09
Vabbé, e sarebbe colpa dei test? :stordita:

no, ma a qualcuno dovevo darla la colpa :D


domani mi metto a lavor :D

franksisca
25-09-2009, 10:28
dopo una settimana tribolata (compresa sospensione) sono qui a dirvi che nonho fatto una emerita mazza :D

cmq non mi scordo di passare da qui appena posso.

cmq credo che l'inghippo sia qui:

public void setNavigatore(TransformGroup tg, BranchGroup radice) {
// al navigatore viene passata la posizione del punto di vista

KeyNavigatorBehavior2 keyNavBeh = new KeyNavigatorBehavior2(tg);
keyNavBeh.setSchedulingBounds(new BoundingSphere(new
Point3d(),1000.0));
radice.addChild(keyNavBeh);

//navigatore = new KeyUsers(tg, this.labirinto, this.posizione,
// this.navigatoreAttivo);
//radice.addChild(navigatore);
navigatoreAttivo = true;
}

con il primo navigatore il movimento è fluido ma salta i check sulle collisioni, mentre col secondo è "scattoso" ma fàò il check...solo che i due navigatori hanno strutture completamente diverse, il primo l'ho preso in rete su qualche tutorial (mannaggia a me che non mi segno mai queste cose), ils econdo l'ho fatto io da me (mannaggia a me che a volte voglio fare tutto da 0).

in poche parole...mannaggia a me :asd:

PGI-Bis
25-09-2009, 14:27
Perchè non usi una libreria per la gestione della fisica, tipo JBullet o JMEPhysics?

Ti assicuro che è uno spasso. Con una mancianta di linee di codice sei pronto a rimbalzare all'interno di qualsiasi labirinto :D.

franksisca
25-09-2009, 14:29
Perchè non usi una libreria per la gestione della fisica, tipo JBullet o JMEPhysics?

Ti assicuro che è uno spasso. Con una mancianta di linee di codice sei pronto a rimbalzare all'interno di qualsiasi labirinto :D.

:asd:

link link link (si mi scoccia cercare su google...ho il wikijava vivente qui :p)

banryu79
25-09-2009, 14:36
:asd:

link link link (si mi scoccia cercare su google...ho il wikijava vivente qui :p)
Chi sarebbe? :D

JBullet:
- JBullet - Java port of Bullet Physics Library (http://jbullet.advel.cz/)
- JBullet integration - progress, questions and gripes. (http://www.jmonkeyengine.com/forum/index.php?topic=8087.0)
JMEPhysics:
- jmephysics (http://code.google.com/p/jmephysics/)
- Fix for jMEPhysics problem caused after 4640 (http://www.jmonkeyengine.com/forum/index.php?topic=12002.0)

franksisca
25-09-2009, 14:45
Chi sarebbe? :D

JBullet:
- JBullet - Java port of Bullet Physics Library (http://jbullet.advel.cz/)
- JBullet integration - progress, questions and gripes. (http://www.jmonkeyengine.com/forum/index.php?topic=8087.0)
JMEPhysics:
- jmephysics (http://code.google.com/p/jmephysics/)
- Fix for jMEPhysics problem caused after 4640 (http://www.jmonkeyengine.com/forum/index.php?topic=12002.0)

dimenticavo....suppongo che sono compatibili con java3d che devo usare per forza ???

PGI-Bis
25-09-2009, 14:49
JBullet usa gli stessi primitivi di Java3D (vettori, matrici, quaternioni eccetera).

JMePhysics invece richiede le librerie JMonkeyEngine.

Entrambi funzionano separatamente rispetto al motore di rendering usato.

franksisca
25-09-2009, 15:15
JBullet usa gli stessi primitivi di Java3D (vettori, matrici, quaternioni eccetera).

JMePhysics invece richiede le librerie JMonkeyEngine.

Entrambi funzionano separatamente rispetto al motore di rendering usato.

il fatto è che per l'esame devo usare java3d...quindi non credo di poter utilizzare queste librerie...o no???

PGI-Bis
25-09-2009, 15:18
Dipende dall'esame. Per andare sul sicuro puoi chiedere al prof.

Comunque se l'esame verte sulla fisica delle collisioni è chiaro che non puoi usare una libreria che gestisce la fisica delle collisioni :D.

franksisca
07-10-2009, 09:10
Dipende dall'esame. Per andare sul sicuro puoi chiedere al prof.

Comunque se l'esame verte sulla fisica delle collisioni è chiaro che non puoi usare una libreria che gestisce la fisica delle collisioni :D.

chiesto...l'esame è su java3d, quindi non credo di poter usare librerie esterne per la realizzazione

stavo cercando alcuni esempi per cercare di chiarire il perchè non funziona....ho trovato questo, ma mi dà heap space...in eclipse ho modificato il file ini ma oltre i 600 mega non mi fà andare...suggerimenti??
import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Vector;

import javax.media.j3d.Alpha;
import javax.media.j3d.Appearance;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Background;
import javax.media.j3d.BackgroundSound;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Group;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Locale;
import javax.media.j3d.MediaContainer;
import javax.media.j3d.Node;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.PointSound;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Sound;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnCollisionEntry;
import javax.media.j3d.WakeupOnCollisionExit;
import javax.media.j3d.WakeupOnElapsedTime;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Color3f;
import javax.vecmath.Color4f;
import javax.vecmath.Point2d;
import javax.vecmath.Point2f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;

import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import com.sun.j3d.loaders.Scene;
import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator;
import com.sun.j3d.utils.behaviors.interpolators.TCBKeyFrame;
import com.sun.j3d.utils.geometry.Cone;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.image.TextureLoader;

/**
* Simple DOOM style navigation of a 3D scene using Java 3D. The scene
* description is loaded from a GIF file where different colors denote objects
* in the 3D scene. The example includes: simple (manual) collision detection,
* texture animation, keyboard navigation.
*/
public class KeyNavigateTest extends Java3dApplet implements CollisionDetector {
private static int m_kWidth = 300;

private static int m_kHeight = 300;

private static final String m_szMapName = new String("brick2.gif");

private float FLOOR_WIDTH = 256;

private float FLOOR_LENGTH = 256;

private final int m_ColorWall = new Color(0, 0, 0).getRGB();

private final int m_ColorGuard = new Color(255, 0, 0).getRGB();

private final int m_ColorLight = new Color(255, 255, 0).getRGB();

private final int m_ColorBookcase = new Color(0, 255, 0).getRGB();

private final int m_ColorWater = new Color(0, 0, 255).getRGB();

private Vector3d m_MapSquareSize = null;

private Appearance m_WallAppearance = null;

private Appearance m_GuardAppearance = null;

private Appearance m_BookcaseAppearance = null;

private Appearance m_WaterAppearance = null;

private BufferedImage m_MapImage = null;

private final double m_kFloorLevel = -20;

private final double m_kCeilingHeight = 50;

private final double m_kCeilingLevel = m_kFloorLevel + m_kCeilingHeight;

private Vector3d m_Translation = new Vector3d();

public KeyNavigateTest() {
initJava3d();
}

protected double getScale() {
return 0.05;
}

protected int getCanvas3dWidth(Canvas3D c3d) {
return m_kWidth - 10;
}

protected int getCanvas3dHeight(Canvas3D c3d) {
return m_kHeight - 10;
}

// edit the positions of the clipping
// planes so we don't clip on the front
// plane prematurely
protected double getBackClipDistance() {
return 20.0;
}

protected double getFrontClipDistance() {
return 0.05;
}

// we create 2 TransformGroups above the ViewPlatform:
// the first merely applies a scale, while the second is
// manipulated using the KeyBehavior
public TransformGroup[] getViewTransformGroupArray() {
TransformGroup[] tgArray = new TransformGroup[2];
tgArray[0] = new TransformGroup();
tgArray[1] = new TransformGroup();

Transform3D t3d = new Transform3D();
t3d.setScale(getScale());
t3d.invert();
tgArray[0].setTransform(t3d);

// ensure the Behavior can access the TG
tgArray[1].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

// create the KeyBehavior and attach
KeyCollisionBehavior keyBehavior = new KeyCollisionBehavior(tgArray[1],
this);
keyBehavior.setSchedulingBounds(getApplicationBounds());
keyBehavior.setMovementRate(0.7);
tgArray[1].addChild(keyBehavior);

return tgArray;
}

protected BranchGroup createSceneBranchGroup() {
BranchGroup objRoot = super.createSceneBranchGroup();

TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

createMap(objTrans);
createFloor(objTrans);
createCeiling(objTrans);

objRoot.addChild(objTrans);

return objRoot;
}

public Group createFloor(Group g) {
System.out.println("Creating floor");

Group floorGroup = new Group();
Land floorTile = null;

// use a shared Appearance so we only store 1 copy of the texture
Appearance app = new Appearance();
g.addChild(floorGroup);

final double kNumTiles = 6;

for (double x = -FLOOR_WIDTH + FLOOR_WIDTH / (2 * kNumTiles); x < FLOOR_WIDTH; x = x
+ FLOOR_WIDTH / kNumTiles) {
for (double z = -FLOOR_LENGTH + FLOOR_LENGTH / (2 * kNumTiles); z < FLOOR_LENGTH; z = z
+ FLOOR_LENGTH / kNumTiles) {
floorTile = new Land(this, g, ComplexObject.GEOMETRY
| ComplexObject.TEXTURE);
floorTile.createObject(app, new Vector3d(x, m_kFloorLevel, z),
new Vector3d(FLOOR_WIDTH / (2 * kNumTiles), 1,
FLOOR_LENGTH / (2 * kNumTiles)), /*"brick.gif"*/"",
null, null);
}
}

return floorGroup;
}

public Group createCeiling(Group g) {
System.out.println("Creating ceiling");

Group ceilingGroup = new Group();
Land ceilingTile = null;

// because we are technically viewing the ceiling from below
// we want to switch the normals using a PolygonAttributes.
Appearance app = new Appearance();
app.setPolygonAttributes(new PolygonAttributes(
PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0,
false));

g.addChild(ceilingGroup);

final double kNumTiles = 6;

for (double x = -FLOOR_WIDTH + FLOOR_WIDTH / (2 * kNumTiles); x < FLOOR_WIDTH; x = x
+ FLOOR_WIDTH / kNumTiles) {
for (double z = -FLOOR_LENGTH + FLOOR_LENGTH / (2 * kNumTiles); z < FLOOR_LENGTH; z = z
+ FLOOR_LENGTH / kNumTiles) {
ceilingTile = new Land(this, g, ComplexObject.GEOMETRY
| ComplexObject.TEXTURE);
ceilingTile.createObject(app, new Vector3d(x, m_kCeilingLevel,
z), new Vector3d(FLOOR_WIDTH / (2 * kNumTiles), 1,
FLOOR_LENGTH / (2 * kNumTiles)), "brick.gif", null,
null);
}
}

return ceilingGroup;
}

Point3d convertToWorldCoordinate(int nPixelX, int nPixelY) {
Point3d point3d = new Point3d();
Vector3d squareSize = getMapSquareSize();

// range from 0 to 1
point3d.x = nPixelX * squareSize.x;
point3d.x -= FLOOR_WIDTH;

point3d.z = nPixelY * squareSize.z;
point3d.z -= FLOOR_LENGTH;

point3d.y = 0;

return point3d;
}

Point3d convertToWorldCoordinatesPixelCenter(int nPixelX, int nPixelY) {
Point3d point3d = convertToWorldCoordinate(nPixelX, nPixelY);
Vector3d squareSize = getMapSquareSize();

point3d.x += squareSize.x / 2;
point3d.z += squareSize.z / 2;

return point3d;
}

Point2d convertToMapCoordinate(Vector3d worldCoord) {
Point2d point2d = new Point2d();

Vector3d squareSize = getMapSquareSize();

point2d.x = (worldCoord.x + FLOOR_WIDTH) / squareSize.x;
point2d.y = (worldCoord.z + FLOOR_LENGTH) / squareSize.z;

return point2d;
}

public boolean isCollision(Transform3D t3d, boolean bViewSide) {
// get the translation
t3d.get(m_Translation);

// we need to scale up by the scale that was
// applied to the root TG on the view side of the scenegraph
if (bViewSide != false)
m_Translation.scale(1.0 / getScale());

Vector3d mapSquareSize = getMapSquareSize();

// first check that we are still inside the "world"
if (m_Translation.x < -FLOOR_WIDTH + mapSquareSize.x
|| m_Translation.x > FLOOR_WIDTH - mapSquareSize.x
|| m_Translation.y < -FLOOR_LENGTH + mapSquareSize.y
|| m_Translation.y > FLOOR_LENGTH - mapSquareSize.y)
return true;

if (bViewSide != false)
// then do a pixel based look up using the map
return isCollision(m_Translation);

return false;
}

// returns true if the given x,z location in the world corresponds to a wall
// section
protected boolean isCollision(Vector3d worldCoord) {
Point2d point = convertToMapCoordinate(worldCoord);
int nImageWidth = m_MapImage.getWidth();
int nImageHeight = m_MapImage.getHeight();

// outside of image
if (point.x < 0 || point.x >= nImageWidth || point.y < 0
|| point.y >= nImageHeight)
return true;

int color = m_MapImage.getRGB((int) point.x, (int) point.y);

// we can't walk through walls or bookcases
return (color == m_ColorWall || color == m_ColorBookcase);
}

public Group createMap(Group g) {
System.out.println("Creating map items");

Group mapGroup = new Group();
g.addChild(mapGroup);

Texture tex = new TextureLoader(m_szMapName, this).getTexture();
m_MapImage = ((ImageComponent2D) tex.getImage(0)).getImage();

float imageWidth = m_MapImage.getWidth();
float imageHeight = m_MapImage.getHeight();

FLOOR_WIDTH = imageWidth * 8;
FLOOR_LENGTH = imageHeight * 8;

for (int nPixelX = 1; nPixelX < imageWidth - 1; nPixelX++) {
for (int nPixelY = 1; nPixelY < imageWidth - 1; nPixelY++)
createMapItem(mapGroup, nPixelX, nPixelY);

float percentDone = 100 * (float) nPixelX
/ (float) (imageWidth - 2);
System.out.println(" " + (int) (percentDone) + "%");
}

createExternalWall(mapGroup);

return mapGroup;
}

void createMapItem(Group mapGroup, int nPixelX, int nPixelY) {
int color = m_MapImage.getRGB((int) nPixelX, (int) nPixelY);

if (color == m_ColorWall)
createWall(mapGroup, nPixelX, nPixelY);

else if (color == m_ColorGuard)
createGuard(mapGroup, nPixelX, nPixelY);

else if (color == m_ColorLight)
createLight(mapGroup, nPixelX, nPixelY);

else if (color == m_ColorBookcase)
createBookcase(mapGroup, nPixelX, nPixelY);

else if (color == m_ColorWater)
createWater(mapGroup, nPixelX, nPixelY);
}

Vector3d getMapSquareSize() {
if (m_MapSquareSize == null) {
double imageWidth = m_MapImage.getWidth();
double imageHeight = m_MapImage.getHeight();
m_MapSquareSize = new Vector3d(2 * FLOOR_WIDTH / imageWidth, 0, 2
* FLOOR_LENGTH / imageHeight);
}

return m_MapSquareSize;
}

void createWall(Group mapGroup, int nPixelX, int nPixelY) {
Point3d point = convertToWorldCoordinatesPixelCenter(nPixelX, nPixelY);

if (m_WallAppearance == null)
m_WallAppearance = new Appearance();

Vector3d squareSize = getMapSquareSize();

Cuboid wall = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY
| ComplexObject.TEXTURE);
wall
.createObject(m_WallAppearance, new Vector3d(point.x,
m_kFloorLevel, point.z), new Vector3d(squareSize.x / 2,
m_kCeilingHeight / 2, squareSize.z / 2), "marmo.jpg",
null, null);
}

void createExternalWall(Group mapGroup) {
Vector3d squareSize = getMapSquareSize();

Appearance app = new Appearance();
app.setColoringAttributes(new ColoringAttributes(new Color3f(
132f / 255f, 0, 66f / 255f), ColoringAttributes.FASTEST));

int imageWidth = m_MapImage.getWidth();
int imageHeight = m_MapImage.getHeight();

Point3d topLeft = convertToWorldCoordinatesPixelCenter(0, 0);
Point3d bottomRight = convertToWorldCoordinatesPixelCenter(
imageWidth - 1, imageHeight - 1);

// top
Cuboid wall = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY);
wall.createObject(app, new Vector3d(0, m_kFloorLevel, topLeft.z),
new Vector3d(squareSize.x * imageWidth / 2,
m_kCeilingHeight / 2, squareSize.z / 2), null, null,
null);

// bottom
wall = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY);
wall.createObject(app, new Vector3d(0, m_kFloorLevel, bottomRight.z),
new Vector3d(squareSize.x * imageWidth / 2,
m_kCeilingHeight / 2, squareSize.z / 2), null, null,
null);

// left
wall = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY);
wall.createObject(app, new Vector3d(topLeft.x, m_kFloorLevel, 0),
new Vector3d(squareSize.x / 2, m_kCeilingHeight / 2,
squareSize.z * imageHeight / 2), null, null, null);

// right
wall = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY);
wall.createObject(app, new Vector3d(bottomRight.x, m_kFloorLevel, 0),
new Vector3d(squareSize.x / 2, m_kCeilingHeight / 2,
squareSize.z * imageHeight / 2), null, null, null);
}

void createGuard(Group mapGroup, int nPixelX, int nPixelY) {
Point3d point = convertToWorldCoordinatesPixelCenter(nPixelX, nPixelY);

if (m_GuardAppearance == null)
m_GuardAppearance = new Appearance();

Vector3d squareSize = getMapSquareSize();

Guard guard = new Guard(this, mapGroup, ComplexObject.GEOMETRY, this);
guard.createObject(m_GuardAppearance, new Vector3d(point.x,
(m_kFloorLevel + m_kCeilingLevel) / 2, point.z), new Vector3d(
1, 1, 1), null, null, null);
}

void createLight(Group mapGroup, int nPixelX, int nPixelY) {
Point3d point = convertToWorldCoordinatesPixelCenter(nPixelX, nPixelY);

// we do not share an Appearance for lights
// or they all animate in synch...
final double lightHeight = m_kCeilingHeight / 1.5;

Light light = new Light(this, mapGroup, ComplexObject.GEOMETRY
| ComplexObject.TEXTURE);
light.createObject(new Appearance(), new Vector3d(point.x,
m_kFloorLevel + lightHeight / 2, point.z), new Vector3d(5,
lightHeight, 5), "light.gif", null, null);
}

void createWater(Group mapGroup, int nPixelX, int nPixelY) {
Point3d point = convertToWorldCoordinatesPixelCenter(nPixelX, nPixelY);

if (m_WaterAppearance == null) {
m_WaterAppearance = new Appearance();
m_WaterAppearance.setPolygonAttributes(new PolygonAttributes(
PolygonAttributes.POLYGON_FILL,
PolygonAttributes.CULL_NONE, 0, false));
m_WaterAppearance
.setTransparencyAttributes(new TransparencyAttributes(
TransparencyAttributes.BLENDED, 1.0f));
m_WaterAppearance.setTextureAttributes(new TextureAttributes(
TextureAttributes.REPLACE, new Transform3D(), new Color4f(
0, 0, 0, 1), TextureAttributes.FASTEST));

}

Land water = new Land(this, mapGroup, ComplexObject.GEOMETRY
| ComplexObject.TEXTURE);
water.createObject(m_WaterAppearance, new Vector3d(point.x,
m_kFloorLevel + 0.1, point.z), new Vector3d(40, 1, 40),
"water.gif", null, null);
}

void createBookcase(Group mapGroup, int nPixelX, int nPixelY) {
Point3d point = convertToWorldCoordinatesPixelCenter(nPixelX, nPixelY);

if (m_BookcaseAppearance == null)
m_BookcaseAppearance = new Appearance();

Vector3d squareSize = getMapSquareSize();

Cuboid bookcase = new Cuboid(this, mapGroup, ComplexObject.GEOMETRY
| ComplexObject.TEXTURE);
bookcase.createObject(m_BookcaseAppearance, new Vector3d(point.x,
m_kFloorLevel, point.z), new Vector3d(squareSize.x / 2,
m_kCeilingHeight / 2.7, squareSize.z / 2), "bookcase.gif",
null, null);

}

public static void main(String[] args) {
KeyNavigateTest keyTest = new KeyNavigateTest();
keyTest.saveCommandLineArguments(args);

new MainFrame(keyTest, m_kWidth, m_kHeight);
}
}

/*******************************************************************************
* Copyright (C) 2001 Daniel Selman
*
* First distributed with the book "Java 3D Programming" by Daniel Selman and
* published by Manning Publications. http://manning.com/selman
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* The license can be found on the WWW at: http://www.fsf.org/copyleft/gpl.html
*
* Or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA.
*
* Authors can be contacted at: Daniel Selman: daniel@selman.orgThis e-mail address is being protected from spam bots, you need JavaScript enabled to view it
*
* If you make changes you think others would like, please contact one of the
* authors or someone at the www.j3d.org web site.
******************************************************************************/

//*****************************************************************************
/**
* Java3dApplet
*
* Base class for defining a Java 3D applet. Contains some useful methods for
* defining views and scenegraphs etc.
*
* @author Daniel Selman
* @version 1.0
*/
//*****************************************************************************

abstract class Java3dApplet extends Applet {
public static int m_kWidth = 300;

public static int m_kHeight = 300;

protected String[] m_szCommandLineArray = null;

protected VirtualUniverse m_Universe = null;

protected BranchGroup m_SceneBranchGroup = null;

protected Bounds m_ApplicationBounds = null;

// protected com.tornadolabs.j3dtree.Java3dTree m_Java3dTree = null;

public Java3dApplet() {
}

public boolean isApplet() {
try {
System.getProperty("user.dir");
System.out.println("Running as Application.");
return false;
} catch (Exception e) {
}

System.out.println("Running as Applet.");
return true;
}

public URL getWorkingDirectory() throws java.net.MalformedURLException {
URL url = null;

try {
File file = new File(System.getProperty("user.dir"));
System.out.println("Running as Application:");
System.out.println(" " + file.toURL());
return file.toURL();
} catch (Exception e) {
}

System.out.println("Running as Applet:");
System.out.println(" " + getCodeBase());

return getCodeBase();
}

public VirtualUniverse getVirtualUniverse() {
return m_Universe;
}

//public com.tornadolabs.j3dtree.Java3dTree getJ3dTree() {
//return m_Java3dTree;
// }

public Locale getFirstLocale() {
java.util.Enumeration e = m_Universe.getAllLocales();

if (e.hasMoreElements() != false)
return (Locale) e.nextElement();

return null;
}

protected Bounds getApplicationBounds() {
if (m_ApplicationBounds == null)
m_ApplicationBounds = createApplicationBounds();

return m_ApplicationBounds;
}

protected Bounds createApplicationBounds() {
m_ApplicationBounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
100.0);
return m_ApplicationBounds;
}

protected Background createBackground() {
Background back = new Background(new Color3f(0.9f, 0.9f, 0.9f));
back.setApplicationBounds(createApplicationBounds());
return back;
}

public void initJava3d() {
// m_Java3dTree = new com.tornadolabs.j3dtree.Java3dTree();
m_Universe = createVirtualUniverse();

Locale locale = createLocale(m_Universe);

BranchGroup sceneBranchGroup = createSceneBranchGroup();

ViewPlatform vp = createViewPlatform();
BranchGroup viewBranchGroup = createViewBranchGroup(
getViewTransformGroupArray(), vp);

createView(vp);

Background background = createBackground();

if (background != null)
sceneBranchGroup.addChild(background);

// m_Java3dTree.recursiveApplyCapability(sceneBranchGroup);
// m_Java3dTree.recursiveApplyCapability(viewBranchGroup);

locale.addBranchGraph(sceneBranchGroup);
addViewBranchGroup(locale, viewBranchGroup);

onDoneInit();
}

protected void onDoneInit() {
// m_Java3dTree.updateNodes(m_Universe);
}

protected double getScale() {
return 1.0;
}

public TransformGroup[] getViewTransformGroupArray() {
TransformGroup[] tgArray = new TransformGroup[1];
tgArray[0] = new TransformGroup();

// move the camera BACK a little...
// note that we have to invert the matrix as
// we are moving the viewer
Transform3D t3d = new Transform3D();
t3d.setScale(getScale());
t3d.setTranslation(new Vector3d(0.0, 0.0, -20.0));
t3d.invert();
tgArray[0].setTransform(t3d);

return tgArray;
}

protected void addViewBranchGroup(Locale locale, BranchGroup bg) {
locale.addBranchGraph(bg);
}

protected Locale createLocale(VirtualUniverse u) {
return new Locale(u);
}

protected BranchGroup createSceneBranchGroup() {
m_SceneBranchGroup = new BranchGroup();
return m_SceneBranchGroup;
}

protected View createView(ViewPlatform vp) {
View view = new View();

PhysicalBody pb = createPhysicalBody();
PhysicalEnvironment pe = createPhysicalEnvironment();

AudioDevice audioDevice = createAudioDevice(pe);

if (audioDevice != null) {
pe.setAudioDevice(audioDevice);
audioDevice.initialize();
}

view.setPhysicalEnvironment(pe);
view.setPhysicalBody(pb);

if (vp != null)
view.attachViewPlatform(vp);

view.setBackClipDistance(getBackClipDistance());
view.setFrontClipDistance(getFrontClipDistance());

Canvas3D c3d = createCanvas3D();
view.addCanvas3D(c3d);
addCanvas3D(c3d);

return view;
}

protected PhysicalBody createPhysicalBody() {
return new PhysicalBody();
}

protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);

if (javaSoundMixer == null)
System.out.println("create of audiodevice failed");

return javaSoundMixer;
}

protected PhysicalEnvironment createPhysicalEnvironment() {
return new PhysicalEnvironment();
}

protected float getViewPlatformActivationRadius() {
return 100;
}

protected ViewPlatform createViewPlatform() {
ViewPlatform vp = new ViewPlatform();
vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
vp.setActivationRadius(getViewPlatformActivationRadius());

return vp;
}

protected Canvas3D createCanvas3D() {
GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getScreenDevices();

Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));

return c3d;
}

protected int getCanvas3dWidth(Canvas3D c3d) {
return m_kWidth;
}

protected int getCanvas3dHeight(Canvas3D c3d) {
return m_kHeight;
}

protected double getBackClipDistance() {
return 100.0;
}

protected double getFrontClipDistance() {
return 1.0;
}

protected BranchGroup createViewBranchGroup(TransformGroup[] tgArray,
ViewPlatform vp) {
BranchGroup vpBranchGroup = new BranchGroup();

if (tgArray != null && tgArray.length > 0) {
Group parentGroup = vpBranchGroup;
TransformGroup curTg = null;

for (int n = 0; n < tgArray.length; n++) {
curTg = tgArray[n];
parentGroup.addChild(curTg);
parentGroup = curTg;
}

tgArray[tgArray.length - 1].addChild(vp);
} else
vpBranchGroup.addChild(vp);

return vpBranchGroup;
}

protected void addCanvas3D(Canvas3D c3d) {
setLayout(new BorderLayout());
add(c3d, BorderLayout.CENTER);
doLayout();
}

protected VirtualUniverse createVirtualUniverse() {
return new VirtualUniverse();
}

protected void saveCommandLineArguments(String[] szArgs) {
m_szCommandLineArray = szArgs;
}

protected String[] getCommandLineArguments() {
return m_szCommandLineArray;
}
}

class KeyCollisionBehavior extends KeyBehavior {
private CollisionChecker m_CollisionChecker = null;

public KeyCollisionBehavior(TransformGroup tg,
CollisionDetector collisionDetector) {
super(tg);

m_CollisionChecker = new CollisionChecker(tg, collisionDetector, true);
}

protected void updateTransform() {
if (m_CollisionChecker.isCollision(transform3D) == false)
transformGroup.setTransform(transform3D);
}

// dissallow rotation up or down
protected void altMove(int keycode) {
}

// dissallow moving up or down
protected void controlMove(int keycode) {
}
}

class Guard extends ComplexObject {
private CollisionDetector m_CollisionDetector = null;

public Guard(Component comp, Group g, int nFlags, CollisionDetector detector) {
super(comp, g, nFlags);

m_CollisionDetector = detector;
}

protected Group createGeometryGroup(Appearance app, Vector3d position,
Vector3d scale, String szTextureFile, String szSoundFile) {
TransformGroup tg = new TransformGroup();
tg.addChild(new Cone(5, 30));

attachBehavior(new RandomWalkBehavior(getBehaviorTransformGroup(),
m_CollisionDetector));

return tg;
}
}

interface CollisionDetector {
public boolean isCollision(Transform3D t3d, boolean bViewSide);
}

class CollisionChecker {
CollisionDetector m_Detector = null;

Transform3D m_ToWorld = null;

Transform3D m_Transform3D = null;

Node m_Node = null;

boolean m_bViewSide = false;

public CollisionChecker(Node node, CollisionDetector detector,
boolean bViewSide) {
m_Detector = detector;
m_Node = node;
m_bViewSide = bViewSide;
}

public boolean isCollision(Transform3D t3d) {
return m_Detector.isCollision(t3d, m_bViewSide);
}
}

class Light extends ComplexObject {
private TextureAttributes m_TextureAttributes = null;

public Light(Component comp, Group g, int nFlags) {
super(comp, g, nFlags);
}

protected Group createGeometryGroup(Appearance app, Vector3d position,
Vector3d scale, String szTextureFile, String szSoundFile) {
Group g = new Group();

app.setPolygonAttributes(new PolygonAttributes(
PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0,
false));
app.setTransparencyAttributes(new TransparencyAttributes(
TransparencyAttributes.BLENDED, 1.0f));

m_TextureAttributes = new TextureAttributes(TextureAttributes.REPLACE,
new Transform3D(), new Color4f(0, 0, 0, 1),
TextureAttributes.FASTEST);
app.setTextureAttributes(m_TextureAttributes);

if ((m_nFlags & ComplexObject.TEXTURE) == ComplexObject.TEXTURE)
setTexture(app, szTextureFile);

Cone cone = new Cone(1, 1, Primitive.GENERATE_TEXTURE_COORDS, app);

g.addChild(cone);

attachBehavior(new TextureAnimationBehavior(m_TextureAttributes));

return g;
}
}

class TextureAnimationBehavior extends Behavior {
// the wake up condition for the behavior
protected WakeupCondition m_WakeupCondition = null;

protected Transform3D m_Transform3D = null;

protected TextureAttributes m_TextureAttributes = null;

protected double rotY = 0;

public TextureAnimationBehavior(TextureAttributes texAttribs) {
m_TextureAttributes = texAttribs;
m_Transform3D = new Transform3D();
m_TextureAttributes
.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);

// create the WakeupCriterion for the behavior
WakeupCriterion criterionArray[] = new WakeupCriterion[1];
criterionArray[0] = new WakeupOnElapsedTime(300);

// save the WakeupCriterion for the behavior
m_WakeupCondition = new WakeupOr(criterionArray);
}

public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_WakeupCondition);
}

public void processStimulus(java.util.Enumeration criteria) {
while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();

if (wakeUp instanceof WakeupOnElapsedTime) {
rotY += Utils.getRandomNumber(0.01, 0.01);
m_Transform3D.rotY(rotY);
m_TextureAttributes.setTextureTransform(m_Transform3D);
}
}

// assign the next WakeUpCondition, so we are notified again
wakeupOn(m_WakeupCondition);
}
}

// this class implements a simple behavior that
// calculates and prints the size of an object
// based on the vertices in its GeometryArray

class RandomWalkBehavior extends Behavior {
// the wake up condition for the behavior
protected WakeupCondition m_WakeupCondition = null;

protected TransformGroup m_TransformGroup = null;

protected Transform3D m_Transform3D = null;

protected Vector3d TargetVector3d = null;

protected Vector3d CurrentVector3d = null;

private final double m_MovementX = 2;

private final double m_MovementY = 0;

private final double m_MovementZ = 2;

private int m_nFrameCount = 0;

private CollisionChecker m_CollisionChecker = null;

public RandomWalkBehavior(TransformGroup tg, CollisionDetector detector) {
m_TransformGroup = tg;

m_CollisionChecker = new CollisionChecker(tg, detector, false);

m_Transform3D = new Transform3D();

TargetVector3d = new Vector3d();
CurrentVector3d = new Vector3d();

// create the WakeupCriterion for the behavior
WakeupCriterion criterionArray[] = new WakeupCriterion[1];
criterionArray[0] = new WakeupOnElapsedTime(100);

// save the WakeupCriterion for the behavior
m_WakeupCondition = new WakeupOr(criterionArray);
}

public void initialize() {
// apply the initial WakeupCriterion
wakeupOn(m_WakeupCondition);
}

public void processStimulus(java.util.Enumeration criteria) {
while (criteria.hasMoreElements()) {
WakeupCriterion wakeUp = (WakeupCriterion) criteria.nextElement();

if (wakeUp instanceof WakeupOnElapsedTime) {
if (m_nFrameCount % 100 == 0) {
// generate a random direction for movement
TargetVector3d.x = m_MovementX
* Utils.getRandomNumber(0, 1);
TargetVector3d.y = m_MovementY
* Utils.getRandomNumber(0, 1);
TargetVector3d.z = m_MovementZ
* Utils.getRandomNumber(0, 1);
}

CurrentVector3d.x += TargetVector3d.x
* Utils.getRandomNumber(1, 0.1);
CurrentVector3d.y += TargetVector3d.y
* Utils.getRandomNumber(1, 0.1);
CurrentVector3d.z += TargetVector3d.z
* Utils.getRandomNumber(1, 0.1);

m_Transform3D.setTranslation(CurrentVector3d);

if (m_CollisionChecker.isCollision(m_Transform3D) == false)
m_TransformGroup.setTransform(m_Transform3D);

m_nFrameCount++;
}
}

// assign the next WakeUpCondition, so we are notified again
wakeupOn(m_WakeupCondition);
}
}

abstract class ComplexObject extends BranchGroup {
protected Group m_ParentGroup = null;

protected int m_nFlags = 0;

protected BackgroundSound m_CollideSound = null;

protected Component m_Component = null;

protected TransformGroup m_TransformGroup = null;

protected TransformGroup m_BehaviorTransformGroup = null;

public static final int SOUND = 0x001;

public static final int GEOMETRY = 0x002;

public static final int TEXTURE = 0x004;

public static final int COLLISION = 0x008;

public static final int COLLISION_SOUND = 0x010;

public ComplexObject(Component comp, Group group, int nFlags) {
m_ParentGroup = group;
m_nFlags = nFlags;
m_Component = comp;
}

public Bounds getGeometryBounds() {
return new BoundingSphere(new Point3d(0, 0, 0), 100);
}

private MediaContainer loadSoundFile(String szFile) {
try {
File file = new File(System.getProperty("user.dir"));
URL url = file.toURL();

URL soundUrl = new URL(url, szFile);
return new MediaContainer(soundUrl);
} catch (Exception e) {
System.err.println("Error could not load sound file: " + e);
System.exit(-1);
}

return null;
}

protected void setTexture(Appearance app, String szFile) {
Texture tex = new TextureLoader(szFile, m_Component).getTexture();
app.setTexture(tex);
}

abstract protected Group createGeometryGroup(Appearance app,
Vector3d position, Vector3d scale, String szTextureFile,
String szSoundFile);

protected Group loadGeometryGroup(String szModel, Appearance app)
throws java.io.FileNotFoundException {
// load the object file
Scene scene = null;
Shape3D shape = null;

// read in the geometry information from the data file
ObjectFile objFileloader = new ObjectFile(ObjectFile.RESIZE);

scene = objFileloader.load(szModel);

// retrieve the Shape3D object from the scene
BranchGroup branchGroup = scene.getSceneGroup();
shape = (Shape3D) branchGroup.getChild(0);
shape.setAppearance(app);

return branchGroup;
}

protected int getSoundLoop(boolean bCollide) {
return 1;
}

protected float getSoundPriority(boolean bCollide) {
return 1.0f;
}

protected float getSoundInitialGain(boolean bCollide) {
return 1.0f;
}

protected boolean getSoundInitialEnable(boolean bCollide) {
return true;
}

protected boolean getSoundContinuousEnable(boolean bCollide) {
return false;
}

protected Bounds getSoundSchedulingBounds(boolean bCollide) {
return new BoundingSphere(new Point3d(0, 0, 0), 1.0);
}

protected boolean getSoundReleaseEnable(boolean bCollide) {
return true;
}

protected Point2f[] getSoundDistanceGain(boolean bCollide) {
return null;
}

protected void setSoundAttributes(Sound sound, boolean bCollide) {
sound.setCapability(Sound.ALLOW_ENABLE_WRITE);
sound.setCapability(Sound.ALLOW_ENABLE_READ);

sound.setSchedulingBounds(getSoundSchedulingBounds(bCollide));
sound.setEnable(getSoundInitialEnable(bCollide));
sound.setLoop(getSoundLoop(bCollide));
sound.setPriority(getSoundPriority(bCollide));
sound.setInitialGain(getSoundInitialGain(bCollide));

sound.setContinuousEnable(getSoundContinuousEnable(bCollide));
sound.setReleaseEnable(bCollide);

if (sound instanceof PointSound) {
PointSound pointSound = (PointSound) sound;
pointSound.setInitialGain(getSoundInitialGain(bCollide));

Point2f[] gainArray = getSoundDistanceGain(bCollide);

if (gainArray != null)
pointSound.setDistanceGain(gainArray);
}
}

public Group createObject(Appearance app, Vector3d position,
Vector3d scale, String szTextureFile, String szSoundFile,
String szCollisionSound) {
m_TransformGroup = new TransformGroup();
Transform3D t3d = new Transform3D();

t3d.setScale(scale);
t3d.setTranslation(position);

m_TransformGroup.setTransform(t3d);

m_BehaviorTransformGroup = new TransformGroup();

if ((m_nFlags & GEOMETRY) == GEOMETRY)
m_BehaviorTransformGroup.addChild(createGeometryGroup(app,
position, scale, szTextureFile, szSoundFile));

if ((m_nFlags & SOUND) == SOUND) {
MediaContainer media = loadSoundFile(szSoundFile);
PointSound pointSound = new PointSound(media,
getSoundInitialGain(false), 0, 0, 0);
setSoundAttributes(pointSound, false);
m_BehaviorTransformGroup.addChild(pointSound);
}

if ((m_nFlags & COLLISION) == COLLISION) {
m_BehaviorTransformGroup
.setCapability(Node.ENABLE_COLLISION_REPORTING);
m_BehaviorTransformGroup.setCollidable(true);
m_BehaviorTransformGroup.setCollisionBounds(getGeometryBounds());

if ((m_nFlags & COLLISION_SOUND) == COLLISION_SOUND) {
MediaContainer collideMedia = loadSoundFile(szCollisionSound);

m_CollideSound = new BackgroundSound(collideMedia, 1);
setSoundAttributes(m_CollideSound, true);
m_TransformGroup.addChild(m_CollideSound);
}

CollisionBehavior collision = new CollisionBehavior(
m_BehaviorTransformGroup, this);
collision.setSchedulingBounds(getGeometryBounds());

m_BehaviorTransformGroup.addChild(collision);
}

m_TransformGroup.addChild(m_BehaviorTransformGroup);
m_ParentGroup.addChild(m_TransformGroup);

return m_BehaviorTransformGroup;
}

public void onCollide(boolean bCollide) {
System.out.println("Collide: " + bCollide);

if (m_CollideSound != null && bCollide == true)
m_CollideSound.setEnable(true);
}

public void attachBehavior(Behavior beh) {
m_BehaviorTransformGroup
.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
beh.setSchedulingBounds(getGeometryBounds());
m_BehaviorTransformGroup.addChild(beh);
}

public TransformGroup getBehaviorTransformGroup() {
return m_BehaviorTransformGroup;
}

public void attachSplinePathInterpolator(Alpha alpha, Transform3D axis,
URL urlKeyframes) {
// read a spline path definition file and
// add a Spline Path Interpolator to the TransformGroup for the object.

m_BehaviorTransformGroup
.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

RotPosScaleTCBSplinePathInterpolator splineInterpolator = Utils
.createSplinePathInterpolator(alpha, m_BehaviorTransformGroup,
axis, urlKeyframes);

if (splineInterpolator != null) {
splineInterpolator.setSchedulingBounds(getGeometryBounds());
m_BehaviorTransformGroup.addChild(splineInterpolator);
} else {
System.out.println("attachSplinePathInterpolator failed for: "
+ urlKeyframes);
}
}
}

class KeyBehavior extends Behavior {
protected static final double FAST_SPEED = 20.0;

protected static final double NORMAL_SPEED = 1.0;

protected static final double SLOW_SPEED = 0.5;

protected TransformGroup transformGroup;

protected Transform3D transform3D;

protected WakeupCondition keyCriterion;

private final static double TWO_PI = (2.0 * Math.PI);

private double rotateXAmount = Math.PI / 16.0;

private double rotateYAmount = Math.PI / 16.0;

private double rotateZAmount = Math.PI / 16.0;

private double moveRate = 5;

private double speed = NORMAL_SPEED;

private final double kMoveForwardScale = 1.1;

private final double kMoveBackwardScale = 0.9;

private int forwardKey = KeyEvent.VK_UP;

private int backKey = KeyEvent.VK_DOWN;

private int leftKey = KeyEvent.VK_LEFT;

private int rightKey = KeyEvent.VK_RIGHT;

public KeyBehavior(TransformGroup tg) {
super();

transformGroup = tg;
transform3D = new Transform3D();
}

public void initialize() {
WakeupCriterion[] keyEvents = new WakeupCriterion[2];
keyEvents[0] = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
keyEvents[1] = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED);
keyCriterion = new WakeupOr(keyEvents);

wakeupOn(keyCriterion);
}

public void processStimulus(Enumeration criteria) {
WakeupCriterion wakeup;
AWTEvent[] event;

while (criteria.hasMoreElements()) {
wakeup = (WakeupCriterion) criteria.nextElement();

if (!(wakeup instanceof WakeupOnAWTEvent))
continue;

event = ((WakeupOnAWTEvent) wakeup).getAWTEvent();

for (int i = 0; i < event.length; i++) {
if (event[i].getID() == KeyEvent.KEY_PRESSED) {
processKeyEvent((KeyEvent) event[i]);
}
}
}

wakeupOn(keyCriterion);
}

protected void processKeyEvent(KeyEvent event) {
int keycode = event.getKeyCode();

if (event.isShiftDown())
speed = FAST_SPEED;
else
speed = NORMAL_SPEED;

if (event.isAltDown())
altMove(keycode);
else if (event.isControlDown())
controlMove(keycode);
else
standardMove(keycode);
}

//moves forward backward or rotates left right
private void standardMove(int keycode) {
if (keycode == forwardKey)
moveForward();
else if (keycode == backKey)
moveBackward();
else if (keycode == leftKey)
rotLeft();
else if (keycode == rightKey)
rotRight();
}

//moves left right, rotate up down
protected void altMove(int keycode) {
if (keycode == forwardKey)
rotUp();
else if (keycode == backKey)
rotDown();
else if (keycode == leftKey)
rotLeft();
else if (keycode == rightKey)
rotRight();
else if (keycode == leftKey)
moveLeft();
else if (keycode == rightKey)
moveRight();
}

//move up down, rot left right
protected void controlMove(int keycode) {
if (keycode == forwardKey)
moveUp();
else if (keycode == backKey)
moveDown();
else if (keycode == leftKey)
rollLeft();
else if (keycode == rightKey)
rollRight();
}

private void moveForward() {
doMove(new Vector3d(0.0, 0.0, kMoveForwardScale * speed));
}

private void moveBackward() {
doMove(new Vector3d(0.0, 0.0, -kMoveBackwardScale * speed));
}

private void moveLeft() {
doMove(new Vector3d(-getMovementRate(), 0.0, 0.0));
}

private void moveRight() {
doMove(new Vector3d(getMovementRate(), 0.0, 0.0));
}

private void moveUp() {
doMove(new Vector3d(0.0, getMovementRate(), 0.0));
}

private void moveDown() {
doMove(new Vector3d(0.0, -getMovementRate(), 0.0));
}

protected void rotRight() {
doRotateY(getRotateRightAmount());
}

protected void rotUp() {
doRotateX(getRotateUpAmount());
}

protected void rotLeft() {
doRotateY(getRotateLeftAmount());
}

protected void rotDown() {
doRotateX(getRotateDownAmount());
}

protected void rollLeft() {
doRotateZ(getRollLeftAmount());
}

protected void rollRight() {
doRotateZ(getRollRightAmount());
}

protected void updateTransform() {
transformGroup.setTransform(transform3D);
}

protected void doRotateY(double radians) {
transformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.rotY(radians);
transform3D.mul(toMove);
updateTransform();
}

protected void doRotateX(double radians) {
transformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.rotX(radians);
transform3D.mul(toMove);
updateTransform();
}

protected void doRotateZ(double radians) {
transformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.rotZ(radians);
transform3D.mul(toMove);
updateTransform();
}

protected void doMove(Vector3d theMove) {
transformGroup.getTransform(transform3D);
Transform3D toMove = new Transform3D();
toMove.setTranslation(theMove);
transform3D.mul(toMove);
updateTransform();
}

protected double getMovementRate() {
return moveRate * speed;
}

protected double getRollLeftAmount() {
return rotateZAmount * speed;
}

protected double getRollRightAmount() {
return -rotateZAmount * speed;
}

protected double getRotateUpAmount() {
return rotateYAmount * speed;
}

protected double getRotateDownAmount() {
return -rotateYAmount * speed;
}

protected double getRotateLeftAmount() {
return rotateYAmount * speed;
}

protected double getRotateRightAmount() {
return -rotateYAmount * speed;
}

public void setRotateXAmount(double radians) {
rotateXAmount = radians;
}

public void setRotateYAmount(double radians) {
rotateYAmount = radians;
}

public void setRotateZAmount(double radians) {
rotateZAmount = radians;
}

public void setMovementRate(double meters) {
moveRate = meters; // Travel rate in meters/frame
}

public void setForwardKey(int key) {
forwardKey = key;
}

public void setBackKey(int key) {
backKey = key;
}

public void setLeftKey(int key) {
leftKey = key;
}
}

//creates a 2x2x2 cuboid with its base at y=0

class Cuboid extends ComplexObject {
public Cuboid(Component comp, Group g, int nFlags) {
super(comp, g, nFlags);
}

protected Group createGeometryGroup(Appearance app, Vector3d position,
Vector3d scale, String szTextureFile, String szSoundFile) {
int nFlags = GeometryArray.COORDINATES | GeometryArray.NORMALS;

if ((m_nFlags & TEXTURE) == TEXTURE)
nFlags |= GeometryArray.TEXTURE_COORDINATE_2;

QuadArray quadArray = new QuadArray(24, nFlags);

quadArray.setCoordinates(0, verts, 0, 24);

for (int n = 0; n < 24; n++)
quadArray.setNormal(n, normals[n / 4]);

if ((m_nFlags & TEXTURE) == TEXTURE) {
quadArray.setTextureCoordinates(0, 0, tcoords, 0, 24);
setTexture(app, szTextureFile);
}

Shape3D shape = new Shape3D(quadArray, app);

BranchGroup bg = new BranchGroup();
bg.addChild(shape);
return bg;
}

private static final float[] verts = {
// front face
1.0f, 0.0f, 1.0f, 1.0f, 2.0f, 1.0f, -1.0f, 2.0f, 1.0f, -1.0f, 0.0f,
1.0f,
// back face
-1.0f, 0.0f, -1.0f, -1.0f, 2.0f, -1.0f, 1.0f, 2.0f, -1.0f, 1.0f,
0.0f, -1.0f,
// right face
1.0f, 0.0f, -1.0f, 1.0f, 2.0f, -1.0f, 1.0f, 2.0f, 1.0f, 1.0f, 0.0f,
1.0f,
// left face
-1.0f, 0.0f, 1.0f, -1.0f, 2.0f, 1.0f, -1.0f, 2.0f, -1.0f, -1.0f,
0.0f, -1.0f,
// top face
1.0f, 2.0f, 1.0f, 1.0f, 2.0f, -1.0f, -1.0f, 2.0f, -1.0f, -1.0f,
2.0f, 1.0f,
// bottom face
-1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f,
0.0f, 1.0f, };

private static final float[] tcoords = {
// front
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// back
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
//right
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// left
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// top
1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// bottom
0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f };

private static final Vector3f[] normals = { new Vector3f(0.0f, 0.0f, 1.0f), // front
// face
new Vector3f(0.0f, 0.0f, -1.0f), // back face
new Vector3f(1.0f, 0.0f, 0.0f), // right face
new Vector3f(-1.0f, 0.0f, 0.0f), // left face
new Vector3f(0.0f, 1.0f, 0.0f), // top face
new Vector3f(0.0f, -1.0f, 0.0f), // bottom face
};
}

//*****************************************************************************
/**
* Utils
*
* @author Daniel Selman
* @version 1.0
*/
//*****************************************************************************

class Utils {
// convert an angular rotation about an axis to a Quaternion
static Quat4f createQuaternionFromAxisAndAngle(Vector3d axis, double angle) {
double sin_a = Math.sin(angle / 2);
double cos_a = Math.cos(angle / 2);

// use a vector so we can call normalize
Vector4f q = new Vector4f();

q.x = (float) (axis.x * sin_a);
q.y = (float) (axis.y * sin_a);
q.z = (float) (axis.z * sin_a);
q.w = (float) cos_a;

// It is necessary to normalise the quaternion
// in case any values are very close to zero.
q.normalize();

// convert to a Quat4f and return
return new Quat4f(q);
}

// convert three rotations about the Euler axes to a Quaternion
static Quat4f createQuaternionFromEuler(double angleX, double angleY,
double angleZ) {
// simply call createQuaternionFromAxisAndAngle
// for each axis and multiply the results
Quat4f qx = createQuaternionFromAxisAndAngle(new Vector3d(1, 0, 0),angleX);
Quat4f qy = createQuaternionFromAxisAndAngle(new Vector3d(0, 1, 0),
angleY);
Quat4f qz = createQuaternionFromAxisAndAngle(new Vector3d(0, 0, 1),
angleZ);

// qx = qx * qy
qx.mul(qy);

// qx = qx * qz
qx.mul(qz);

return qx;
}

static public double getRandomNumber(double basis, double random) {
return basis + ((float) Math.random() * random * 2f) - (random);
}

static public double getRandomNumber(double basis, double random,
double scale) {
double value = basis + ((float) Math.random() * random * 2f) - (random);
return value * scale;
}

static public StringBuffer readFile(URL urlFile) {
/* allocate a temporary buffer to store the input file*/
StringBuffer szBufferData = new StringBuffer();
Vector keyFramesVector = new Vector();

try {
InputStream inputStream = urlFile.openStream();

int nChar = 0;

// read the entire file into the StringBuffer
while (true) {
nChar = inputStream.read();

/* if we have not hit the end of file
add the character to the StringBuffer
*/
if (nChar != -1)
szBufferData.append((char) nChar);
else
// EOF
break;
}

inputStream.close();
} catch (Exception e) {
System.err.println(e.toString());
return null;
}

return szBufferData;
}

static public RotPosScaleTCBSplinePathInterpolator createSplinePathInterpolator(
Alpha alpha, TransformGroup tg, Transform3D axis, URL urlKeyframes) {
TCBKeyFrame[] keyFrames = readKeyFrames(urlKeyframes);

if (keyFrames != null)
return new RotPosScaleTCBSplinePathInterpolator(alpha, tg, axis,
keyFrames);

return null;
}

static public TCBKeyFrame[] readKeyFrames(URL urlKeyframes) {
StringBuffer szBufferData = readFile(urlKeyframes);

if (szBufferData == null)
return null;

Vector keyFramesVector = new Vector();

// create a tokenizer to tokenize the input file at whitespace
java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
szBufferData.toString());

// each keyframe is defined as follows
// - knot (0 >= k <= 1)
// - position (x,y,z)
// - rotation (rx,ry,rz)
// - scale (x,y,z)

// - tension (-1 >= t <= 1)
// - continuity (-1 >= c <= 1)
// - bias (-1 >= b <= 1)
// - linear (int - 0 or 1)

while (true) {
try {
float knot = Float.parseFloat(tokenizer.nextToken());

float posX = Float.parseFloat(tokenizer.nextToken());
float posY = Float.parseFloat(tokenizer.nextToken());
float posZ = Float.parseFloat(tokenizer.nextToken());

float rotX = Float.parseFloat(tokenizer.nextToken());
float rotY = Float.parseFloat(tokenizer.nextToken());
float rotZ = Float.parseFloat(tokenizer.nextToken());

float scaleX = Float.parseFloat(tokenizer.nextToken());
float scaleY = Float.parseFloat(tokenizer.nextToken());
float scaleZ = Float.parseFloat(tokenizer.nextToken());

float tension = Float.parseFloat(tokenizer.nextToken());
float continuity = Float.parseFloat(tokenizer.nextToken());
float bias = Float.parseFloat(tokenizer.nextToken());

int linear = Integer.parseInt(tokenizer.nextToken());

TCBKeyFrame keyframe = new TCBKeyFrame(knot, linear,
new Point3f(posX, posY, posZ),
createQuaternionFromEuler(rotX, rotY, rotZ),
new Point3f(scaleX, scaleY, scaleZ), tension,
continuity, bias);

keyFramesVector.add(keyframe);
} catch (Exception e) {
break;
}
}

// create the return structure and populate
TCBKeyFrame[] keysReturn = new TCBKeyFrame[keyFramesVector.size()];

for (int n = 0; n < keysReturn.length; n++)
keysReturn[n] = (TCBKeyFrame) keyFramesVector.get(n);

// return the array
return keysReturn;
}
}

class Land extends ComplexObject {
public static final float WIDTH = 1.0f;

public static final float LENGTH = 1.0f;

public static final float HEIGHT = 0.0f;

public Land(Component comp, Group g, int nFlags) {
super(comp, g, nFlags);
}

protected Group createGeometryGroup(Appearance app, Vector3d position,
Vector3d scale, String szTextureFile, String szSoundFile) {
int nFlags = GeometryArray.COORDINATES | GeometryArray.NORMALS;

if ((m_nFlags & TEXTURE) == TEXTURE)
nFlags |= GeometryArray.TEXTURE_COORDINATE_2;

QuadArray quadArray = new QuadArray(4, nFlags);

float[] coordArray = { -WIDTH, HEIGHT, LENGTH, WIDTH, HEIGHT, LENGTH,
WIDTH, HEIGHT, -LENGTH, -WIDTH, HEIGHT, -LENGTH };

quadArray.setCoordinates(0, coordArray, 0, coordArray.length / 3);

for (int n = 0; n < coordArray.length / 3; n++)
quadArray.setNormal(n, new Vector3f(0, 1, 0));

if ((m_nFlags & TEXTURE) == TEXTURE) {
float[] texArray = { 0, 0, 1, 0, 1, 1, 0, 1 };

quadArray.setTextureCoordinates(0, 0, texArray, 0,
coordArray.length / 3);
setTexture(app, szTextureFile);
}

BranchGroup bg = new BranchGroup();
Shape3D shape = new Shape3D(quadArray, app);
bg.addChild(shape);

return bg;
}
}

/**
* This class is a simple behavior that invokes the KeyNavigator to modify the
* view platform transform.
*/

class CollisionBehavior extends Behavior {
private WakeupOnCollisionEntry wakeupOne = null;

private WakeupOnCollisionExit wakeupTwo = null;

private WakeupCriterion[] wakeupArray = new WakeupCriterion[2];

private WakeupCondition wakeupCondition = null;

private ComplexObject m_Owner = null;

public CollisionBehavior(Node node, ComplexObject owner) {
wakeupOne = new WakeupOnCollisionEntry(node,
WakeupOnCollisionEntry.USE_GEOMETRY);
wakeupTwo = new WakeupOnCollisionExit(node,
WakeupOnCollisionExit.USE_GEOMETRY);

wakeupArray[0] = wakeupOne;
wakeupArray[1] = wakeupTwo;

wakeupCondition = new WakeupOr(wakeupArray);

m_Owner = owner;
}

/**
* Override Behavior's initialize method to setup wakeup criteria.
*/
public void initialize() {
// Establish initial wakeup criteria
wakeupOn(wakeupCondition);
}

/**
* Override Behavior's stimulus method to handle the event.
*/
public void processStimulus(Enumeration criteria) {
WakeupCriterion genericEvt;

while (criteria.hasMoreElements()) {
genericEvt = (WakeupCriterion) criteria.nextElement();

if (genericEvt instanceof WakeupOnCollisionEntry) {
m_Owner.onCollide(true);
} else if (genericEvt instanceof WakeupOnCollisionExit) {
m_Owner.onCollide(false);
}
}

// Set wakeup criteria for next time
wakeupOn(wakeupCondition);
}
}

maro89
31-05-2010, 12:36
Consiglio questo breve articolo (http://www.acm.org/crossroads/xrds13-3/minueto.html) a tutti coloro che per vari motivi si trovano a programmare applicazioni/giochi in 2D in Java per cui la questione delle performance è importante.

Molto utile come punto di inizio per imparare a conoscere le strategie di base da utilizzare in merito. Ulteriori ricerche possono essere approfondite consultando il materiale citato (come il blog di Chet Haase).

Ciao :)

hanno tolto l'articolo =( giusto ora che mi serviva per capire come fare il progetto per l'esame di informatica b.

c'è qualcuno che mi può consigliare un articolo simile?

banryu79
31-05-2010, 14:28
hanno tolto l'articolo =( giusto ora che mi serviva per capire come fare il progetto per l'esame di informatica b.

c'è qualcuno che mi può consigliare un articolo simile?
Già, sembra che la sezione dedicata al Software Engeneering Lab della McGill abbia tirato le cuoia. Ergo l'articolo è diventato assimilabile al vaporware :D

In compenso le pagine del progetto Minueto sono ancora raggiungibili (http://minueto.cs.mcgill.ca/index.html#news) e questo piccolo framework è distribuito completo di sorgenti, quindi puoi consultarlo.

Peccato però, perchè l'articolo aveva una fruibilità immediata essendo ovviamente discorsivo e mirato a pochi punti fondamentali, ben delineati.
Comunque spunti vari sull grafica in Java2D li puoi trovare anche ai link successivi nella discussione... in ogni ti posto qua sotto "un po' di roba" che potrebbe interessarti:
- Blog di Chet Haase su java.net: topic Games (http://www.java.net/blogs/topic/51/15829)
(Intermidiate Images è vecchiotto 2004 ma sempre valido)
(darei un occhio anche a tutte le sue altre entry nel blog che trattano estensivamente della API per le immagini, BufferedImages, VolatileImage, ecc..)
- Poi, partendo da quest'altra entry (http://weblogs.java.net/blog/2004/10/06/java-game-development-jdj-article-and-code) del blog si arriva a questo (https://ping.dev.java.net/?redirect=SSL): si può scaricare il file Ping.jar e spulciare i sorgenti, su cui meditare.
- Altra risorsa specifica anche se vasta, è il forum JavaGaming.org (http://www.javagaming.org//); la sezione Tutorial potrebbe avere qualcosa di utile.
- Dal sito della Sun (... Oracle, uffa) nella sezione Java Desktop (anche qua, tanta roba) si possono trovare approfondimenti su diversi aspetti; ad esempio un paper intitolato "Graphics Performance Improvements (http://java.sun.com/products/java-media/2D/perf_graphics.html)" oppure un pdf che entra nel merito delle VolatileImages (http://java.sun.com/j2se/1.4/pdf/VolatileImage.pdf).

maro89
31-05-2010, 20:53
Già, sembra che la sezione dedicata al Software Engeneering Lab della McGill abbia tirato le cuoia. Ergo l'articolo è diventato assimilabile al vaporware :D

In compenso le pagine del progetto Minueto sono ancora raggiungibili (http://minueto.cs.mcgill.ca/index.html#news) e questo piccolo framework è distribuito completo di sorgenti, quindi puoi consultarlo.

Peccato però, perchè l'articolo aveva una fruibilità immediata essendo ovviamente discorsivo e mirato a pochi punti fondamentali, ben delineati.
Comunque spunti vari sull grafica in Java2D li puoi trovare anche ai link successivi nella discussione... in ogni ti posto qua sotto "un po' di roba" che potrebbe interessarti:
- Blog di Chet Haase su java.net: topic Games (http://www.java.net/blogs/topic/51/15829)
(Intermidiate Images è vecchiotto 2004 ma sempre valido)
(darei un occhio anche a tutte le sue altre entry nel blog che trattano estensivamente della API per le immagini, BufferedImages, VolatileImage, ecc..)
- Poi, partendo da quest'altra entry (http://weblogs.java.net/blog/2004/10/06/java-game-development-jdj-article-and-code) del blog si arriva a questo (https://ping.dev.java.net/?redirect=SSL): si può scaricare il file Ping.jar e spulciare i sorgenti, su cui meditare.
- Altra risorsa specifica anche se vasta, è il forum JavaGaming.org (http://www.javagaming.org//); la sezione Tutorial potrebbe avere qualcosa di utile.
- Dal sito della Sun (... Oracle, uffa) nella sezione Java Desktop (anche qua, tanta roba) si possono trovare approfondimenti su diversi aspetti; ad esempio un paper intitolato "Graphics Performance Improvements (http://java.sun.com/products/java-media/2D/perf_graphics.html)" oppure un pdf che entra nel merito delle VolatileImages (http://java.sun.com/j2se/1.4/pdf/VolatileImage.pdf).


grazie mille, mi sei stato davvero utile!
ora cosi ho delle linee guida e non devo partire da zero cambiando centinai di volte il codice.