Libgdx first person camera controll

…衆ロ難τιáo~ 提交于 2019-12-04 07:53:17
Guest

Hey thanks for sharing this link. I found it very useful. Here's my code on rotating a land based camera and it seems to work without problems.

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;
}

This works for landbased cameras. If you want to make a flightcontroll camera, you have to do a pitch rotation arround the cam.direction.crs(cam.up). Instead of using the Vector3.cpy() i would store a Vector3 help, which gets those temporary values, because Vector3.cpy() creates a new Vector3 and this operation is performed every render loop. For flightcontroll cameras you also need to add a roll rotation and do the yaw rotation arround the cam.up Vector.

I know that this question already has good answers. But I had some issues with the selected answer. And I just want to help someone who is looking for the same solution. I noticed some strange behaviour with the selected answer. I doesn't keep the Y exis as up. Which is of course very important on a fps. So this one is not perfect but I wanted to put this here.

// 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;
        }

    });

NOTE: Don't use any camera controllers.
NOTE2: This might come handy: Gdx.input.setCursorCatched(true);

EDIT: I just wanted to share the walking function I use to change position of the camera with wasd keys. When W key is down the forward is true. And when the key is up forward is false. Other directions have the same principle. To detect the key down and up, please use the InputProcessor in the above code.
This creates movement in the two dimensional space (X-Z axises). The direction of the camera will not change the direction of the movement as we are eliminating the Y axis. of the direction.
One must now even if camera is directed to the sky (at a non 90 degree angle with the ground), the length of the direction vector is not fixed to 1.0f. So there will not be any loss of movement speed. To test this I rotated camera up and down (moved the mouse forward and backward) and the x and z values of the direction vector didn't change. So when the y axis of the direction vector is eliminated, we have a 2d direction vector which doesn't effected by the Y angle of the camera.

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

        }
    }

This article is really helpful in my opinion. I have found a solution which should work, but i haven't tryed it yet. My MovingObjects all have a Vector3 position, Vector3 direction, Vector3 size and Vecotr3 upVector. The Player class extends this MovingObject class and adds Mouse and Keycontroll to the movement. In the MovingObject class i have the moethods:

  1. rotateYaw(float degrees): rotates the Vector3 direction arround the Y-Axis by the given degrees (libgdx has a rotate function for Vector3)--> Simple
  2. rotatePitch(float degrees): rotates the Vector3 direction arround the: direction.cross(Vector3.Y), which is the rotated side Vector of your MovingObject, by the given degrees. Also a Pitch-Rotation has to rotate the upVector, so you rotate the upVector arround the same axis, by the given degrees. As soon as you understand this it is simple.
  3. move(delta) moves your MovingObject in x,z direction by doing:

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

I did not test this until now, but i think it should work. Note, that in the Pitch-rotation you should also limit it to straight up/ straight down. Do this by checking the signum of x and z. If they change while you are doing a Pitch-rotation you rotated over 90 degrees. I am stil waiting for other answers and if i am wrong please correct me!

EDIT: I tested it. It works like this, but there are a few things to take care of:

  1. direction.cross(upVector) changes the direction Vector. So store that data somewhere first! After using it reset the direction Vector.
  2. The Pitch limitation has a problem: If you controll signum change, as i suggested the following happens: you look straight up, signum x and signum z are 0. You look down, signum changes and your action (limiting) starts. So take care that you also check, if it is not zero. I stil don't know how to do the pitch limitation and i edit my question to explain my issue.
  3. Think about normalizing your direction and upVector whenever you change something!

I think this should work pretty good. If you have any improvements let me know and i will update this here. If you have another solution please add an answer! Thanks

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!