Search code examples
c#unity-game-enginequaternions

How can I do this kind of 3D camera movement in Unity?


This is a school project. I have a big cube which is like a planet. I have a small cube that can move on every side of the cube planet. The player moves forward automatically on its local z axis and I rotate it by 90 or -90 degrees to move left or right- but the player can control it like it's an up-down-left-right movement (made a script so they don't have to rotate the cube with 2 keys). It's like a Tron game so if I press the up key, I can't press down immediately because I leave a trail so I have to press the left or right keys. I have a problem with my camera movement. The camera follows the little cube from above, but I want it to lean a little when the little cube player gets close to the edge of a side so it lets me see the other side - where I'm planning to go.

I have a script where I use the center of the cube planet and the player's center as the direction vector and multiply it with the camera-player distance.

Vector3 direction = (target.position - center.position).normalized;         
transform.position = target.position + direction * distance;

Then I point my camera's forward vector to the player cube's direction. I tried two codes but none of them worked perfectly. First I tried to rotate the camera with:

transform.rotation = Quaternion.LookRotation(-direction); 

Shown in video. The problem with this is that since I don't tell the program the Up and Right vectors (I think), it sets them for itself to some random numbers so the camera sometimes do its own thing like it does a pirouette.

Next I tried this:

Quaternion rot = Quaternion.FromToRotation(transform.forward, -direction);                                                                          
transform.Rotate(rot.eulerAngles, Space.World); 

Shown in video. It's almost good but as the little cube moves, the camera starts steering slightly in the beginning and it gets worse and worse.

Do you have any ideas how can I make it work? I hope you understand what I would like to achieve. I'm trying to set the camera as to always show that when I press Up, my cube moves upward, when I press Right my cube always goes right etc. and when I reach the edge of my side the camera leans a bit towards the side I'm moving to.


Solution

  • Use dot product to find which orthogonal direction of your cube is closest to the camera's current up.

    Vector3 closestToUp;
    float greatestDot = 0f;
    foreach (Vector3 dir in new Vector3[]{
            target.forward, target.right, -target.forward, -target.right})
    {
        float curDot = Vector3.Dot(dir,transform.up);
        if (curDot > greatestDot) 
        {
            greatestDot = curDot;
            closestToUp = dir;
        }
    }
    

    Than, use that direction as the second parameter of Quaternion.LookRotation. This will keep its local up direction as aligned with the cube's "top" as possible given whatever new forward direction:

    transform.rotation = Quaternion.LookRotation(-direction, closestToUp);