2013-08-15 11 views
10

Sto provando a implementare un movimento in prima persona utilizzando il mouse. Ho funzionato con la tastiera, ma ho difficoltà ad implementarlo usando il mouse poiché il movimento su un lato specifico non è chiaro (cioè spostandoci a sinistra è possibile spostarlo verso l'alto o verso il basso). Desidero utilizzare lo matrix3d per ricevere i valori modificati della posizione.Movimento in prima persona controllato tramite mouse JS

EDIT # 2 Ecco uno jsfiddle.

EDIT Ho incollato il nuovo codice sono riuscito a risolvere:

$(document).on('mousemove', function (e) { 
     var MOVE = 10; // how much to move 
     var XTURN = 1; // how much to rotate 
     var YTURN = 1; // how much to rotate 
     var transformer, origMat, translationMatrix, result; 
     transformer = document.getElementById("transformer"); 

     if ($.browser.webkit) 
      origMat = new WebKitCSSMatrix(window.getComputedStyle(transformer).webkitTransform); 

     //turn left 
     if (e.pageX < xPrev) { 
      if (XTURN < 0) { 
       XTURN *= -1; 
      } 
      xPrev = e.pageX; 
     //turn right 
     } else { 
      if (XTURN > 0) { 
       XTURN *= -1; 
      } 
      xPrev = e.pageX; 

     } 
     //look up 
     if (e.pageY < yPrev) { 
      if (YTURN < 0) { 
       YTURN *= -1; 
      } 
      yPrev = e.pageY; 
     //look down 
     } else { 
      if (YTURN > 0) { 
       YTURN *= -1; 
      } 
      yPrev = e.pageY; 
     } 

     translationMatrix = new WebKitCSSMatrix("matrix3d(" + cos(XTURN).toFixed(10) + ",0," + sin(XTURN).toFixed(10) + ",0,0,"+ cos(-YTURN).toFixed(10) +","+ sin(YTURN).toFixed(10) +",0, " + sin(-XTURN).toFixed(10) + ","+ sin(-YTURN).toFixed(10) +"," + cos(XTURN).toFixed(10) + ",0,0,0,0,1)"); 

     transformer.style.webkitTransform = translationMatrix.multiply(origMat).toString(); 
    }); 

Come potete vedere (Ci scusiamo per la matrice di una riga) Sto indicando i cambiamenti del X e Le rotazioni di Y sulla stessa matrice cambiano e poi la commettono, il problema ora è con il cos(XTURN).toFixed(10) che può essere correlato alle rotazioni X e Y, quindi puoi vederlo funzionare ma non perfetto. Apprezzerebbero eventuali suggerimenti/idee.

P.S Non voglio utilizzare lo Pointer Lock API, anche se è fantastico, poiché desidero supportare il numero massimo di browser.

+0

Se lo avete a lavorare, si prega di inviare ciò che si cambia in una risposta, o di cancellare la domanda (la risposta sarebbe meglio). – FakeRainBrigand

+0

Non funziona come dovrebbe, quindi non è stato risolto quindi postare una risposta sarebbe la cosa sbagliata da fare. Ho pubblicato una modifica di ciò che è cambiato dalla mia prima domanda. –

+0

Oh, scusa, ho frainteso. Pensavo avessi detto che l'hai risolto. – FakeRainBrigand

risposta

3

Pure JavaScript è in gran parte migliore di librerie (a meno che non si tratta di un "Codice meno fare di più" cosa),
dal puoi capire cosa fa veramente il tuo codice.

Questo è il mio intero codice JavaScript:

var velocity = 0.5; 

document.onmousemove = function(e) { 
    var angleX = e.pageY * velocity * Math.PI/180; 
    var angleY = e.pageX * velocity * Math.PI/180; 
    document.getElementById('transformer').style.webkitTransform = 'matrix3d(' + Math.cos(-angleY) + ',0,' + Math.sin(-angleY) + ',0,' + (Math.sin(angleX)*Math.sin(-angleY)) + ',' + Math.cos(angleX) + ',' + (-Math.sin(angleX)*Math.cos(-angleY)) + ',0,' + (-Math.cos(angleX)*Math.sin(-angleY)) + ',' + Math.sin(angleX) + ',' + (Math.cos(angleX)*Math.cos(-angleY)) + ',0,0,0,0,1)'; 
}; 

E this is the fiddle.

Funziona!

(Ho anche fatto un esempio di questo utilizza l'API Pointer Lock: fiddle (fare clic sul quadrato per iniziare)


Spiegazione:

In primo luogo, una variabile di velocità per impostare facilmente la
Quindi, un evento mousemove impostato con le due variabili di rotazione impostate
L'ultima riga è quella di conversione da rotateX e rotateY trasformazioni, a matrix3d come richiesto. This Stackoverflow question mi ha aiutato ad arrivare alla seguente soluzione.


rotateX(angleX) è uguale alla seguente matrice:

1    0    0    0 


0    cos(angleX)  -sin(angleX) 0 


0    sin(angleX)  cos(angleX)  0 


0    0    0    1 

rotateY(angleY) è uguale alla seguente matrice:

cos(angleY)  0    sin(angleY)  0 


0    1    0    0 


-sin(angleY) 0    cos(angleY)  0 


0    0    0    1 

E per usarli entrambi insieme, è necessario moltiplicare i due matrici. Così ho scritto un piccolo strumento JavaScript per darmi il calcolo che devo fare per ottenere il risultato di questa moltiplicazione.

Il risultato:

cos(angleY)    sin(angleX)*sin(angleY) cos(angleX)*sin(angleY) 0 



0       cos(angleX)    -sin(angleX)    0 



-sin(angleY)    sin(angleX)*cos(angleY) cos(angleX)*cos(angleY) 0 



0       0       0       1 

E questo è il modo per convertire rotateX e rotateY a matrix3d.

Speranza che aiuta :)

+0

Questa è davvero una grande spiegazione, mi ha fatto decidere che questa risposta è la migliore. (anche se @ IcanDivideBy0 aveva la stessa risposta ma meno dettagliata). Mi chiedo se l'uso di quaternioni, come menzionato in altre risposte, contribuisca in modo diverso alla soluzione. (non solo un codice più bello) –

3

Non mi è del tutto chiaro quale sia il tuo obiettivo di alto livello. Sembra che tu stia cercando di implementare un gioco simile a Counterstrike in JS e CSS. Che è fantastico! Per il resto di questa risposta, assumerò che tu stia cercando di fare qualcosa del genere.

Realisticamente, è necessario utilizzare l'API Pointer Lock. Altrimenti, non sarai in grado di girarti muovendo il mouse verso sinistra. Colpisci il bordo della finestra del browser e smetti di girare. Il supporto del browser non è eccezionale, ma è di gran lunga un'esperienza migliore per il giocatore!

Per rendere il tuo mondo con le trasformazioni CSS, devi creare una serie complicata di trasformazioni per generare la matrice per ogni lato di ogni oggetto visibile nel mondo di gioco. Questo perché la prospettiva del browser guarda sempre direttamente lungo l'asse Z. Quindi, per animare le cose "intorno" all'occhio dello spettatore, devi tradurle e ruotarle intorno. Dopo un po 'di curiosità, sono giunto alla conclusione che fare tutte le trasformazioni in CSS è proibitivamente lento (e complicato!). Ma non temere mai, c'è un altro modo! WebGL o Canvas in soccorso!

Dai un'occhiata al gioco di Isaac Sukin Nemesis. È un ottimo esempio e ha scritto un tutorial per inventare qualcosa di simile! La libreria su cui si basa, Three.js, è molto usata e ha un'API molto comprensibile. Ci vuole quasi tutta la parte difficile e ti consente di creare un mondo 3D!

Buona fortuna con il gioco!

+0

Il gioco [Nemsis] (http://icecreamyou.github.io/Nemesis/) collegato non è troppo difficile da controllare anche se non ha il blocco del puntatore. Trasforma il tuo personaggio non con il movimento del mouse ma con la deviazione del mouse dal centro della finestra. Quindi quando il mouse si trova sul lato sinistro dello schermo, continui a girare a sinistra. Scatti anche dove il puntatore è invece diretto. Pointer Lock sarebbe meglio, e sarebbe bello se il gioco di Shahar rilevasse se Pointer Lock fosse supportato e lo usasse in questo caso, ma non lo chiamerei * required *. –

+0

Grazie per la risposta dettagliata, ma in realtà non risolve il problema, spiegherò: sono in grado di ottenere la rotazione X e la rotazione Y separatamente usando il movimento del mouse, come la Nemesis (solo la rotazione Y lì), tuttavia Voglio essere in grado e combinare questi 2 movimenti in modo che l'utente possa sperimentare uno stile FPS guardandosi intorno, spostando l'asse Z sarà fatto con la tastiera quindi nessun problema lì. Per quanto riguarda WebGL, è incredibile che io sia d'accordo ma non rilevante per il mio progetto specifico né per l'obiettivo qui e poiché l'ambiente esistente che non ho creato con Canvas non mi aiuta. –

+0

Oh, ok. Se tutto quello che vuoi fare è ruotare una vista in entrambe le direzioni allo stesso tempo, dovresti fare due trasformazioni su matrix3d ​​(). o ruotare una volta intorno a <1,1,0> (o simile). Dai un'occhiata alla [documentazione di Mozilla per 'rotate3d()'] (https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate3d()) e poi usa quella trasformazione della matrice invece di quello che hai. – tangphillip

2

L'utilizzo di quaternioni è molto più semplice. Ho trovato un'implementazione in Google closure library così ho fatto un esempio (anche, controllare the jsFiddle):

goog.require('goog.vec.Quaternion'); 

var velocity = 0.5; 

var lastX = null; 
var lastY = null; 
var angleX = 0; 
var angleY = 0; 

$(document).on('mousemove', function (e) { 
    if (lastX == null) lastX = e.pageX; 
    if (lastY == null) lastY = e.pageY; 

    angleX += (e.pageX - lastX) * velocity * Math.PI/180; 
    angleY += (e.pageY - lastY) * velocity * Math.PI/180; 

    lastX = e.pageX; 
    lastY = e.pageY; 

    var quat = goog.vec.Quaternion.concat(
     goog.vec.Quaternion.fromAngleAxis(angleX, [0, 1, 0], []), 
     goog.vec.Quaternion.fromAngleAxis(-angleY, [1, 0, 0], []), []); 

    var matrix = goog.vec.Quaternion.toRotationMatrix4(quat, []); 

    $("#transformer").css({ 
     webkitTransform: "matrix3d(" + matrix.join(",") + ")" 
    }); 
}); 
+0

Non sapevo di questa grande biblioteca e la soluzione davvero elegante usandola. Non l'ho ancora messo alla prova, ma sembra che risolva il problema con cui ho avuto problemi e come bonus ho avuto modo di conoscere questa libreria. Potrebbe spiegare ulteriormente l'uso di Quaternion e come si risolve in matrix3d, solo per comprendere appieno il codice e la matematica che c'è dietro, grazie. –

Problemi correlati