Libgdx第一人称相机控制

时间:2014-02-17 10:03:46

标签: java camera libgdx

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

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

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

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

3 个答案:

答案 0 :(得分:5)

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

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个旋转,并在yaw向量周围进行cam.up旋转。

答案 1 :(得分:3)

我知道这个问题已经有了很好的答案。但是我对所选答案有些疑问。我只是想帮助那些正在寻找相同解决方案的人。 我注意到所选答案有些奇怪的行为。我没有把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);

编辑:我只想分享我用来改变相机位置的步行功能。当W键关闭时,forward为真。当密钥出现时forward为假。其他方向具有相同的原则。要检测密钥是否向上和向上,请使用上面代码中的InputProcessor 这在二维空间(X-Z轴)中产生运动。我们消除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();
            v.y = 0f;
            v.x *= speed * timeElapsed;
            v.z *= speed * timeElapsed;
            cam.translate(v);
            cam.update();
        }
        if (back) {
            Vector3 v = cam.direction.cpy();
            v.y = 0f;
            v.x = -v.x;
            v.z = -v.z;
            v.x *= speed * timeElapsed;
            v.z *= speed * timeElapsed;
            cam.translate(v);
            cam.update();
        }
        if (left) {
            Vector3 v = cam.direction.cpy();
            v.y = 0f;
            v.rotate(Vector3.Y, 90);
            v.x *= speed * timeElapsed;
            v.z *= speed * timeElapsed;
            cam.translate(v);
            cam.update();
        }
        if (right) {
            Vector3 v = cam.direction.cpy();
            v.y = 0f;
            v.rotate(Vector3.Y, -90);
            v.x *= speed * timeElapsed;
            v.z *= speed * timeElapsed;
            cam.translate(v);
            cam.update();

        }
    }

答案 2 :(得分:2)

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

  1. rotateYaw(float degrees):将Vector3 direction围绕Y-Axis旋转给定度数(libgdx具有Vector3的旋转功能) - &gt;简单
  2. rotatePitch(float degrees):按照给定的度数旋转Vector3 direction围绕direction.cross(Vector3.Y),即MovingObject的旋转侧矢量。另外,Pitch-Rotation必须旋转upVector,因此您可以按照给定的度数围绕同一轴旋转upVector。一旦你明白这一点就很简单。
  3. move(delta)通过以下方式移动MovingObject x,z方向:

    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);
    }
    
  4. 直到现在我才对此进行测试,但我认为它应该可行。请注意,在Pitch-rotation中,您还应将其限制为直线上升/下降。通过检查x和z的符号来完成此操作。如果他们在你做Pitch-rotation时你改变了,你旋转了90度。 我等待其他答案,如果我错了,请纠正我!

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

    1. direction.cross(upVector)更改direction向量。所以先将数据存储在某个地方!使用后重置方向Vector。
    2. Pitch限制有一个问题:如果你控制了signum的变化,我建议发生以下情况:你直视,signum x和signum z是0.你向下看,signum变化,你的动作(限制)开始。所以请注意,如果它不是零,你也要检查。 我不知道怎么做音高限制,我编辑我的问题来解释我的问题。
    3. 每当您更改内容时,请考虑规范化directionupVector
    4. 我认为这应该会很好。如果您有任何改进,请告诉我,我会在此更新。如果您有其他解决方案,请添加答案!感谢