2013-08-15 4 views
10

마우스를 사용하여 1 인칭 동작을 구현하려고합니다. 키보드로 작업해도 마우스를 사용하여 구현하는 데 어려움이 있습니다. 특정면으로의 이동이 명확하지 않아서 (즉, 왼쪽으로 움직이는 것이 위 또는 아래로 움직이는 것을 포함 할 수 있기 때문입니다.) 변경된 위치 값을 받으려면 matrix3d을 사용하고 싶습니다.마우스로 제어되는 1 인칭 동작 JS

편집 # 2 여기는 jsfiddle입니다.

편집는 내가 해결하기 위해 관리했습니다 새 코드를 붙여 넣은 :

$(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 행렬을 바꾼 다음 커밋하면 이제는 X 및 Y 회전과 관련 될 수있는 cos(XTURN).toFixed(10)을 사용하여 문제가 해결됩니다. 그러나 완벽하지는 않습니다. 팁/아이디어를 주시면 감사하겠습니다.

피씨 나는 최대한의 브라우저를 지원하기를 원하기 때문에 Pointer Lock API을 사용하고 싶지 않습니다.

+0

바랍니다. – FakeRainBrigand

+0

따라서 해결되지 않아야하므로 제대로 작동하지 않습니다. 따라서 답변을 게시하면 잘못 될 수 있습니다. 첫 번째 질문 이후 변경된 내용을 게시했습니다. –

+0

아, 죄송합니다. 오해했습니다. 네가 네가 해결했다고 말한 줄 알았는데. – FakeRainBrigand

답변

3

순수 자바 스크립트 라이브러리보다 대부분 더 나은을하기 때문에,
을 (그것은 일 "코드가 덜 더을"않는 한) 코드가 실제로 무엇을하는지 이해할 수 있습니다.

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를 사용하여이 예를했다

: fiddle은 (시작하기 위해 사각형을 클릭)를


설명 :

첫째, 속도 변수를 쉽게 설정할 수있는
두 개의 회전 변수가 설정된 mousemove 이벤트
마지막 줄은 rotateX과로 변환됩니다.변환을 요청하면 matrix3d으로 변경됩니다. This Stackoverflow question 다음 솔루션을 얻는 데 도움이되었습니다.

1    0    0    0 


0    cos(angleX)  -sin(angleX) 0 


0    sin(angleX)  cos(angleX)  0 


0    0    0    1 

rotateY(angleY)는 다음의 행렬과 같다 :


rotateX(angleX)는 다음의 행렬과 같다

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 

그리고 그 matrix3drotateXrotateY 변환하는 방법입니다.

은 도움이 :) 당신이 그것을 작동하는 경우, 당신이 대답에 변경 무엇을 게시하거나 질문 (답변이 더 나은 것)을 삭제하시기 바랍니다

+0

이것은 정말 좋은 설명입니다.이 대답이 더 나은 결정이라고 생각하게 만들었습니다. (비록 @ IcanDivideBy0가 동일한 대답을 가지고 있지만 덜 상세 함). 다른 답변에서 언급 한 것처럼 쿼터니언의 사용이 솔루션과 다른 방식으로 기여하는지 궁금합니다. (더 멋진 코드가 아님) –

3

귀하의 높은 목표가 무엇인지는 분명하지 않습니다. JS 및 CSS에서 Counterstrike와 유사한 게임을 구현하려는 것 같습니다. 어느 것이 굉장합니다! 이 답변의 나머지 부분에 대해서는, 당신이 그런 것을하려고한다고 가정 할 것입니다.

현실적으로, 포인터 잠금 API를 사용해야합니다. 그렇지 않으면 마우스를 왼쪽으로 움직여서 방향을 바꿀 수 없습니다. 브라우저 창 가장자리를 치고 회전을 멈 춥니 다. 브라우저 지원은 좋지 않지만 게이머에게는 훨씬 좋은 경험입니다!

CSS 변환으로 세계를 렌더링하려면 게임 세계에서 볼 수있는 모든 객체의 모든면에 대해 행렬을 생성하기 위해 복잡한 일련의 변형을 수행해야합니다. 이는 브라우저의 관점이 항상 Z 축을 따라 직접보고 있기 때문입니다. 따라서 시청자의 눈을 "주변에서"움직이게하려면 주위를 번역하고 회전해야합니다. 약간의 파고 끝에 CSS에서 모든 변형을하는 것이 매우 느리고 복잡하다는 결론에 도달했습니다. 그러나 결코 두려워하지 마십시오, 또 다른 방법이 있습니다! WebGL 또는 Canvas를 구출하십시오!

Isaac Sukin의 게임 Nemesis을보세요. 훌륭한 예입니다. 그는 비슷한 것을 생각해 내기 위해 tutorial을 작성했습니다. Three.js를 기반으로하는 라이브러리는 매우 널리 사용되고 있으며 매우 이해하기 쉬운 API를 가지고 있습니다. 거의 모든 어려운 부분을 제거하고 3D 세계를 만들 수 있습니다!

게임에 대한 행운을 비세요!

+0

링크 된 게임 [Nemsis] (http://icecreamyou.github.io/Nemesis/)는 포인터 잠금 기능이 없어도 제어가 어렵지 않습니다. 당신은 당신의 캐릭터를 마우스 움직임이 아닌 마우스 중앙에서 벗어난 마우스로 돌립니다. 마우스가 스크린의 왼쪽에있을 때, 당신은 왼쪽으로 돌고 있습니다. 포인터는 똑바로 앞으로가 아닌 위치에서 촬영합니다. 포인터 잠금이 더 좋을 것입니다. 만약 Shahar의 게임이 Pointer Lock이 지원된다면 그것을 감지하고 사용한다면 좋을 것입니다.하지만 필자는 그것을 * required *라고 부르지 않을 것입니다. –

+0

아직 정말 내 문제가 해결되지 상세 답변을 주셔서 감사합니다, 나는 설명 할 것이다 : 나는 네메시스 (거기에만 Y 회전)와 같은 마우스의 움직임을 이용하여 별도로 X 회전 및 Y 회전을 달성 할 수있어, 그러나 나는이 두 움직임을 가능하고 결합하여 사용자가 주위를 바라 보는 FPS 스타일을 경험할 수 있기를 바랍니다. Z 축을 따라 움직이면 키보드로 아무런 문제가 없습니다. WebGL에 관해서는 동의하고 있지만 특정 프로젝트 나 목표와 관련이 없으며 Canvas를 사용하여 생성하지 않은 기존 환경이 나와도 도움이되지 않습니다. –

+0

오, 알겠습니다. 한 번에 양방향으로 뷰를 회전시키고 싶다면 matrix3d ​​()에서 두 개의 변형을 수행해야합니다. 또는 <1,1,0> (또는 이와 유사한) 주위를 한 번 회전하십시오. [) (모질라 ROTATE3D '문서'상기에서보세요 (https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate3d()), 그리고, 그 매트릭스 변환을 사용 네가 가진 것 대신에. 나는 ROTATE3D (인식 할 @tangphillip – 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의 사용법과 matrix3d ​​로의 해결 방법에 대해 더 자세히 설명해 주시겠습니까? 코드 및 수학에 대한 이해를 완전히하기 위해, 감사합니다. –

관련 문제