PDA

View Full Version : [JAVA3D] collisioni con vari behavor


franksisca
12-01-2010, 17:46
sto completamendo impazzendo -.-

oramai credo di avere l'ultimo neurone nascosto da qualche parte...che non vuole essere trovato!!!

non riesco nemmeno più a gestire la collisione semplice, sono completamente in palla.

detto ciò, e visto che mi fermo altrimenti SCASSO TUTTO...il mio problema è questo:

usando il keynavigator "originale" ho l'effetto "scivolo" che non mi piace, e inoltre non riesco a gestire le collisioni.

se creo io un key navigator mi và a scatti, non riesco a premere 2 direzioni contemporaneamente però riesco a farli "sbattere".

ora, dopo che ho sbattuto io la testa mi date qualche suggerimento???

i muri sono dei box e "io" sono un oggetto creato in blender(molto brutto)

PGI-Bis
12-01-2010, 23:59
Tutto dipende da come l'hai fatto la questione del navigatore si può risolvere con due behavior.

Uno si sveglia alla pressione dei tasti e l'altro gira in continuazione.

Quello che gira controlla la telecamera usando due vettori, uno per la direzione dello spostamento e uno per le rotazioni. Quando la telecamera è ferma i componenti dei due Vector3f valgono zero.

Il behavior che raccoglie l'input AWT e lo trasforma in "segnale" per il thread Java3D altro non fa che modificare i componenti di quei due vettori in accordo alla direzione che l'utente vuole impartire.

Tanto per essere meno astratti, la questione è:

behavior 1: due Vector3f, spostamento e rotazione.

behavior 2: reagisce alla condizione WakeupOnAWTEvent per tasto premuto, tasto rilasciato (e volendo movimento del mouse). Supponiamo che il tasto W significhi avanti e il tasto S indietro. Dirà, nel processStimulus:

se l'evento è W premuto: behavior1.spostamento.z = -1;
se l'evento è W rilasciato: behavior1.spsotamento.z = 0;
se l'evento è S premuto: behavior1.spostamento.z = 1;
se l'evento è S rilasciato: behavior1.spostamento.z = 0;

behavior 1, che nel frattempo gira come un pazzo, dice nel suo processStimulus:

float dz = PLAYER_SPEED * DTIME * spostamento.z;

poi applica dz al gruppo di trasformazione della vista. Il vettore spostamento stabilisce se la vista debba muoversi mantenendo o azzerando il prodotto PLAYER_SPEED * DIME. Nel caso in cui mantenga il prodotto, stabilisce la direzione negandolo o no. Lo stesso vale per lo spostamento lungo gli altri due assi e le rotazioni (tenendo però conto che in caso di rotazione lo spostamento va trasformato con la rotazione prima di essere applicato per mantenere la "direzione di marcia").

Per quanto riguarda la collisione ricordo che puoi usare una libreria per la fisica (tipo JBullet) se non vuoi far da te.

franksisca
13-01-2010, 10:42
Tutto dipende da come l'hai fatto la questione del navigatore si può risolvere con due behavior.

Uno si sveglia alla pressione dei tasti e l'altro gira in continuazione.

Quello che gira controlla la telecamera usando due vettori, uno per la direzione dello spostamento e uno per le rotazioni. Quando la telecamera è ferma i componenti dei due Vector3f valgono zero.

Il behavior che raccoglie l'input AWT e lo trasforma in "segnale" per il thread Java3D altro non fa che modificare i componenti di quei due vettori in accordo alla direzione che l'utente vuole impartire.

Tanto per essere meno astratti, la questione è:

behavior 1: due Vector3f, spostamento e rotazione.

behavior 2: reagisce alla condizione WakeupOnAWTEvent per tasto premuto, tasto rilasciato (e volendo movimento del mouse). Supponiamo che il tasto W significhi avanti e il tasto S indietro. Dirà, nel processStimulus:

se l'evento è W premuto: behavior1.spostamento.z = -1;
se l'evento è W rilasciato: behavior1.spsotamento.z = 0;
se l'evento è S premuto: behavior1.spostamento.z = 1;
se l'evento è S rilasciato: behavior1.spostamento.z = 0;

behavior 1, che nel frattempo gira come un pazzo, dice nel suo processStimulus:

float dz = PLAYER_SPEED * DTIME * spostamento.z;

poi applica dz al gruppo di trasformazione della vista. Il vettore spostamento stabilisce se la vista debba muoversi mantenendo o azzerando il prodotto PLAYER_SPEED * DIME. Nel caso in cui mantenga il prodotto, stabilisce la direzione negandolo o no. Lo stesso vale per lo spostamento lungo gli altri due assi e le rotazioni (tenendo però conto che in caso di rotazione lo spostamento va trasformato con la rotazione prima di essere applicato per mantenere la "direzione di marcia").

