Мышь контролируется движением первого лица JS

Я пытаюсь реализовать движение первого лица с помощью мыши. У меня есть работа с клавиатурой, но у меня возникают трудности с ее использованием с помощью мыши, поскольку перемещение на определенную сторону не так ясно (например, перемещение влево может включать перемещение вверх или вниз). Я хочу использовать matrix3d для получения измененных значений позиции.

EDIT # 2 Вот jsfiddle.

EDIT Я вставил новый код, который мне удалось решить:

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

Как вы можете видеть (Извините за матрицу с одной строкой), я указываю изменения поворотов X и Y при одном и том же изменении матрицы, а затем фиксируя это, теперь проблема связана с cos(XTURN).toFixed(10), которая может быть связана к поворотам X и Y, поэтому вы можете видеть, что это работает, но не идеально. Почитал бы любые советы/идеи.

P.S Я не хочу использовать API-указатель указателей, хотя это здорово, так как я хочу, чтобы он поддерживал максимальное количество браузеров.

Ответ 1

Чистый JavaScript в основном лучше, чем библиотеки (если только это не означает "Code less do more" ),
так как вы можете понять, что действительно делает ваш код.

Это мой весь код 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)';
};

И это скрипка.

Это работает!

(Я даже сделал пример этого с помощью API-указателей с указателем: fiddle (нажмите квадрат для начала)


Пояснение:

Во-первых, переменная скорости, чтобы легко установить скорость вращения.
Затем выполняется событие mousemove, в котором установлены два параметра поворота.
Последняя строка состоит в преобразовании из преобразований rotateX и rotateY в matrix3d по запросу. fooobar.com/questions/72560/...


rotateX(angleX) равна следующей матрице:

1               0               0               0


0               cos(angleX)     -sin(angleX)    0


0               sin(angleX)     cos(angleX)     0


0               0               0               1

rotateY(angleY) равна следующей матрице:

cos(angleY)     0               sin(angleY)     0


0               1               0               0


-sin(angleY)    0               cos(angleY)     0


0               0               0               1

И чтобы использовать их вместе, вам нужно умножить две матрицы. Поэтому я написал небольшой инструмент JavaScript, чтобы дать мне расчет, который мне нужно сделать, чтобы получить результат этого умножения.

Результат:

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

И это способ преобразования rotateX и rotateY в matrix3d.

Надеюсь, это поможет:)

Ответ 2

Мне не совсем понятно, какова ваша цель на высоком уровне. Похоже, вы пытаетесь реализовать подобную Counterstrike игру в JS и CSS. Это потрясающе! Для остальной части этого ответа я собираюсь предположить, что вы пытаетесь сделать что-то подобное.

Реально, вы должны использовать API блокировки указателей. В противном случае вы не сможете обойтись, только перемещая мышь влево. Вы попадете в край окна браузера и перестанете поворачиваться. Поддержка браузера невелика, но это, безусловно, лучший опыт для геймера!

Чтобы преобразовать ваш мир в CSS-преобразования, вам нужно сделать сложную серию преобразований для генерации матрицы для каждой стороны каждого объекта, видимого в игровом мире. Это связано с тем, что перспектива браузера всегда смотрит прямо вдоль оси Z. Поэтому, чтобы оживить "вокруг" глаз зрителя, вы должны перевести и повернуть их вокруг. После некоторого разговора я пришел к выводу, что выполнение всех преобразований в CSS является чрезмерно медленным (и сложным!). Но никогда не бойтесь, там другой путь! WebGL или Canvas для спасения!

Взгляните на игру Исаака Сукина Nemesis. Это отличный пример, и он написал учебник, чтобы придумать что-то подобное! Библиотека, основанная на ней, Three.js, очень широко используется и имеет очень понятный API. Это занимает почти всю сложную часть, и позволяет вам просто создавать 3D-мир!

Удачи в игре!

Ответ 3

Использование кватернионов действительно проще. Я нашел реализацию в Google закрывающей библиотеке, поэтому я сделал пример (также проверьте 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(",") + ")"
    });
});

Ответ 4

Вот моя конструкция на эту тему, если она кому-нибудь поможет в моей нынешней программе для 3d-моделирования, в ней не хватает только масштаба...: P https://twitter.com/necasjanz Также это мой первый пост о stackoverflow, ожидающий изучения и помогите тоже так весело :).

var objMatrix = [];
 var MDN = MDN || {};
MDN.matrixArrayToCssMatrix = function (array) {
  return "matrix3d(" + array.join(',') + ")";
}   

    var angX=Rx,angY=Ry,
            MCpx=Math.cos(angX * Math.PI / 180),
            MSpx=Math.sin(angX * Math.PI / 180),
            MSnx=Math.sin(-angX * Math.PI / 180),
            MCpy=Math.cos(angY * Math.PI / 180),
            MSpy=Math.sin(angY * Math.PI / 180),
            MSny=Math.sin(-angY * Math.PI / 180);
        if (matrix==true) {
            a1= MCpy,
            a2 = MSpx*MSpy,
            a3= MCpx*MSpy,
            a6 = MCpx,
            a7 = MSnx,
            a9 = MSny,
            a10 = MSpx*MCpy,
            a11 = MCpx*MCpy;
             }

            objMatrix = [
            a1,   a2,    a3,   a4,
            a5,   a6,    a7,   a8,
            a9,   a10,   a11,   a12,
            a13,    a14,    a15,   a16
        ];
        return objMatrix;
        }

    // put this code in to a loop like setInterval or animeframe 
    matrix(objMatrix); // float matrix
    var matrixToCSS = MDN.matrixArrayToCssMatrix( matrix(objMatrix) ); // translate raw matrix to css startdart
    obj.style.transform = matrixToCSS; // object to transform