Controllo per fotocamera in prima persona Libgdx

Ho appena iniziato a giocare con 3D in libgdx. So già come disegnare Model base e ho provato a giocare con il CameraController . Ora voglio creare una FirstPersonCamera o FirstPersonCameraController . Ho pensato di estendere PerspectiveCamera e aggiungere un MyMovingObject target ad esso. MyMovingObject mantiene una posizione x, y, z position , dove y è un valore costante, perché non posso spostarmi up/down al momento. Quindi il mio movimento è fondamentalmente in 2D. MyMovingObject memorizza anche la left/right rotation , necessaria per la sua moving direction / xSpeed, zSpeed . Ma il Player dovrebbe anche essere in grado di cercare su e giù, e questa rotazione su / giù non è realmente necessaria per MyMovingObject , in quanto modifica solo la vista e nessun’altra proprietà. Quindi non sono sicuro se vado nel modo giusto.
Voglio essere in grado di andare avanti, a sinistra, a destra, all’indietro usando W,A,S,D e ruotare a sinistra a destra usando il mouse. Anche io voglio cercare su e giù usando il mouse, come nella maggior parte dei giochi in First Person .
Dovrei usare un altro modo, non creare la mia fotocamera estendendo PerspectiveCamera ? Oppure questo approccio è buono e devo solo memorizzare la rotazione su / giù in MyMovingObject , anche se è necessaria solo per la vista?
O sarebbe meglio controllare la videocamera con W,A,S,D and mouse e aggiornare la posizione di MyMovingObject , a seconda della posizione e della rotazione della telecamera?
Spero tu capisca quello che intendo. Sembra un po ‘complicato spiegarlo (almeno per me).

EDIT: Ora sto usando la Vector3 direction , la Vector3 position Vector3 size e la Vector3 size per i miei NPC e il giocatore. Calcolo la velocità eseguendo: xSpeed = direction.x / (direction.x + direction.z) * speed; lo stesso per zSpeed. Facendo questo, “filtro” il valore y da esso e ottengo solo la percentuale di x e y. L’unico problema è che quando guardo verso l’alto x e z sono 0 . Potrei risolvere questo problema utilizzando un UpVecotr , che viene ruotato quando UpVecotr una “Pitch-rotation”. Ma come lo faccio ruotare? Ho bisogno di ruotarlo attorno al vettore laterale. Grazie

EDIT: La rotazione e il movimento funzionano ora (vedi la mia risposta), ma ho davvero grossi problemi con la limitazione della “Pitch-rotation”. Sto usando: if (direction.y 1) doPitchRotation(); else if (direction.y > -0.9 && angle < 1) doPitchRotation(); if (direction.y 1) doPitchRotation(); else if (direction.y > -0.9 && angle < 1) doPitchRotation(); quindi se ruoto verso il basso e guardo ancora in basso almeno a -0,9 y, semplicemente non esegue la rotazione. Ma cosa succede veramente: ruoto a – 0,9 allora ruota intorno all’asse Y e dall’altra parte ruota, anche se muovo il mio mous down. Puoi spiegare perché? Perché l’asse Y si capovolge quando giro verso l’interno guardando in basso?

EDIT: Funziona ora. Sembra che il mio upVector abbia qualche volta valori sbagliati. Per le camme a terra puoi anche usare crossproduct di Y-Axis e direction Vector. Non c’è bisogno di upVector.

Ehi, grazie per aver condiviso questo link L’ho trovato molto utile. Ecco il mio codice sulla rotazione di una fotocamera terrestre e sembra funzionare senza problemi.

 private int mouseX = 0; private int mouseY = 0; private float rotSpeed = 0.2f; @Override public boolean mouseMoved(int screenX, int screenY) { int magX = Math.abs(mouseX - screenX); int magY = Math.abs(mouseY - screenY); if (mouseX > screenX) { cam.rotate(Vector3.Y, 1 * magX * rotSpeed); cam.update(); } if (mouseX < screenX) { cam.rotate(Vector3.Y, -1 * magX * rotSpeed); cam.update(); } if (mouseY < screenY) { if (cam.direction.y > -0.965) cam.rotate(cam.direction.cpy().crs(Vector3.Y), -1 * magY * rotSpeed); cam.update(); } if (mouseY > screenY) { if (cam.direction.y < 0.965) cam.rotate(cam.direction.cpy().crs(Vector3.Y), 1 * magY * rotSpeed); cam.update(); } mouseX = screenX; mouseY = screenY; return false; } 

Questo funziona per le fotocamere a terra. Se si desidera realizzare una telecamera per il controllo del volo, è necessario eseguire una rotazione del pitch intorno a cam.direction.crs(cam.up) . Invece di usare Vector3.cpy() vorrei memorizzare una guida di Vector3 help , che ottiene quei valori temporanei, perché Vector3.cpy() crea un nuovo Vector3 e questa operazione viene eseguita ogni ciclo di rendering. Per le videocamere per il controllo di volo è inoltre necessario aggiungere una rotazione del roll e fare la rotazione di yaw cam.up alla cam.up vettore.

