Libgdx第一人称相机控制

我刚刚开始在libgdx中使用3D进行游戏。 我已经知道如何绘制基本Model ,我CameraControllerCameraControllerCameraController 。 现在我想创建一个FirstPersonCameraFirstPersonCameraController 。 我考虑过扩展PerspectiveCameraMyMovingObject target添加一个MyMovingObject targetMyMovingObject将保持x, y, z position ,其中y是一个常数值,因为此刻我无法up/down移动。 所以我的动作基本上是2D。 MyMovingObject还会存储其moving direction / xSpeed, zSpeed所需的left/right rotation 。 但是Player也应该能够向上和向下查看,而MyMovingObject并不需要这种向上/向下旋转,因为它只会改变视图而不会改变其他属性。 所以我不确定我是否走正确的路。
我希望能够通过使用W,A,S,D向前,向左,向右,向后W,A,S,D并使用鼠标向左旋转。 此外,我想通过使用鼠标来上下打量,就像大多数First Person游戏一样。
我应该使用另一种方式,而不是通过扩展PerspectiveCamera创建我自己的相机? 或者这种方法是否良好,我只需要在MyMovingObject存储向上/向下旋转,如果只需要视图?
或者用W,A,S,D and mouse控制相机并根据相机的位置和旋转更新MyMovingObject的位置会更好吗?
我希望你明白我的意思。 解释它似乎有点复杂(至少对我而言)。

编辑:我现在使用Vector3 directionVector3 positionVector3 size为我的NPC和播放器。 我通过这样做来计算速度: xSpeed = direction.x / (direction.x + direction.z) * speed; zSpeed也一样。 通过这样做,我“过滤”了它的y值,我只得到x和y的百分比。 唯一的问题是,当我直视xz0 。 我可以通过使用UpVecotr解决这个UpVecotr ,当我进行“俯仰旋转”时,它会旋转。 但我怎么旋转他? 我需要在侧面矢量旋转它。 谢谢

编辑:旋转和运动现在工作(参见我的答案),但我对“俯仰旋转”的限制有很大的问题。 我正在使用: if (direction.y 1) doPitchRotation(); else if (direction.y > -0.9 && angle < 1) doPitchRotation(); if (direction.y 1) doPitchRotation(); else if (direction.y > -0.9 && angle < 1) doPitchRotation(); 所以,如果我向下旋转,我仍然低头至少在-0.9 y,它只是不执行旋转。 但究竟发生了什么:我旋转到-0.9然后它旋转到Y轴周围,而另一侧它旋转起来,即使我移动我的mous。 你能解释一下原因吗? 当我向下看时,为什么Y轴会翻转?

编辑:它现在有效。 看起来我的upVector有时会得到一些错误的值。 对于陆基凸轮,您还可以使用Y轴和方向矢量的交叉产品。 不需要upVector。

嘿谢谢分享这个链接。 我发现它非常有用。 这是我的旋转陆基相机的代码,它似乎没有问题。

 private int mouseX = 0; private int mouseY = 0; private float rotSpeed = 0.2f; @Override public boolean mouseMoved(int screenX, int screenY) { int magX = Math.abs(mouseX - screenX); int magY = Math.abs(mouseY - screenY); if (mouseX > screenX) { cam.rotate(Vector3.Y, 1 * magX * rotSpeed); cam.update(); } if (mouseX < screenX) { cam.rotate(Vector3.Y, -1 * magX * rotSpeed); cam.update(); } if (mouseY < screenY) { if (cam.direction.y > -0.965) cam.rotate(cam.direction.cpy().crs(Vector3.Y), -1 * magY * rotSpeed); cam.update(); } if (mouseY > screenY) { if (cam.direction.y < 0.965) cam.rotate(cam.direction.cpy().crs(Vector3.Y), 1 * magY * rotSpeed); cam.update(); } mouseX = screenX; mouseY = screenY; return false; } 

这适用于陆基相机。 如果你想制作一个flightcontroll相机,你必须在cam.direction.crs(cam.up)做一个音高旋转。 而不是使用Vector3.cpy()我将存储一个Vector3 help ,它获取那些临时值,因为Vector3.cpy()创建一个新的Vector3并且每个渲染循环执行此操作。 对于flightcontroll相机,您还需要添加roll旋转并在cam.up Vector cam.up进行yaw旋转。

