Mouse controlled first person movement JS

css, javascript, jquery

Solution

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 :)

Problem

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.

Original source

Related problems