Tomáš Zato
Tomáš Zato

Reputation: 53307

TransformDirection not behaving as expected when creating RTS camera

I'm trying to create a RTS game from scratch using Unity engine. I started with this Unity RTS game tutorial and I'm setting up the camera. Basically what I do is, that I generate [x,0,z] vector for movement. I then need to apply it on camera.

It works perfectly if the camera isn't rotated - but it usually IS rotated and must be rotatable.

According to the tutorial and the docs, I can transform vector to camera's point of view using Camera.main.transform.TransformDirection(MyVector). Which is what I do:

    //Get mouse position
    float xpos = Input.mousePosition.x;
    float ypos = Input.mousePosition.y;
    //Create vector for movement
    Vector3 movement = new Vector3(0, 0, 0);

    //horizontal camera movement
    if (xpos >= 0 && xpos < ResourceManager.ScrollWidth)
    {
        movement.x -= ResourceManager.ScrollSpeed;
    }
    else if (xpos <= Screen.width && xpos > Screen.width - ResourceManager.ScrollWidth)
    {
        movement.x += ResourceManager.ScrollSpeed;
    }
    //vertical camera movement
    if (ypos >= 0 && ypos < ResourceManager.ScrollWidth)
    {
        movement.z -= ResourceManager.ScrollSpeed;
    }
    else if (ypos <= Screen.height && ypos > (Screen.height - ResourceManager.ScrollWidth))
    {
        movement.z += ResourceManager.ScrollSpeed;
    }

    //make sure movement is in the direction the camera is pointing
    //but ignore the vertical tilt of the camera to get sensible scrolling
    movement = Camera.main.transform.TransformDirection(movement);
    //Up/down movement will be calculated diferently
    movement.y = 0;

However, if I do this, the vertical movement doesn't work for the inital camera rotation, and when I rotate camera, the movement happens at strange speeds.

How can I properly apply the movement vector on camera?

Upvotes: 1

Views: 1999

Answers (1)

Bunny83
Bunny83

Reputation: 1119

Well, the problem here is that TransformDirection will preserve the lenth of the vector. So if you tilt the camera downwards the overall length get distributed between the y, x and z axis. Since you simply eliminate the y part the vector will get shorter. The more the camera is tilted the more you will lose on the other two axes.

It's usually easier to just rotate a unit vector, modify it as you want and normalize it when done. This unit vector can then be scaled by your actual movement vector. Something like that:

// [...]
Vector3 forward = Camera.main.transform.forward;
Vector3 right = Camera.main.transform.right;
forward.y = 0f;
right.y = 0f;  // not needed unless your camera is also rotated around z
movement = forward.normalized * movement.z + right.normalized * movement.x;
// [...]

Another approach is to seperate your two rotations. So by using an empty GameObject that is only rotated around y and have the camera a child of that gameobject. Now the camera will only be rotated around the local x axis to tilt it the way you want. To lat the camera look into a different direction you rotate the empty GameObject around y. That way you can use the transform of the empty GameObject to transform the direction just the way you did in your code since the tilt of the camera doesn't matter.

Upvotes: 2

Related Questions