这篇文章在我看来真的很有帮助。 我找到了一个应该有效的解决方案,但我还没有尝试过。 我的MovingObject都有Vector3 positionVector3 directionVector3 sizeVecotr3 upVectorPlayer类扩展了此MovingObject类,并将MouseKeycontroll添加到移动中。 在MovingObject类中,我有moethods:

  1. rotateYaw(float degrees) :将Y-AxisVector3 direction旋转给定度数(libgdx具有Vector3的旋转function) – >简单
  2. rotatePitch(float degrees) :以给定的度数围绕: direction.cross(Vector3.Y)旋转Vector3 directiondirection.cross(Vector3.Y)的旋转侧Vector。 Pitch-Rotation也必须旋转upVector ,因此您可以使用给定的度数围绕同一轴旋转upVector 。 一旦你明白这一点就很简单。
  3. move(delta)通过执行以下MovingObjectx,z方向上移动MovingObject

     if (direction.y == 1) { // You are looking straight up, no x,z direction, move in the opposite // direction of upVector xSpeed = upVector.x / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * (-speed); zSpeed = upVector.z / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * (-speed); position.add(xSpeed * delta, 0, ySpeed * delta); } else if (direction.y == -1) { // You are looking straight down, no x,z direction, move in the direction of // upVector xSpeed = upVector.x / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * speed; zSpeed = upVector.z / (Math.abs(upVetor.x) + Math.abs(upVector.z)) * speed; position.add(xSpeed * delta, 0, ySpeed * delta); } else { // You are not looking straight up or down, so you have x,z direction. Use // that. xSpeed = direction.x / (Math.abs(direction.x) + Math.abs(direction.z)) * speed; zSpeed = direction.z / (Math.abs(direction.x) + Math.abs(direction.z)) * speed; position.add(xSpeed * delta, 0, ySpeed * delta); } 

直到现在我才对此进行测试,但我认为它应该可行。 请注意,在Pitch-rotation您还应将其限制为直线向上/向下直线。 通过检查x和z的符号来完成此操作。 如果它们在进行Pitch-rotation时发生变化,则旋转超过90度。 我等待其他答案,如果我错了,请纠正我!

编辑:我测试了它。 它的工作原理如下,但有几点需要注意:

  1. direction.cross(upVector)改变direction Vector。 所以先将数据存储在某个地方! 使用后重置方向Vector。
  2. Pitch限制有一个问题:如果你控制了signum的变化,我建议发生以下情况:你直视,signum x和signum z是0.你向下看,signum变化,你的动作(限制)开始。 所以请注意,如果它不是零,你也要检查。 我不知道怎么做音高限制,我编辑我的问题来解释我的问题。
  3. 想想在你改变什么的时候规范你的directionupVector

我认为这应该工作得很好。 如果您有任何改进,请告诉我,我会在此更新。 如果您有其他解决方案,请添加答案! 谢谢

我知道这个问题已经有了很好的答案。 但是我对所选答案有些疑问。 我只是想帮助那些正在寻找相同解决方案的人。 我注意到所选答案有些奇怪的行为。 我没有把Y exis保持为正常状态。 这对fps来说当然非常重要。 所以这个并不完美,但我想把它放在这里。

 // put into the create() method. Gdx.input.setInputProcessor(new InputProcessor() { private int dragX, dragY; float rotateSpeed = 0.2f; // dont' forget to override other methods. @Override public boolean mouseMoved(int screenX, int screenY) { Vector3 direction = cam.direction.cpy(); // rotating on the y axis float x = dragX -screenX; // change this Vector3.y with cam.up if you have a dynamic up. cam.rotate(Vector3.Y,x * rotateSpeed); // rotating on the x and z axis is different float y = (float) Math.sin( (double)(dragY -screenY)/180f); if (Math.abs(cam.direction.y + y * (rotateSpeed*5.0f))< 0.9) { cam.direction.y += y * (rotateSpeed*5.0f) ; } cam.update(); dragX = screenX; dragY = screenY; return true; } }); 

注意:请勿使用任何相机控制器。
注2:这可能很方便: Gdx.input.setCursorCatched(true);

编辑:我只是想分享我用来改变相机位置的步行function。 当W键关闭时, forward为真。 而当钥匙forward是错误的。 其他方向具有相同的原则。 要检测密钥是否向上和向上,请使用上面代码中的InputProcessor
这在二维空间(XZ轴)中产生运动。 由于我们正在消除Y轴,因此摄像机的方向不会改变运动方向。 的方向。
现在必须将相机对准天空(与地面成90度角),方向矢量的长度不固定为1.0f 。 因此不会有任何移动速度的损失。 为了测试这一点,我上下旋转相机(向前和向后移动鼠标),方向矢量的x和z值没有改变。 因此,当消除方向矢量的y轴时,我们有一个2d方向矢量,它不受相机Y角度的影响。

 private void walking(float timeElapsed) { float speed = movementSpeed; if ((forward | back) & (right | left)) { speed /= Math.sqrt(2); } System.out.println(speed); if (forward) { Vector3 v = cam.direction.cpy(); vy = 0f; vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } if (back) { Vector3 v = cam.direction.cpy(); vy = 0f; vx = -vx; vz = -vz; vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } if (left) { Vector3 v = cam.direction.cpy(); vy = 0f; v.rotate(Vector3.Y, 90); vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } if (right) { Vector3 v = cam.direction.cpy(); vy = 0f; v.rotate(Vector3.Y, -90); vx *= speed * timeElapsed; vz *= speed * timeElapsed; cam.translate(v); cam.update(); } }