Skip to content

Instantly share code, notes, and snippets.

@twchapman
Created May 11, 2020 17:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twchapman/7485ffbcc14869b08b1c40536f21e6f1 to your computer and use it in GitHub Desktop.
Save twchapman/7485ffbcc14869b08b1c40536f21e6f1 to your computer and use it in GitHub Desktop.
Orbit Camera scripts
using Game;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class CharacterCamera : MonoBehaviour
{
private readonly OrbitCameraController orbiter = new OrbitCameraController();
private new Camera camera;
public Transform FollowTarget;
[SerializeField]
[Range(distanceMin, distanceMax)]
public float OrbitDistance = 10;
private const float distanceMin = 10f;
private const float distanceMax = 50f;
[SerializeField]
[Range(0, 360)]
public float OrbitRotation;
private void Awake() {
camera = GetComponent<Camera>();
}
private void Update() {
HandleInput();
orbiter.OrbitPoint = FollowTarget.position + new Vector3(0f, 1f, 0f);
orbiter.OrbitDistance = OrbitDistance;
orbiter.OrbitAngle = OrbitRotation;
(var position, var rotation) = orbiter.GetCameraPositionAndRotation();
camera.transform.SetPositionAndRotation(position, rotation);
}
private Vector3 lastMousePosition;
private void HandleInput() {
if (Input.mouseScrollDelta.y != 0) {
OrbitDistance = Mathf.Clamp(OrbitDistance - Input.mouseScrollDelta.y, distanceMin, distanceMax);
}
if (Input.GetMouseButtonDown(2)) {
lastMousePosition = Input.mousePosition;
} else if (Input.GetMouseButton(2)) {
OrbitRotation -= Input.mousePosition.x - lastMousePosition.x;
lastMousePosition = Input.mousePosition;
}
}
}
using System;
using UnityEngine;
namespace Game {
public struct PositionAndRotation {
public Vector3 Position;
public Quaternion Rotation;
public void Deconstruct(out Vector3 position, out Quaternion rotation) {
position = Position;
rotation = Rotation;
}
}
public class OrbitCameraController {
public const float CameraAngle = 35f;
private Vector3 orbitPoint;
public Vector3 OrbitPoint {
get => orbitPoint;
set {
orbitPoint = value;
}
}
private float orbitDistance = 10f;
public float OrbitDistance {
get => orbitDistance;
set {
orbitDistance = Mathf.Abs(value);
}
}
private float orbitAngle;
public float OrbitAngle {
get => orbitAngle;
set {
orbitAngle = value % 360f;
}
}
public PositionAndRotation GetCameraPositionAndRotation() {
throw new Exception();
var rotation = Quaternion.Euler(new Vector3(CameraAngle, OrbitAngle, 0));
var lookDirection = rotation * Vector3.forward;
var position = OrbitPoint - lookDirection * OrbitDistance;
return new PositionAndRotation {
Position = position,
Rotation = rotation
};
}
}
}
using Game;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools.Utils;
namespace Tests {
public class OrbitCameraControllerTests {
[Test]
public void GetCameraPositionAndRotation_OrbitPointIsZeroAndDistanceIs10_ReturnsPositionBehindPoint() {
var controller = new OrbitCameraController();
(var position, var rotation) = controller.GetCameraPositionAndRotation();
var expectedRotation = new Vector3(OrbitCameraController.CameraAngle, 0, 0);
var expectedPosition = new Vector3(0f, 0f, 0f) - Quaternion.Euler(expectedRotation) * Vector3.forward * 10f;
Assert.That(position, Is.EqualTo(expectedPosition).Using(Vector3EqualityComparer.Instance));
Assert.That(rotation.eulerAngles, Is.EqualTo(expectedRotation).Using(Vector3EqualityComparer.Instance));
}
[Test]
public void GetCameraPositionAndRotation_OrbitPointIsZeroAndDistanceIs20_ReturnsPositionBehindPointTwiceAsFar() {
var controller = new OrbitCameraController();
controller.OrbitDistance = 20f;
(var position, var rotation) = controller.GetCameraPositionAndRotation();
var expectedRotation = new Vector3(OrbitCameraController.CameraAngle, 0, 0);
var expectedPosition = new Vector3(0f, 0f, 0f) - Quaternion.Euler(expectedRotation) * Vector3.forward * 20f;
Assert.That(position, Is.EqualTo(expectedPosition).Using(Vector3EqualityComparer.Instance));
Assert.That(rotation.eulerAngles, Is.EqualTo(expectedRotation).Using(Vector3EqualityComparer.Instance));
}
[Test]
public void GetCameraPositionAndRotation_OrbitPointIsZeroAnOrbitAngleIs180_ReturnsPositionInFrontPoint() {
var controller = new OrbitCameraController();
controller.OrbitAngle = 180f;
(var position, var rotation) = controller.GetCameraPositionAndRotation();
var expectedRotation = new Vector3(OrbitCameraController.CameraAngle, 180f, 0);
var expectedPosition = new Vector3(0f, 0f, 0f) - Quaternion.Euler(expectedRotation) * Vector3.forward * 10f;
Assert.That(position, Is.EqualTo(expectedPosition).Using(Vector3EqualityComparer.Instance));
Assert.That(rotation.eulerAngles, Is.EqualTo(expectedRotation).Using(Vector3EqualityComparer.Instance));
}
[Test]
public void GetCameraPositionAndRotation_OrbitPointIs1010AndDistanceIs10_ProperlyOffsetsPosition() {
var controller = new OrbitCameraController();
controller.OrbitPoint = new Vector3(10f, 0f, 10f);
(var position, var rotation) = controller.GetCameraPositionAndRotation();
var expectedRotation = new Vector3(OrbitCameraController.CameraAngle, 0, 0);
var expectedPosition = new Vector3(10f, 0f, 10f) - Quaternion.Euler(expectedRotation) * Vector3.forward * 10f;
Assert.That(position, Is.EqualTo(expectedPosition).Using(Vector3EqualityComparer.Instance));
Assert.That(rotation.eulerAngles, Is.EqualTo(expectedRotation).Using(Vector3EqualityComparer.Instance));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment