2013-08-15 4 views
10

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

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 Я не хочу использовать Pointer Lock API, хотя это здорово, так как я хочу, чтобы он поддерживал максимальное количество браузеров.

+0

Если он работает, пожалуйста, напишите, что вы изменили в ответе, или удалить вопрос (ответ будет лучше). – FakeRainBrigand

+0

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

+0

О, извините, я неправильно понял. Я думал, ты сказал, что решил. – FakeRainBrigand

ответ

3

Pure JavaScript в основном лучше, чем библиотеки (если только это не «код меньше делать больше» вещь),
так вы можете понять, что действительно делает ваш код.

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

И this is the fiddle.

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

(я даже сделал пример этого с помощью API Pointer Lock: fiddle (нажмите квадрат, чтобы начать)


Объяснение:

Во-первых, переменная скорость легко установить скорость вращения
Затем, событие mousemove, которое имеет два варианта поворота.
Последняя строка должна конвертировать из rotateX и rotateY, до matrix3d в соответствии с запросом. This Stackoverflow question помог мне перейти к следующему решению.


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.

Надеется, что это помогает :)

+0

Это действительно замечательное объяснение. Сделал мне решение, что этот ответ лучше. (хотя @ IcanDivideBy0 имел такой же ответ, но менее подробный). Интересно, влияет ли использование кватернионов, как упоминалось в других ответах, другим способом решения. (не только более удобный код) –

3

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

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

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

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

Удачи вам в игре!

+0

Увлекательная игра [Nemsis] (http://icecreamyou.github.io/Nemesis/) не слишком сложна, даже если у нее нет блокировки указателя. Вы поворачиваете своего персонажа не с движением мыши, а с отклонением мыши от центра окна. Поэтому, когда мышь находится в левой части экрана, вы продолжаете поворачивать налево. Вы также стреляете, где указатель вместо прямого. Pointer Lock был бы лучше, и было бы неплохо, если бы игра Shahar обнаружила, если Pointer Lock был поддержан и использовал его, если так, но я бы не назвал его * required *. –

+0

Благодарим вас за подробный ответ, но он действительно не разрешает мою проблему. Я объясню: я могу добиться вращения X и вращения Y отдельно с помощью движения мыши, так же как и Nemesis (только вращение Y там), но Я хочу быть в состоянии и объединить эти 2 движения, так что пользователь будет испытывать стиль FPS, оглядываясь вокруг, перемещение по оси Z будет выполняться с помощью клавиатуры, поэтому никаких проблем нет. Что касается WebGL, удивительно, что я согласен, но не уместен для своего конкретного проекта или цели здесь, и поскольку существующая среда, которую я не создал с помощью Canvas, это тоже не помогает. –

+0

О, ладно. Если все, что вы хотите сделать, это поочередно поворачивать представление в обоих направлениях, нужно либо сделать две преобразования на матрице3d(). или поверните один раз около <1,1,0> (или аналогичный). Взгляните на [документацию Mozilla для 'rotate3d()'] (https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate3d()), а затем используйте преобразование матрицы а не тот, который у вас есть. – tangphillip

2

Использование кватернионов действительно проще. Я нашел применение в Google closure library, так что я сделал пример (также, проверить 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

Не знал об этой замечательной библиотеке, и решение действительно изящно использовало ее. Не поставили его на тест, но, похоже, он решил проблему, с которой я столкнулся, и в качестве бонуса я познакомился с этой библиотекой. Не могли бы вы объяснить это, хотя использование Quaternion и то, как он разрешает матрицу3d, просто чтобы полностью понять код и математику за ним, спасибо. –

Смежные вопросы