Skip to content

Instantly share code, notes, and snippets.

@bingomanatee
Created August 19, 2014 20:42
Show Gist options
  • Save bingomanatee/764858f6c1323770c77b to your computer and use it in GitHub Desktop.
Save bingomanatee/764858f6c1323770c77b to your computer and use it in GitHub Desktop.
The camera control - using state and Lerping betweeen camera data
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/**
* this is a structure that freezes a target camera position rotation and field of view
* as a lerp target for transitions.
* while these properties will be frozen in place for the target extremes, the main camera's properteis
* will be constantly fluxuating between values. Also, if a camera transitions to a new target while en route
* to an old one, the goal is to freeze that transition point into a CameraState as a basis for lerping.
*/
public struct CameraState
{
public Vector3 position;
public Quaternion rotation;
public float fieldOfView;
public string name;
// redundant as most of the time cameraState will be pulled off of the dictionary
// but useful occasionally.
public CameraState (Camera c)
{
position = c.transform.position;
rotation = c.transform.rotation;
fieldOfView = c.fieldOfView;
name = c.name;
}
public CameraState (Camera c, string n)
{
position = c.transform.position;
rotation = c.transform.rotation;
fieldOfView = c.fieldOfView;
name = n;
}
}
public class CameraShift : MonoBehaviour
{
const float DEFAULT_TRANSITION_TIME = 4f;
public const string HOME_CAMERA_NAME = "HOME";
public List <Camera> targets = new List<Camera> ();
Dictionary<string, CameraState> lookup = new Dictionary<string, CameraState> ();
public CameraState currentTarget;
public CameraState lastTarget;
float lastRetargetTime = 0;
float transitionTime = DEFAULT_TRANSITION_TIME;
public delegate void CameraArrival (string name);
public static event CameraArrival CameraArrived;
public AnimationCurve animationTransition;
enum MoveState
{
Unknown,
Stable,
Moving
}
public float progressToTarget = 0f;
MoveState state = MoveState.Unknown;
public string _ntName;
public string targetName {
set {
if (state == MoveState.Moving) {
FreezeCurrentCameraState ();
}
Debug.Log ("Lerping to target: " + value);
if (lookup.ContainsKey (value)) {
_ntName = value;
currentTarget = lookup [value];
} else {
Debug.Log ("Cannot find key " + value + " in CameraShift dictionary");
currentTarget = lookup [HOME_CAMERA_NAME];
_ntName = HOME_CAMERA_NAME;
}
state = MoveState.Moving;
lastRetargetTime = Time.time;
}
get {
return _ntName;
}
}
// Use this for initialization
void Start ()
{
currentTarget = new CameraState (this.GetComponent<Camera>(), HOME_CAMERA_NAME);
lastTarget = currentTarget;
state = MoveState.Stable;
progressToTarget = 1.0f;
lookup.Add(HOME_CAMERA_NAME, new CameraState(this.GetComponent<Camera>(), HOME_CAMERA_NAME));
foreach (Camera c in targets) {
lookup.Add (c.name, new CameraState (c));
}
// for testing purposes
//targetName = targets [0].name;
CameraArrived += OnCameraArrive;
}
// Update is called once per frame
void Update ()
{
if (state == MoveState.Moving) {
MoveCamera ();
}
}
void FreezeCurrentCameraState(){
lastTarget = new CameraState(this.GetComponent<Camera>());
}
void OnCameraArrive (string arrivedName)
{
/* Debug.Log ("Camera change -- arrived at " + arrivedName);
string firstTarget = targets [0].name;
string secondTarget = targets [1].name;
switch (arrivedName) {
case HOME_CAMERA_NAME:
Debug.Log ("Switching to first target " + firstTarget);
targetName = firstTarget;
break;
case "TableCamera":
Debug.Log ("Switching to second target " + secondTarget);
targetName = secondTarget;
break;
default:
targetName = HOME_CAMERA_NAME;
break;
} */
}
float CurveValue (float inputValue)
{
return animationTransition.Evaluate (inputValue);
}
void MoveCamera ()
{
float l = (Time.time - lastRetargetTime) / transitionTime;
if (l >= 1) {
this.GetComponent<Camera>().transform.position = currentTarget.position;
this.GetComponent<Camera>().transform.rotation = currentTarget.rotation;
state = MoveState.Stable;
lastTarget = currentTarget;
this.GetComponent<Camera>().fieldOfView = currentTarget.fieldOfView;
if (CameraArrived != null)
CameraArrived (currentTarget.name);
} else {
l = CurveValue (l);
this.GetComponent<Camera>().transform.position = LerpPosition(l);
this.GetComponent<Camera>().transform.rotation = LerpRotation(l);
this.GetComponent<Camera>().fieldOfView = LerpFOV(l);
}
}
float LerpFOV (float l)
{
return Mathf.Lerp (lastTarget.fieldOfView, currentTarget.fieldOfView, l);
}
Vector3 LerpPosition (float l)
{
Vector3 previous = (1 - l) * lastTarget.position;
Vector3 current = l * currentTarget.position;
return previous + current;
}
Quaternion LerpRotation (float l)
{
return Quaternion.Lerp (lastTarget.rotation, currentTarget.rotation, l);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment