Camera Controls while Parachuting in Unity (Rotating Around a Sphere)

Abstract

This article takes record of my attempt into creating a camera controllers suitable for free-looking when parachuting. A practical use of this controller is recreating the free-looking camera during the dropping phase in typical Battle Royale games. This controller takes the camera motions in Apex Legends as reference.

Observation

In Apex Legends, the dropping camera works as shown in the following screen capture (on PS4):

On PS4, the right analog stick is responsible for rotating the camera.

Keypoints:

  1. If the player pushes the stick to the left or the right, the camera rotates horizontally around the player.
  2. If the player pushes it upwards or downwards, the camera rotates vertically around the player.
  3. The camera stops rotating when it’s looking straight down into Earth up into the sky.

Implementation

Attempt 1

First, set up your mock objects. For me, I parented my target object Player to my main camera.

Then, create a controller script for your camera. For me, I name it CameraController.

Used to be that when I’m challenged with the problem of designing this type of camera, I’d go as deep as implementing this camera by hard-setting the camera’s position by calculating the angles and the exact coordinates; only until recently had I found out the life-saving method of Transform.RotateAround(..).

Basically, what it does is it rotates an object around a given vector as axis by x degrees. What’s convenient here is that this method takes in euler degrees as argument, not Quaternions.

Basically, there are two parts to this problem:

  1. Rotating the camera around the target.
  2. Stop rotating the camera at certain degrees.

Part 1: Rotating

Since the camera does not roll, so it’s safe to assume that the camera rotates along two axes: x (right, pitch) and y (up, yaw). I was first inclined to rotate it around the world’s right and up axes; this turned out to be wrong since it’d cause a gimble lock on them.

Yet, rotating around our target’s x and y axes would cause problems on its own: rotating along one of the two axes implies that the other axis would be pointing at another direction. This means that as soon as we start rotating around the x axis, the whole thing spins off.

Notice that the new camera in violet does not rotate correctly.

Let’s split this problem into two, each regarding one axis:

  • For Y axis: This concerns the horizontal movements of the camera. In our reference video, the camera always look towards up or down with reference to the world. Had it operated with reference to the player’s up vector, if the target suddenly starts rolling, we would end up with a camera spinning chaotically around it. So, we should keep our settings for the Y axis.
  • For X axis: This concerns the vertical movements of the camera. As mentioned, if we rotate around the world’s X axis, we would end up with a gimble lock. If we rotate around our target’s own x axis, since it’s right vector does not roll when it changes direction along with the y axis, we can ensure that every time the camera travels upwards or downwards, it always travel the full circumference of the sphere.

Applying our findings above, we end up having a camera that works fluently around all angles.

Apologies for screen-capturing. WordPress wants me to pay first before I can format my code.

Now we need to take care of the flipping problem.

Part 2: Limiting Angles

At first glance, I thought using dot product was the way to go. Here was my code:

Putting the mathematical errors aside, there is a much more fundamental issue going on here: the condition here checks against the two forward vectors before changes are made. This is wrong because a 179-going-on-to-be-181 degrees in the next frame would be allowed. In fact, this has resulted in crazy angle-flipping between 181 and 179.

The correct way to do this is to check if the angles after change will go below 0 or 180. The problem here, though, is that we must then convert the angles into a corresponding vector. This can be much more tedious and more prone to math errors along implementation. When predicting for values that are not guaranteed to be applied, it’s better to simplify things.

To fix this problem, along with mathematical problems:

  1. I chose angles (float) to be the compared data type.
  2. Then, assuming that we ignore the rotation of our target, I choose the world Y axis (Vector3.Up) as a reference vector.
  3. I used Vector3.Angle(..) to check the angle between said vector and the camera’s current forward vector and add it with the delta degrees, the angle that is supposed to be applied to in this frame.
  4. If this resulting number is greater than 180 degrees (looking down, remember we are comparing the camera to the world up vector) or smaller than 0 degrees (looking up), then the change will not apply.

If everything works well, we should have a code that works like this:

PS: Use LateUpdate() for camera manipulation, as it ensures that your objects move first before the camera moves.

Results:

You may be wondering: if the camera is a child to our target, when our target rolls on the ground, won’t that also change tip over our camera’s right vector?

While that is indeed true, it is saved by one method here:

Transform.LookAt(Transform target, Vector3 worldUp = Vector3.up)

This code has an additional setting which forces the camera to right its rotation according to the given argument (worldUp).

So there you have it! A simple script that controls the camera on your parachuting character.

Origin

I had an idea last night:

so I started prototyping out a game that plays like a battle royale but there’s only parachuting out from the sky. I needed a reliable way to get where to player is looking at, so they can maneuver themselves while dropping.

Who knows if this thing will actually turn into a game? We’ll see 🙂

Published by

Brian Teng

Game Designer | San Jose, CA

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s