Questo articolo è davvero utile secondo me. Ho trovato una soluzione che dovrebbe funzionare, ma non l’ho ancora provato. MovingObject i miei MovingObject hanno una Vector3 position Vector3 direction , Vector3 direction Vector3 size , Vector3 size Vecotr3 upVector e Vecotr3 upVector . La class Player estende questa class MovingObject e aggiunge Mouse e Keycontroll al movimento. Nella class MovingObject ho i moethod:

  1. rotateYaw(float degrees) : ruota la Vector3 direction intorno Y-Axis base ai gradi indicati (libgdx ha una funzione di rotazione per Vector3 ) -> Semplice
  2. rotatePitch(float degrees) : ruota la Vector3 direction intorno a: direction.cross(Vector3.Y) , che è il vettore lato ruotato di MovingObject , in base ai gradi indicati. Anche una Pitch-Rotation deve ruotare l’ upVector , in modo da ruotare l’ upVector allo stesso asse, in base ai gradi indicati. Non appena lo capisci, è semplice.
  3. move(delta) sposta il tuo MovingObject in direzione x,z facendo:

     if (direction.y == 1) { // You are looking straight up, no x,z direction, move in the opposite // direction of upVector xSpeed = upVector.x / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * (-speed); zSpeed = upVector.z / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * (-speed); position.add(xSpeed * delta, 0, ySpeed * delta); } else if (direction.y == -1) { // You are looking straight down, no x,z direction, move in the direction of // upVector xSpeed = upVector.x / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * speed; zSpeed = upVector.z / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * speed; position.add(xSpeed * delta, 0, ySpeed * delta); } else { // You are not looking straight up or down, so you have x,z direction. Use // that. xSpeed = direction.x / (Math.abs(direction.x) + Math.abs(direction.z)) * speed; zSpeed = direction.z / (Math.abs(direction.x) + Math.abs(direction.z)) * speed; position.add(xSpeed * delta, 0, ySpeed * delta); } 

Non ho provato questo fino ad ora, ma penso che dovrebbe funzionare. Nota che nella Pitch-rotation dovresti anche limitarlo verso l’alto / verso il basso. Fai questo controllando il signum di x e z. Se cambiano mentre stai facendo una Pitch-rotation hai ruotato di oltre 90 gradi. Sto aspettando altre risposte e se sbaglio, correggimi!

EDIT: l’ ho provato Funziona così, ma ci sono alcune cose di cui occuparsi:

  1. direction.cross(upVector) cambia la direction Vector. Quindi archivia prima questi dati da qualche parte! Dopo averlo utilizzato, reimposta la direzione Vector.
  2. La limitazione del Pitch ha un problema: se controlli la modifica del signum, come ho suggerito, succede: guardi verso l’alto, signum x e signum z sono 0. Guarda in basso, il signum cambia e la tua azione (limitante) inizia. Quindi fai attenzione a controllare anche se non è zero. Non so come fare la limitazione del pitch e modifico la mia domanda per spiegare il mio problema.
  3. Pensa a normalizzare la tua direction e upVector ogni volta che cambi qualcosa!

Penso che questo dovrebbe funzionare abbastanza bene. Se hai qualche miglioramento fammi sapere e aggiornerò questo qui. Se hai un’altra soluzione, per favore aggiungi una risposta! Grazie

So che questa domanda ha già delle buone risposte. Ma ho avuto alcuni problemi con la risposta selezionata. E voglio solo aiutare qualcuno che sta cercando la stessa soluzione. Ho notato un comportamento strano con la risposta selezionata. Non mantengo gli Y exis come sopra. Che è ovviamente molto importante su un fps. Quindi questo non è perfetto ma volevo metterlo qui.

 // put into the create() method. Gdx.input.setInputProcessor(new InputProcessor() { private int dragX, dragY; float rotateSpeed = 0.2f; // dont' forget to override other methods. @Override public boolean mouseMoved(int screenX, int screenY) { Vector3 direction = cam.direction.cpy(); // rotating on the y axis float x = dragX -screenX; // change this Vector3.y with cam.up if you have a dynamic up. cam.rotate(Vector3.Y,x * rotateSpeed); // rotating on the x and z axis is different float y = (float) Math.sin( (double)(dragY -screenY)/180f); if (Math.abs(cam.direction.y + y * (rotateSpeed*5.0f))< 0.9) { cam.direction.y += y * (rotateSpeed*5.0f) ; } cam.update(); dragX = screenX; dragY = screenY; return true; } }); 

NOTA: non utilizzare alcun controller per fotocamera.
NOTA 2: questo potrebbe tornare utile: Gdx.input.setCursorCatched(true);

EDIT: Volevo solo condividere la funzione walking che utilizzo per cambiare la posizione della telecamera con i tasti wasd. Quando il tasto W è abbassato, l' forward è vero. E quando la chiave è in forward è falsa. Altre direzioni hanno lo stesso principio. Per rilevare il tasto giù e su, si prega di utilizzare il InputProcessor nel codice sopra.
Questo crea movimento nello spazio bidimensionale (assi XZ). La direzione della telecamera non cambierà la direzione del movimento mentre eliminiamo l'asse Y. della direzione.
Uno deve ora anche se la macchina fotografica è diretta verso il cielo (a un angolo non di 90 gradi con il terreno), la lunghezza del vettore di direzione non è fissata a 1.0f . Quindi non ci sarà alcuna perdita di velocità di movimento. Per verificare ciò ho ruotato la telecamera su e giù (spostato il mouse in avanti e all'indietro) ei valori x e z del vettore direzione non sono cambiati. Quindi, quando l'asse y del vettore di direzione viene eliminato, abbiamo un vettore di direzione 2d che non viene influenzato dall'angolo Y della telecamera.

 private void walking(float timeElapsed) { float speed = movementSpeed; if ((forward | back) & (right | left)) { speed /= Math.sqrt(2); } System.out.println(speed); if (forward) { Vector3 v = cam.direction.cpy(); vy = 0f; vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } if (back) { Vector3 v = cam.direction.cpy(); vy = 0f; vx = -vx; vz = -vz; vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } if (left) { Vector3 v = cam.direction.cpy(); vy = 0f; v.rotate(Vector3.Y, 90); vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } if (right) { Vector3 v = cam.direction.cpy(); vy = 0f; v.rotate(Vector3.Y, -90); vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } }