Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mouse controlled first person movement JS

I'm trying to implement a first person movement using the mouse. I do have it working with keyboard yet I'm having difficulties implementing it using mouse since movement to a specific side isn't that clear (i.e moving left can include moving up or down). I want to use the matrix3d in order to receive changed values of the position.

EDIT #2 Here is a jsfiddle.

EDIT I've pasted the new code I've managed to resolve:

$(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();
    });

As you can see (Sorry for the one line matrix) I'm stating the changes of the X and Y rotations on the same matrix change and then committing it, the issue now is with the cos(XTURN).toFixed(10) which can be related to the X and Y rotations, so you can see it works but not perfect. Would appreciate any tips/ideas.

P.S I don't want to use the Pointer Lock API, even though it's great, since I want it to support maximal number of browsers.

like image 703
Shahar Galukman Avatar asked Aug 15 '13 11:08

Shahar Galukman


1 Answers

Pure JavaScript is mostly better than libraries (unless it's a "Code less do more" thing),
since you can understand what your code really does.

This is my entire JavaScript code:

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)';
};

And this is the fiddle.

It works!

(I even made an example of this using the Pointer Lock API: fiddle (click the square to begin)


Explanation:

First, a velocity variable to easily set the rotation speed.
Then, a mousemove event which has the two rotation variabls set.
The last line is to convert from rotateX and rotateY transformations, to matrix3d as requested. This Stackoverflow question helped me get to the following solution.


rotateX(angleX) is equal to the following matrix:

1               0               0               0


0               cos(angleX)     -sin(angleX)    0


0               sin(angleX)     cos(angleX)     0


0               0               0               1

rotateY(angleY) is equal to the following matrix:

cos(angleY)     0               sin(angleY)     0


0               1               0               0


-sin(angleY)    0               cos(angleY)     0


0               0               0               1

And to use them both together, you need to multiply the two matrices. So I wrote a small JavaScript tool to give me the calculation I need to do to get the result of this multiplication.

The result:

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

And that's the way to convert rotateX and rotateY to matrix3d.

Hope it helps :)

like image 90
assembly_wizard Avatar answered Sep 19 '22 18:09

assembly_wizard