Skip to content

Instantly share code, notes, and snippets.

@bamacken
Last active March 6, 2024 17:43
Show Gist options
  • Save bamacken/5cfdac3a2e025918c05a to your computer and use it in GitHub Desktop.
Save bamacken/5cfdac3a2e025918c05a to your computer and use it in GitHub Desktop.
Unity - Weighted 2D Camera movement based on the influence of "interest points".
//usage: Set Camera to Orthographic and use CameraInfluence.AddInfluence(gameObject,influence);
//permanent interest points such as onscreen players should have influence set to 0.5f
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
public class CameraInfluence : MonoBehaviour
{
/*public static*/
public float min, max = 0.0f;
public Vector3 CameraTarget;
public Vector3 InfluenceTarget;
public float InterpolationSpeed = 0.001f;
public float distance = 75f;
/*public*/
public static Dictionary<GameObject, float> InfluenceObjects;
public static int InfluencePoints = 0;
/*private*/
private RaycastHit hit;
private Camera cam;
private float[] VariedInfluence;
private static CameraInfluence _instance;
private static readonly object padlock = new object();
/// <summary>
/// Threadsafe singleton instance
/// </summary>
public static CameraInfluence Instance
{
get
{
lock (padlock)
{
if (_instance == null)
{
_instance = FindObjectOfType<CameraInfluence>();
}
return _instance;
}
}
}
// Use this for initialization
void Awake()
{
cam = GetComponent<Camera>();
InfluenceObjects = new Dictionary<GameObject, float>();
InfluenceTarget = Vector3.zero;
VariedInfluence = new float[] { 1.0f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f };
}
// Update is called once per frame
void FixedUpdate()
{
if (InfluenceObjects.Count > 0)
{
float previousDistance = 0f;
float totalDistance = 0f;
Vector3 previous = Vector3.zero;
foreach (KeyValuePair<GameObject, float> pair in InfluenceObjects)
{
if (previous == Vector3.zero)
{
previous = pair.Key.transform.position;
}
float dist = Vector3.Distance(previous, pair.Key.transform.position);
if (dist > previousDistance)
{
previousDistance = dist;
}
}
totalDistance = previousDistance;
if (totalDistance > 50)
{
distance = totalDistance / InfluenceObjects.Count;
}
if (InfluenceObjects.Count == 1)
{
CameraTarget = Vector3.Lerp(CameraTarget, midpointplus(InfluenceObjects), Time.time * InterpolationSpeed);
transform.position = new Vector3(CameraTarget.x, CameraTarget.y, -3.0f);
cam.orthographicSize = distance;
}
else
{
//need to interpolate further to avoid camera bounce when new influence point is added
CameraTarget = Vector3.Lerp(CameraTarget, midpointplus(InfluenceObjects), Time.time * InterpolationSpeed);
transform.position = new Vector3(CameraTarget.x, CameraTarget.y, 0);
cam.orthographicSize = distance;
}
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube(CameraTarget, new Vector3(1, 1, 1));
Gizmos.color = Color.red;
Gizmos.DrawWireCube(CameraTarget, new Vector3(28.5f, 16f, 1f));
}
/// <summary>
/// Midpoint of multiple vectors.
/// </summary>
private Vector3 midpointplus(Dictionary<GameObject, float> a)
{
if (a.Count > 0)
{
//get the vector positions of the all interest points and add the influence
foreach (KeyValuePair<GameObject, float> pair in InfluenceObjects)
{
if (a.Count == 1)
{
InfluenceTarget.x = (pair.Key.transform.position.x);
InfluenceTarget.y = (pair.Key.transform.position.y);
}
else
{
InfluenceTarget.x += (pair.Key.transform.position.x * pair.Value);
InfluenceTarget.y += (pair.Key.transform.position.y * pair.Value);
}
}
InfluenceTarget.x /= VariedInfluence[a.Count - 1];
InfluenceTarget.y /= VariedInfluence[a.Count - 1];
}
return InfluenceTarget;
}
/// <summary>
/// Updates object influence, or adds object and influence
/// Checks if influence is 0 and should be removed.
/// </summary>
/// <param name="obj">Object.</param>
/// <param name="influence">Influence.</param>
public static void AddInfluence(GameObject obj)
{
float influence = 0.5f;
if (influence > 0)
{
if (InfluenceObjects.ContainsKey(obj))
InfluenceObjects[obj] = influence;
else
InfluenceObjects.Add(obj, influence);
}
else
if (InfluenceObjects.ContainsKey(obj))
InfluenceObjects.Remove(obj);
}
public static void AddInfluence(GameObject obj, float influence)
{
if (influence > 0)
{
if (InfluenceObjects.ContainsKey(obj))
InfluenceObjects[obj] = influence;
else
InfluenceObjects.Add(obj, influence);
}
else
{
if (InfluenceObjects.ContainsKey(obj))
InfluenceObjects.Remove(obj);
}
}
public static void RemoveInfluence(GameObject obj)
{
if (InfluenceObjects.ContainsKey(obj))
InfluenceObjects.Remove(obj);
}
void OnDisable()
{
//InfluenceObjects = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment