Spherical coordinates are based on positional offset relative to a sphere’s center point, and seem well suited to this task. On the side I happened to be working on a game that makes heavy use of spherical coordinates, so when doing this section and assigning the second stick to camera movement, I wanted to try taking a mathematical approach.
I used the formula for converting between spherical coordinates and cartesian (x, y, z) coordinates on Wikipedia.
Note: the Y and Z are switched to compensate for Y being “up” in Unity
Here is my solution, with the Polar
class borrowed from my other game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraManager : MonoBehaviour
{
public GameObject followTarget;
public float distance = 10f;
public float speed = 1f;
private Polar polarOffset;
private void Awake()
{
polarOffset = new Polar(distance, 90f, 90f);
}
private void LateUpdate()
{
// The angle from the "north pole" (polar angle)
float targetInclination = polarOffset.inclination + (Input.GetAxis("RightVertical") * speed * Time.deltaTime);
// Clamping inclination prevents rotational weirdness when at/beyond the poles
polarOffset.inclination = Mathf.Clamp(targetInclination, 1f, 179f);
// The angle around the "equator"
polarOffset.azimuth = polarOffset.azimuth + Input.GetAxis("RightHorizontal") * speed * Time.deltaTime;
Vector3 offset = polarOffset.ToCartesian();
transform.position = followTarget.transform.position + offset;
transform.LookAt(followTarget.transform);
}
}
public class Polar
{
public float radius, inclination, azimuth;
public static Vector3 ToCartesian(float radius, float inclination, float azimuth)
{
float x = radius * Mathf.Sin(inclination * Mathf.Deg2Rad) * Mathf.Cos(azimuth * Mathf.Deg2Rad);
float y = radius * Mathf.Cos(inclination * Mathf.Deg2Rad);
float z = radius * Mathf.Sin(inclination * Mathf.Deg2Rad) * Mathf.Sin(azimuth * Mathf.Deg2Rad);
return new Vector3(x, y, z);
}
public Polar(float radius, float inclination, float azimuth)
{
this.radius = radius;
this.inclination = inclination;
this.azimuth = azimuth;
}
public Vector3 ToCartesian()
{
return Polar.ToCartesian(radius, inclination, azimuth);
}
}
I just figured I’d post this method, as it can be handy to have different solutions to pull from later.