Rotating Cameras and Moving Forward

One thing I stumbled across in many games, where you can rotate the camera freely, is how “move forward”, is handled respective to the given camera and scene. Sometimes you push the “up” button (on whatever device you are) and end up moving the game’s character you are in charge for navigating through life to the left or to the right.

This is a problem which also occured to me when working on the controls of TheRPG and I have found a nice way of solving this issue.

Let’s say our game is controlled via gamepad with two 2-axis analog stick. For simplicity, let’s also say the left one controls the character’s movement and the right one the camera such that only the X-axis of the right analog stick is actually used to turn the camera left or right.

There are basically two ways:

  • move the player towards the upper part of the map/northward
  • move the player towards the upper part of the screen

Definitions

In order to describe the math behind this we have to define a few things first:

As we have only two axis to control our character, 2D vectors will be sufficient. $latex c = \begin{pmatrix} x_c \\ y_c \end{pmatrix}$ will be the camera forward vector which can be accessed in Unity as transform.forward. This vector is actually a 3D Vector but as we defined, we only need 2D vectors so we just omit the $latex z_c$ part.

$latex m  = \begin{pmatrix}x_m\\y_m\end{pmatrix}$ will be the left analog stick’s direction, so e.g. “forward” would translate to $latex m = \begin{pmatrix}0\\1\end{pmatrix}$, “right” to $latex m =\begin{pmatrix}1\\0\end{pmatrix}$ and so on.

Finally, $latex p = \begin{pmatrix}x_p\\y_p\end{pmatrix}$ will be the character’s position before the left analog stick’s movement momentum is applied, $latex p’$ after it is applied. Again, for simplicity, we just set our character’s starting position to be always $latex p = \begin{pmatrix}0 \\ 0\end{pmatrix}$.

Moving Northward

Imagine now the camera is simply pointing towards the upper part of the map such that $latex c = \begin{pmatrix}0 \\1\end{pmatrix}$. Moving the player forward will result in $latex p’ = p + m = \begin{pmatrix}0\\1\end{pmatrix} = m$, so this is fairly simple to implement. We do not need anything to do other than add the left analog stick’s movement direction onto our position and that’s it.

Difficulty Telling Forward from Backward?

It gets more complex when then camera is turned and the character is supposed to be moved “forward” in the camera direction. This is way more intuitive; just think about the camera pointing toward $latex Y^-$, moving the left analog stick up would result in the character walking into the “wrong” direction.

So, what do we need? Well, first of all, let’s say we have the following situation

The red arrow marks the camera direction vector $latex c = \begin{pmatrix}1\\1\end{pmatrix}$ and it’s perpendicular vector $latex \overline c$. Moving the left analog stick up-right should now result in the character walking towards $latex \begin{pmatrix}1\\0\end{pmatrix}$. Simply adding m to p would result in the playing moving in the camera direction instead of towards the upper-right of the screen.

One way to solve this would be to simply apply some rotation m, i.e. rotate m by the same degree as $latex \deg(\begin{pmatrix}0 \\ 1\end{pmatrix}, c)$. But this would be computationally heavier.

Ugh, Rotations are so messy…

… and thank god, there’s an alternative way:

The desired character direction is just the sum of the two components of m referring to the two axis X and Y in reference to the camera’s frustum.

Sounds complicated, mainly because I do not want to spend too much time formalizing correctly. So, in short: All we need to do is calculate the vector for the current camera’s direction in X and in Y direction and apply this to the given movement vector m.

Luckily, Y is already given as the camera forward direction c. So all we have to do is calculate X. We know that X must be perpendicular to Y, so let’s make use of that! We can solve this with pretty simple math:

For any given vector v we can calculate its perpendicular vector $latex \overline v$ as $latex \overline v = \begin{pmatrix}v_y \\ -v_x\end{pmatrix}$. Now this yields the perpendicular vector which is rotate counter-clockwise from v, so we just have to invert our perpendicular vector to $latex \overline v = -\begin{pmatrix}v_y \\ -v_x\end{pmatrix} = \begin{pmatrix} -v_y \\ v_x \end{pmatrix}$. And that’s about it, X is also calculated.

The last step is to apply the information about the axis onto m. And this can finally be done by simply

  • normalizing X and Y in order to keep the “movement speed” given as the length of m
  • multiplying m with X and Y separately
  • sum up those products

Final Formula

Finally, instead of calculating degrees and rotating vectors around, we can just simply calculate:

$latex \begin{aligned} p’  &= p + m \cdot norm(X) + m \cdot norm(Y) \\&= p + m \cdot \begin{pmatrix}c_y \\ -c_x\end{pmatrix} + m \cdot norm(c) \end{aligned}$

And that is about it – your character will now move forward as expected! The idea is to just calculate how much towards $latex X_{camera}$ and $latex Y_{camera}$ the character should move, which is then added into one final movement vector. Normalizing is actually importent as X and Y need to be unit-length vectors in order to not disturb the amount of movement (loosely: the movement speed of the character).

Leave a Reply

Your email address will not be published. Required fields are marked *