Per quanto riguarda la collisione ricordo che puoi usare una libreria per la fisica (tipo JBullet) se non vuoi far da te.

ok, già una cosa in più con 2 behavior, non ci avevo pensato.

per le collisioni non posso collegare il behavior pazzo alla mia mappa per verificare se è in "zona di collisione"?


ti spiego, io creo una matrice di char per creare un laabirinto con una sola uscita, e poi da questa matrice estraggo la mappa 3d, con muri, nemici, e posizione iniziale mia. poi quando vado a creare il mondo, nella cella del muro ci metto un box e così via...ovviamente lo spostamento di una pressione non equivale all'avanzamento di una singola cella, ma ad una frazione.

pensi che questo approccio sia sbagliato?

PGI-Bis
13-01-2010, 14:05
Il behavior in aggiornamento continuo può benissimo essere lo stesso che usi per gestire la logica del programma - e quindi collisioni, condizioni di vittoria, AI eccetera eccetera.

La tua matrice di char è un caso particolare di albero a quadranti che può essere usato per ripartire uno spazio 3D (sfruttando una proiezione su un piano).

Quello che fai non è altro che prendere il tuo mondo virtuale e dividerlo in parallelepipedi con un lato quadrangolare di lato unitario L (che può valere 1 come 5.7645, è unitario nel senso del rapporto).

Assegni poi ogni elemento 3D ad un quadrante usando la proiezione del volume di quell'elemento su un piano 2D.

Messa così sembra giapponese ma è una questione terra terra. E' come avere una griglia sul pavimento di una stanza e dover dire: quali celle occupa il comodino? Nota la dimensione del lato delle celle di quella griglia e supposto che tali celle siano dei quadrati, sappiamo che un qualsiasi punto nello spazio P(x, y, z) occupa la cella C di coordinate (floor(p.x / L), floor(p.y / L)). Pigliamo la nostra figura 3D, la racchiudiamo in un bel volume AABB (cioè un parallelepipedo allineato con gli assi) e risulta che le celle occupate sono tutte quelle coperte dalla base di quel AABB.

Funziona? Be', tutto quello che ci permette di stabilire cosa ci sia o non ci sia in un certo punto dello spazio con un costo minore della scansione lineare di una lista di elementi funziona. Funziona meglio o peggio di altre soluzioni? Dipende.

