Fixed Camera Scene a la FF7 or Resident Evil style

I’ve been putting together an RPG reminiscent of the Final Fantasy games but I’m having a very difficult time trying to get a fixed camera to work correctly.

The Black Tower game (unfortunately no longer in production) was built in Unity and has the exact kind of Camera setup I want:

It shows walking around in the town around 1:38 time mark.

I have my fixed camera using LookAt for the player but I can’t figure out how to stop it from revealing the end of the map. In that video, the camera follows the player but stops once it reaches the end of the scene and the player continues on.

If anyone can point me in the right direction, it would be much appreciated.

2 Answers

2

If you want to keep the Y and Z rotation constant (and zero I guess), so the ‘horizion’ appears always as a straight line, and it’s always facing say north, you’re going to have to move the camera around with the player, at least in the X and Z planes, while keeping it’s Y coordinates (height) constant, to create a constant 60 degrees diagonal view.

So given the player’s position (this example makes the camera look from south to north (from Vector3.back to Vector3.forward), in a 60 degree angle:

void SetCameraPosition(Transform camera, Transform player, float distanceFromPlayer) {
    Quaternion rotate60Upwards = Quaternion.AngleAxis(60, Vector3.right);
    Vector3 fromPlayerToCamera = (rotate60Upwards * Vector3.back) * distanceFromPlayer;
    camera.position = player.position + fromPlayerToCamera;
camera.rotation = Quaternion.AngleAxis(60, Vector3.right);        
}

Now, you can either move the camera the exact same amount that you move the player, whenever the player moves (without rotating the camera any further), or you can simply run the code above every frame (in Update()) so the camera is always updated according to the player location.

Edit: I now understand that you want the camera to stay fixed and rotate, but limit the rotation. What you can do is calculate the most extreme rays of the camera (the corners of the screen), and check that none of them are outside your boundaries. You can do that by placing a huge box collider behind your scene in the area, but only in the area that you want to be visible, so that when there is a point that you don’t want to be visible, the collider will not be behind it. Set a specific layer for this collider, say “AreaLayer”. Then cast the extreme rays with the AreaLayer as a mask, and see if they hit the collider. If they do not, don’t allow the camera to rotate any further:

void FollowPlayer(Transform player) {
    Quaternion previousRotation = transform.rotation; // remember original rotation
    transform.LookAt(player, Vector3.up); // look at player

    // if looking at player caused the camera to turn outside its bounds, restore previous rotation
    if (IsCameraOutOfBounds()) {
        transform.rotation = previousRotation;
    }
}

bool IsCameraOutOfBounds() {
    Ray[] edgeRays = GetCameraEdgeRays(); // get camera extreme rays
    int layerMask = 1 << LayerMask.NameToLayer("AreaLayer"); // raycast layer should only find the "AreaLayer" collider - the collider that depicts the game area
    foreach (Ray ray in edgeRays) {
        // if raycast doesn't hit the area layer collider, camera is out of bounds
        if (!Physics.Raycast(ray, Mathf.Infinity, layerMask) {
            return true;
        }            
    }
    return false;
}

// get 4 rays, one for each corner of the camera's view
Ray[] GetCameraEdgeRays() {
    Ray[] rays = Ray[4];
    ray[0] = camera.ScreenPointToRay(0, 0); 
    ray[1] = camera.ScreenPointToRay(0, Screen.height);
    ray[2] = camera.ScreenPointToRay(Screen.Width, 0);
    ray[3] = camera.ScreenPointToRay(Screen.Width, Screen.height);

    return rays;
}

I appreciate the input but I'm really hoping to use a camera that doesn't change its transform to follow the player instead uses LookAt to follow. I'm having a problem with keeping the camera from seeing the end of the map. In the video, the camera stays in one position and uses LookAt to follow the player. As the player reaches an edge of the map, the camera reaches a boundary and stops following the player. That's what I'm trying to do.

It is a much simpler solution I appreciated it.

You could establish a limit angle of rotation on the Y and X axis.

Store the the orientation of the camera at the center of the scene in a variable called middleOrientation.
Every frame get a new orientation looking directly to the target player called targetOrientation.
Now test the angle between the X axis of the middleOrientation with the X axis of the targetOrientation and check if it exceeds the limit angle rotation about that angle if not continue otherwise you will have to undo the orientation with exceedAngle - limitAngle.
Do the same thing with the Y axis.

To get the angle between 2 axis you can use the following code:

var vec1=Vector3(2,3,4); 
var vec2= Vector3(1,-2,3);
//Get the dot product
var dot:float = Vector3.Dot(vec1,vec2);
// Divide the dot by the product of the magnitudes of the vectors
dot = dot/(vec1.magnitude*vec2.magnitude);
//Get the arc cosin of the angle, you now have your angle in radians 
var acos = Mathf.Acos(dot);
//Multiply by 180/Mathf.PI to convert to degrees
var angle = acos*180/Mathf.PI;
//Congrats, you made it really hard on yourself.
print(angle);

I messed up the angles when rotation on the Y axis you can test the 2 forward vectors and when rotation on the X axis you can test the 2 up vectors.

Thanks, I am new to Unity^^ but a little math knowledge is good too.