La prima cosa di cui tener conto secondo me è quanti elementi hai nella tua scena. Se non sono più di un centinaio considera che una semplice lista va più che bene (un for(Elemento e : lista) per cento elementi impiega tempi nell'ordine dei nanosecondi per essere eseguito).

La matrice funziona meglio della lista ma è limitata da questioni di memoria se lo spazio da ripartire è molto grande (perchè la memoria che occupa cresce col quadrato della sua dimensione, se vuoi dividere un km quadrato con una risoluzione di un metro hai già un matricione di 10^6 x (N byte), se diminuisci la risoluzione corri il rischio che in certe celle si trovino liste molto lunghe di elementi). Inoltre è una struttura 2D: se il mondo virtuale di divide in più livelli dopo aver stabilito in che cella ti trovi devi fare un ulteriore passaggio per determinare il livello (e non puoi usare una matrice 3D perchè questa si mangia memoria al cubo).

Tuttavia se:

1. lo spazio da dividere è abbastanza piccolo
2. si sviluppa su un solo livello
3. ogni elemento è interamente ed esclusivamente rapportabile ad una o più celle

allora la matrice è perfetta perchè con un costo O(1) arrivi direttamente all'oggetto 3D che occupa una certa posizione nello spazio.

Tommo
13-01-2010, 16:28
Minchia ma così è brutto forte :asd:

Mi sembra che il problema sia completamente una questione di punti di vista; cioè che mentre si parla di collisioni si va a finire alle GUI e agli inputs... bene, questo è errato :D

Io ti suggerirei di fare prima un sistema di collisioni che funziona per generiche shapes in moto, fatto magari come dice PGI-Bis, e POI causare il moto di una forma con le frecce.
Vedrai che torna tutto più elegante.

Poi non hai detto che forme devi gestire e le posizioni che queste possono assumere... perchè se sono solo AABB è banale, se già ci finiscono dentro pure le sfere diventa più complesso.

franksisca
16-01-2010, 15:08
Il behavior in aggiornamento continuo può benissimo essere lo stesso che usi per gestire la logica del programma - e quindi collisioni, condizioni di vittoria, AI eccetera eccetera.

La tua matrice di char è un caso particolare di albero a quadranti che può essere usato per ripartire uno spazio 3D (sfruttando una proiezione su un piano).

Quello che fai non è altro che prendere il tuo mondo virtuale e dividerlo in parallelepipedi con un lato quadrangolare di lato unitario L (che può valere 1 come 5.7645, è unitario nel senso del rapporto).

Assegni poi ogni elemento 3D ad un quadrante usando la proiezione del volume di quell'elemento su un piano 2D.

Messa così sembra giapponese ma è una questione terra terra. E' come avere una griglia sul pavimento di una stanza e dover dire: quali celle occupa il comodino? Nota la dimensione del lato delle celle di quella griglia e supposto che tali celle siano dei quadrati, sappiamo che un qualsiasi punto nello spazio P(x, y, z) occupa la cella C di coordinate (floor(p.x / L), floor(p.y / L)). Pigliamo la nostra figura 3D, la racchiudiamo in un bel volume AABB (cioè un parallelepipedo allineato con gli assi) e risulta che le celle occupate sono tutte quelle coperte dalla base di quel AABB.

Funziona? Be', tutto quello che ci permette di stabilire cosa ci sia o non ci sia in un certo punto dello spazio con un costo minore della scansione lineare di una lista di elementi funziona. Funziona meglio o peggio di altre soluzioni? Dipende.

La prima cosa di cui tener conto secondo me è quanti elementi hai nella tua scena. Se non sono più di un centinaio considera che una semplice lista va più che bene (un for(Elemento e : lista) per cento elementi impiega tempi nell'ordine dei nanosecondi per essere eseguito).

La matrice funziona meglio della lista ma è limitata da questioni di memoria se lo spazio da ripartire è molto grande (perchè la memoria che occupa cresce col quadrato della sua dimensione, se vuoi dividere un km quadrato con una risoluzione di un metro hai già un matricione di 10^6 x (N byte), se diminuisci la risoluzione corri il rischio che in certe celle si trovino liste molto lunghe di elementi). Inoltre è una struttura 2D: se il mondo virtuale di divide in più livelli dopo aver stabilito in che cella ti trovi devi fare un ulteriore passaggio per determinare il livello (e non puoi usare una matrice 3D perchè questa si mangia memoria al cubo).

Tuttavia se:

1. lo spazio da dividere è abbastanza piccolo
2. si sviluppa su un solo livello
3. ogni elemento è interamente ed esclusivamente rapportabile ad una o più celle

allora la matrice è perfetta perchè con un costo O(1) arrivi direttamente all'oggetto 3D che occupa una certa posizione nello spazio.
rileggendo tutto ho capito cosa vuoi dire.

la situazione è esattamente questa.

cella 20x20 con una percentulae del 35% di muri e un 10% di nemici rispetto al numero di celle.

quindi, facendo due conti, la matrice credo ia la soluzione migliore.

concordi?

Minchia ma così è brutto forte :asd:

Mi sembra che il problema sia completamente una questione di punti di vista; cioè che mentre si parla di collisioni si va a finire alle GUI e agli inputs... bene, questo è errato :D

Io ti suggerirei di fare prima un sistema di collisioni che funziona per generiche shapes in moto, fatto magari come dice PGI-Bis, e POI causare il moto di una forma con le frecce.
Vedrai che torna tutto più elegante.

Poi non hai detto che forme devi gestire e le posizioni che queste possono assumere... perchè se sono solo AABB è banale, se già ci finiscono dentro pure le sfere diventa più complesso.

sono oggetti "teoricamente" complessi, ma essendo una cosa didattica, al prof interessa che io la sappia eventualemtne fare.

poi rifinirlo in seguito allora si...anche quello che dici tu è correttissimo

franksisca
16-01-2010, 15:37
questo è il behavior 2, ovvero quello che sveglia il 1 per fare le azioni
package gestioneCollisioniAvanzata;

import java.awt.AWTEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Enumeration;
import java.util.LinkedList;
import javax.media.j3d.Behavior;
import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOnBehaviorPost;
import javax.media.j3d.WakeupOr;

public class AscoltatoreEventi extends Behavior implements KeyListener {
private WakeupCriterion pulsantePremuto = new WakeupOnAWTEvent(
KeyEvent.KEY_PRESSED);
private WakeupCriterion pulsanteRilasciato = new WakeupOnAWTEvent(
KeyEvent.KEY_RELEASED);
private WakeupCriterion[] arrayAzioni = { pulsantePremuto,
pulsanteRilasciato };
private WakeupCondition eventoAzioni = new WakeupOr(arrayAzioni);
private KeyEvent pulsante;
private EsecutoreEventi esecutore;

@SuppressWarnings("unchecked")
private LinkedList eventq;

@SuppressWarnings("unchecked")
public void initialize() {
pulsantePremuto = new WakeupOnBehaviorPost(this, KeyEvent.KEY_PRESSED);
pulsanteRilasciato = new WakeupOnBehaviorPost(this,
KeyEvent.KEY_RELEASED);
arrayAzioni[0] = pulsantePremuto;
arrayAzioni[1] = pulsanteRilasciato;
eventoAzioni = new WakeupOr(arrayAzioni);
eventq = new LinkedList();
wakeupOn(eventoAzioni);
}

@SuppressWarnings("unchecked")
public void processStimulus(Enumeration criteria) {
WakeupOnAWTEvent ev;
WakeupCriterion genericEvt;
AWTEvent[] events;
while (criteria.hasMoreElements()) {
genericEvt = (WakeupCriterion) criteria.nextElement();
if (genericEvt instanceof WakeupOnAWTEvent) {
ev = (WakeupOnAWTEvent) genericEvt;
events = ev.getAWTEvent();
processAWTEvent(events);
} else if ((genericEvt instanceof WakeupOnBehaviorPost)) {
while (true) {
synchronized (eventq) {
if (eventq.isEmpty())
break;
pulsante = (KeyEvent) eventq.remove(0);
if (pulsante.getID() == KeyEvent.KEY_PRESSED
|| pulsante.getID() == KeyEvent.KEY_RELEASED) {
esecutore.processKeyEvent(pulsante);
}
}
}
}
}
wakeupOn(eventoAzioni);
}

private void processAWTEvent(AWTEvent[] events) {
for (int loop = 0; loop < events.length; loop++) {
if (events[loop] instanceof KeyEvent) {
pulsante = (KeyEvent) events[loop];
if (pulsante.getID() == KeyEvent.KEY_PRESSED
|| pulsante.getID() == KeyEvent.KEY_RELEASED) {
// System.out.println("Premuto pulsante: " + eventKey);
esecutore.processKeyEvent(pulsante);

}
}
}
}

@SuppressWarnings("unchecked")
public void keyPressed(KeyEvent evt) {
synchronized (eventq) {
eventq.add(evt);
if (eventq.size() == 1)
postId(KeyEvent.KEY_PRESSED);
}
}

@SuppressWarnings("unchecked")
public void keyReleased(KeyEvent evt) {
synchronized (eventq) {
eventq.add(evt);
if (eventq.size() == 1)
postId(KeyEvent.KEY_RELEASED);
}
}

public void keyTyped(KeyEvent evt) {

}

}



mentre questo è quello che deve fare gli spostamenti in base al keypressed, giusto???

package gestioneCollisioniAvanzata;

import java.awt.event.KeyEvent;

import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Vector3d;

public class EsecutoreEventi {

private Vector3d spostamento;
private Vector3d rotazione;
private Transform3D nominal = new Transform3D();
private TransformGroup targetTG;
public EsecutoreEventi(TransformGroup targetTG) {

this.targetTG = targetTG;
targetTG.getTransform(nominal);
spostamento = new Vector3d(0.0, 0.0, 0.0);
rotazione = new Vector3d(0.0, 0.0, 0.0);

}

public void processKeyEvent(KeyEvent eventKey) {
// TODO Auto-generated method stub

}
}

PGI-Bis
16-01-2010, 16:50
Che c'entra il KeyListener? Tieni conto che quando un Behavior è impostato per "svegliarsi" in conseguenza di un evento AWT "keypressed" la faccenda finisce lì: premi un pulsante e lui risponde. Non è necessario usare un addKeyListener su un componente AWT/Swing.

franksisca
16-01-2010, 17:48
Che c'entra il KeyListener? Tieni conto che quando un Behavior è impostato per "svegliarsi" in conseguenza di un evento AWT "keypressed" la faccenda finisce lì: premi un pulsante e lui risponde. Non è necessario usare un addKeyListener su un componente AWT/Swing.

sry
:asd:

correggo e poi posto :D

anzi...vado a fare la spesa e poi correggo (altriemnit resto digiuno)

franksisca
17-01-2010, 17:33
no...non è stata la spesa più lunga della storia....ma tra partite di ieri e oggi non ho praticamente messo mano al codice X_X


comunque....dicevamo...



import java.awt.AWTEvent;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
import java.util.LinkedList;
import javax.media.j3d.Behavior;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCondition;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOr;

public class AscoltatoreEventi extends Behavior {
private WakeupCriterion pulsantePremuto = new WakeupOnAWTEvent(
KeyEvent.KEY_PRESSED);
private WakeupCriterion pulsanteRilasciato = new WakeupOnAWTEvent(
KeyEvent.KEY_RELEASED);
private WakeupCriterion[] arrayAzioni = { pulsantePremuto,
pulsanteRilasciato };
private WakeupCondition eventoAzioni = new WakeupOr(arrayAzioni);
private KeyEvent pulsante;
private EsecutoreEventi esecutore;

@SuppressWarnings("unchecked")
private LinkedList eventq;

public AscoltatoreEventi(TransformGroup targetTG) {
this.esecutore = new EsecutoreEventi(targetTG);
}

@SuppressWarnings("unchecked")
public void initialize() {
pulsantePremuto = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
pulsanteRilasciato = new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED);
arrayAzioni[0] = pulsantePremuto;
arrayAzioni[1] = pulsanteRilasciato;
eventoAzioni = new WakeupOr(arrayAzioni);
eventq = new LinkedList();
wakeupOn(eventoAzioni);
}

@SuppressWarnings("unchecked")
public void processStimulus(Enumeration criteria) {
WakeupOnAWTEvent ev;
WakeupCriterion genericEvt;
AWTEvent[] events;
while (criteria.hasMoreElements()) {
genericEvt = (WakeupCriterion) criteria.nextElement();
if (genericEvt instanceof WakeupOnAWTEvent) {
ev = (WakeupOnAWTEvent) genericEvt;
events = ev.getAWTEvent();
processAWTEvent(events);
}
}
wakeupOn(eventoAzioni);
}

private void processAWTEvent(AWTEvent[] events) {
for (int loop = 0; loop < events.length; loop++) {
if (events[loop] instanceof KeyEvent) {
pulsante = (KeyEvent) events[loop];
if (pulsante.getID() == KeyEvent.KEY_PRESSED) {
esecutore.processKeyEvent(pulsante, 1);
}
if (pulsante.getID() == KeyEvent.KEY_RELEASED) {
esecutore.processKeyEvent(pulsante, 0);
}

}
}

}

}





package gestioneCollisioniAvanzata;

import java.awt.event.KeyEvent;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Vector3d;


public class EsecutoreEventi {

private static final int forwardKey = KeyEvent.VK_W;
private static final int backKey = KeyEvent.VK_S;
private static final int leftKey = KeyEvent.VK_A;
private static final int rightKey = KeyEvent.VK_D;
private Vector3d spostamento;
private Vector3d rotazione;
private Transform3D nominal = new Transform3D();
private TransformGroup targetTG;

public EsecutoreEventi(TransformGroup targetTG) {

this.targetTG = targetTG;
targetTG.getTransform(nominal);
spostamento = new Vector3d(0.0, 0.0, 0.0);
rotazione = new Vector3d(0.0, 0.0, 0.0);

}

public void processKeyEvent(KeyEvent eventKey, int azione) {
if (azione == 0)
return;
else {
int evento = eventKey.getKeyCode();
switch (evento) {
case forwardKey:
System.out.println("premuto w");
break;
case backKey:
System.out.println("premuto s");
break;
case leftKey:
System.out.println("premuto a");
break;
case rightKey:
System.out.println("premuto d");
break;
default:
System.out.println("premuto niente");
}
int keyCode = eventKey.getKeyCode();
int keyChar = eventKey.getKeyChar();

System.err.println("keyCode " + keyCode + " keyChar " + keyChar);
}
}
}




questi sono i 2 behavior che ho costruito, con il primo che ascolta i messagi da tastiera, mentre il secondo si occuperà di "calcolare" le funzioni e quindi anche le collisioni.

per gestire la pressione contemporanea di due pulsanti (ad esempio a+w per andare in diagonale sinistra avanti) come devo fare?

PGI-Bis
18-01-2010, 06:59
La pressione di più pulsanti genera eventi distinti anche quando il pulsante è un modificatore (ad esempio shift + v sono due eventi key pressed, uno per lo shift e uno per la v). I modificatori si accumulano con i caratteri solo negli eventi di tipo KEY_TYPED (vale a dire durante la digitazione in un componente di testo).

Dunque W+A viene recepito come W premuto seguito da A premuto (o viceversa).

Siccome pulsanti diversi gestiscono assi diversi, ad esempio W e S per l'asse Z, A e D per l'asse X, la combinazione dei pulsanti risultante in una direzione di movimento "arbitraria" risulta semplicemente dalla mutazione di valori diversi nel vettore direzione. Vale a dire che se dico:

quando W è premuto movimento.z = -1
quando S è premuto movimento.z = 1
quando A è premuto movimento.x = -1
quando D è premuto movimento.x = 1

alla pressione dei tasti W+A (che genera due eventi, W premuto e A premuto), otterrò una direzione:

movimento = (-1, 0, -1)

che è appunto un "avanti a sinistra" (nel sistema di coordinate di Java3D)

franksisca
18-01-2010, 11:04
La pressione di più pulsanti genera eventi distinti anche quando il pulsante è un modificatore (ad esempio shift + v sono due eventi key pressed, uno per lo shift e uno per la v). I modificatori si accumulano con i caratteri solo negli eventi di tipo KEY_TYPED (vale a dire durante la digitazione in un componente di testo).

Dunque W+A viene recepito come W premuto seguito da A premuto (o viceversa).

Siccome pulsanti diversi gestiscono assi diversi, ad esempio W e S per l'asse Z, A e D per l'asse X, la combinazione dei pulsanti risultante in una direzione di movimento "arbitraria" risulta semplicemente dalla mutazione di valori diversi nel vettore direzione. Vale a dire che se dico:

quando W è premuto movimento.z = -1
quando S è premuto movimento.z = 1
quando A è premuto movimento.x = -1
quando D è premuto movimento.x = 1

alla pressione dei tasti W+A (che genera due eventi, W premuto e A premuto), otterrò una direzione:

movimento = (-1, 0, -1)

che è appunto un "avanti a sinistra" (nel sistema di coordinate di Java3D)
si questo l'avevo capito, ma non ho capito come "gestirlo" nella coda dei processi.

se uso queste due classi insieme proprio come sono ora, con le stampe, e se premo 2 pulsanti insieme mi stampa il risultato dell'ultima pressione, e non delle due pressini

franksisca
18-01-2010, 16:37
behaviior2

package gestioneCollisioniAvanzata;

import java.awt.event.KeyEvent;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Vector3d;

import dunJeonPac.Posizione;

public class EsecutoreEventi {

private static final int forwardKey = KeyEvent.VK_W;
private static final int backKey = KeyEvent.VK_S;
private static final int leftKey = KeyEvent.VK_A;
private static final int rightKey = KeyEvent.VK_D;
private Vector3d spostamento;
private Vector3d rotazione;
private Transform3D nominal = new Transform3D();
private TransformGroup targetTG;

public EsecutoreEventi(TransformGroup targetTG) {

this.targetTG = targetTG;
this.targetTG.getTransform(nominal);
this.spostamento = new Vector3d(0.0, 0.0, 0.0);
this.rotazione = new Vector3d(0.0, 0.0, 0.0);

}

public void processKeyEvent(KeyEvent eventKey, int azione) {
if (azione == 0)
return;
else {

int evento = eventKey.getKeyCode();

if (evento == forwardKey) {
this.spostamento = new Vector3d(0.0, 0.0, -0.24);
}
if (evento == forwardKey && evento == rightKey) {
this.spostamento = new Vector3d(0.240, 0.0, -0.24);
}
if (evento == backKey) {
this.spostamento = new Vector3d(0.0, 0.0, 0.24);
}
if (evento == leftKey) {
this.spostamento = new Vector3d(-0.240, 0.0, 0.0);
}
if (evento == rightKey) {
this.spostamento = new Vector3d(0.24, 0.0, 0.0);
}
this.targetTG.getTransform(this.nominal);
Transform3D toMove = new Transform3D();
toMove.setTranslation(this.spostamento);
this.nominal.mul(toMove);
this.targetTG.setTransform(this.nominal);

int keyCode = eventKey.getKeyCode();
char keyChar = eventKey.getKeyChar();

System.err.println("keyCode " + keyCode + " keyChar " + keyChar);
}
}
}



altra cosa....volevo usare il mouse per spostare il punto di rotazione, ma se uso il mouse translate è un caso, che faccio...estendo e reipllmnenteo da 0?

PGI-Bis
18-01-2010, 18:01
E' strano che ti salti un evento nel caso della pressione di due tasti.

Per la rotazione, il discorso è lo stesso anche nel caso in cui l'input provenga dal mouse. In questo caso anzichè la pressione di un tasto consideri come evento lo spostamento del mouse tra un frame e l'altro (nel senso che se lo spostamento è x positivo, giri a destra, altrimenti a sinistra, y negativo guardi giuù, y positivo guardi su). Occhio che ti serve lo spostamento e non la posizione (quindi dovrai tener traccia del punto precedemente occupato dal mouse).

franksisca
18-01-2010, 20:56
E' strano che ti salti un evento nel caso della pressione di due tasti.

Per la rotazione, il discorso è lo stesso anche nel caso in cui l'input provenga dal mouse. In questo caso anzichè la pressione di un tasto consideri come evento lo spostamento del mouse tra un frame e l'altro (nel senso che se lo spostamento è x positivo, giri a destra, altrimenti a sinistra, y negativo guardi giuù, y positivo guardi su). Occhio che ti serve lo spostamento e non la posizione (quindi dovrai tener traccia del punto precedemente occupato dal mouse).

ecco, mi salta questo passagio...

PGI-Bis
19-01-2010, 12:45
In che senso ti salta? Chi è che salta?

franksisca
19-01-2010, 13:34
ecco, mi salta questo passagio...

In che senso ti salta? Chi è che salta?

nel senso che mi salta mentalmente il passaggio.

io vorrei che con il mouse, senza premere, mi permetta una "rotazione completa" (quindi angolare) e piccoli spostamenti in alto-basso, ma solo come "visuale", mentre con wasd farei il movimento.

per ora il movimento, anche se parziale, funziona (non come vorrei.....ma ci stiamo lavorando :D ) mentrer per il discorso mouse non sò come implementarlo.
usare i behavior che ci sono non mi sembra riesca a fare quello che mi serve.

PGI-Bis
19-01-2010, 14:12
Frugando nei meandri dell'hard-disk ho trovato un esempio.

package j3dcollisions;

import java.awt.AWTEvent;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import javax.media.j3d.Behavior;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.media.j3d.WakeupOr;
import javax.vecmath.Vector3f;

public class KeyController extends Behavior {

WakeupOr wakeup = new WakeupOr(new WakeupOnAWTEvent[]{
new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED),
new WakeupOnAWTEvent(KeyEvent.KEY_RELEASED),
new WakeupOnAWTEvent(MouseEvent.MOUSE_MOVED)});
private Movable target;
private Point lastMousePoint;

public KeyController(Movable target) {
this.target = target;
}

public void initialize() {
wakeupOn(wakeup);
}

public void processStimulus(Enumeration criteria) {
while (criteria.hasMoreElements()) {
WakeupOnAWTEvent criterion = (WakeupOnAWTEvent) criteria.nextElement();
AWTEvent[] events = criterion.getAWTEvent();
for (int i = 0; i < events.length; i++) {
AWTEvent e = events[i];
switch (e.getID()) {
case KeyEvent.KEY_PRESSED:
processKeyPressed(((KeyEvent) e).getKeyCode());
break;
case KeyEvent.KEY_RELEASED:
processKeyReleased(((KeyEvent) e).getKeyCode());
break;
case MouseEvent.MOUSE_MOVED:
processMouseMoved(((MouseEvent) e).getPoint());
break;
}
}
}
wakeupOn(wakeup);
}

private void processMouseMoved(Point p) {
if (lastMousePoint == null) {
lastMousePoint = new Point(p.x, p.y);
}
int dx = lastMousePoint.x - p.x;
int dy = lastMousePoint.y - p.y;

lastMousePoint.move(p.x, p.y);

Vector3f max = new Vector3f();
target.getMaxAngularVelocity(max);

int xdir = Integer.signum(dx);
int ydir = Integer.signum(dy);

max.x *= ydir;
max.y *= xdir;
max.z = 0;

target.setAngularVelocity(max);
}

private void processKeyPressed(int keyCode) {
Vector3f max = new Vector3f();
target.getMaxLinearVelocity(max);
Vector3f vel = new Vector3f();
target.getLinearVelocity(vel);

switch (keyCode) {
case KeyEvent.VK_S:
vel.z = max.z;
break;
case KeyEvent.VK_W:
vel.z = -max.z;
break;
case KeyEvent.VK_A:
vel.x = -max.x;
break;
case KeyEvent.VK_D:
vel.x = max.x;
break;
}
target.setLinearVelocity(vel);
}

private void processKeyReleased(int keyCode) {
Vector3f vel = new Vector3f();
target.getLinearVelocity(vel);

switch (keyCode) {
case KeyEvent.VK_S:
vel.z = 0;
break;
case KeyEvent.VK_W:
vel.z = 0;
break;
case KeyEvent.VK_A:
vel.x = 0;
break;
case KeyEvent.VK_D:
vel.x = 0;
break;
}
target.setLinearVelocity(vel);
}
}

Francamente non mi ricordo neanche più cosa facesse (credo riguardasse gli alberi a ottanti) ma c'era un movimento in stile FPS e quello è il behavior che cattura l'input sia del mouse che della tastiera per movimento e rotazione.

franksisca
19-01-2010, 14:32
grazie..ora lo testo

franksisca
19-01-2010, 14:55
manca la classe movable...che non sòcosa server...cmq me lo studio lo stesso (suppongo sia una tua transform3d)

PGI-Bis
19-01-2010, 15:00
Movable è (fu) un'interfaccia:

import javax.media.j3d.BoundingBox;
import javax.vecmath.Tuple3f;

public interface Movable {
public BoundingBox getBounds();

void getMaxLinearVelocity(Tuple3f components);
void getMaxAngularVelocity(Tuple3f components);

void setLinearVelocity(Tuple3f components);
void getLinearVelocity(Tuple3f components);

void getAngularVelocity(Tuple3f components);
void setAngularVelocity(Tuple3f components);

void setLocation(Tuple3f location);
void getLocation(Tuple3f location);

void setRotation(Tuple3f rotation);
void getRotation(Tuple3f rotation);
}

Ho trovato un Avatar che è un Movable e dovrebbe essere proprio il giocatore:

import javax.media.j3d.BoundingBox;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Node;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.vecmath.AxisAngle4f;
import javax.vecmath.Matrix3f;
import javax.vecmath.Point3d;
import javax.vecmath.Quat4f;
import javax.vecmath.Tuple3f;
import javax.vecmath.Vector3f;

public class Avatar implements Movable {
private Vector3f maxLinearVelocity = new Vector3f(0.002f, 0.002f, 0.002f);
private Vector3f maxAngularVelocity = new Vector3f(0.002f, 0.002f, 0.002f);
private Vector3f linearVelocity = new Vector3f();
private Vector3f angularVelocity = new Vector3f();
private Vector3f rotation = new Vector3f();
private Vector3f location = new Vector3f();

private TransformGroup headGroup;
private TransformGroup bodyGroup;

private BoundingBox bounds = new BoundingBox();
private Point3d upper = new Point3d();
private Point3d lower = new Point3d();

public Avatar(Canvas3D canvas) {
Utilities u = new Utilities();
headGroup = u.newRWTransformGroup();
bodyGroup = u.newRWTransformGroup();
View view = new View();
view.setPhysicalBody(new PhysicalBody());
view.setPhysicalEnvironment(new PhysicalEnvironment());
view.addCanvas3D(canvas);
ViewPlatform vp = new ViewPlatform();
view.attachViewPlatform(vp);
headGroup.addChild(vp);

TransformGroup neck = new TransformGroup();
Transform3D neckT = new Transform3D();
neckT.set(new Vector3f(0, 1.7f, 0));
neck.setTransform(neckT);
neck.addChild(headGroup);

bodyGroup.addChild(neck);
updateBounds();
}

public BoundingBox getBounds() {
return bounds;
}

public Node getNode() {
return bodyGroup;
}

public void setLinearVelocity(Tuple3f components) {
linearVelocity.set(components);
}

public void getLinearVelocity(Tuple3f components) {
components.set(linearVelocity);
}

public void getAngularVelocity(Tuple3f components) {
components.set(angularVelocity);
}

public void setAngularVelocity(Tuple3f components) {
angularVelocity.set(components);
}

private void updateBounds() {
lower.x = location.x - 1;
lower.y = location.y - 1;
lower.z = location.z - 1;
upper.x = location.x + 1;
upper.y = location.y + 2;
upper.z = location.z + 1;
bounds.setLower(lower);
bounds.setUpper(upper);
}

public void setLocation(Tuple3f location) {
this.location.set(location);

Matrix3f bodyRot = new Matrix3f();
bodyRot.rotY(rotation.y);
Transform3D t = new Transform3D();
t.set(bodyRot, this.location, 1);
bodyGroup.setTransform(t);
updateBounds();
}

public void getLocation(Tuple3f location) {
location.set(this.location);
}

public void setRotation(Tuple3f rotation) {
this.rotation.set(rotation);

Transform3D t = new Transform3D();
t.rotX(rotation.x);
headGroup.setTransform(t);

Matrix3f bodyRot = new Matrix3f();
bodyRot.rotY(rotation.y);
t.set(bodyRot, location, 1);
bodyGroup.setTransform(t);
updateBounds();
}

public void getRotation(Tuple3f rotation) {
rotation.set(this.rotation);
}

public void getMaxLinearVelocity(Tuple3f components) {
components.set(maxLinearVelocity);
}

public void getMaxAngularVelocity(Tuple3f components) {
components.set(maxAngularVelocity);
}
}

Ma tieni sempre conto che non mi ricordo più cosa io volessi fare.

franksisca
19-01-2010, 15:05
allora decodificherò il tuo codice :D