Space-Smash-Out/Assets/Scripts/CameraOperator.cs

119 lines
2.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using static UnityEngine.Mathf;
public class CameraOperator : MonoBehaviour
{
private Dictionary<int, GameObject> players = new Dictionary<int, GameObject>();
[SerializeField]
private int MaxAdditionalDistance = 15;
private float InitialDistance = 0;
private float MaxDistance;
private Camera cam;
private void Awake()
{
cam = gameObject.GetComponent<Camera>();
// Distance here is in the negative direction on the z axis
InitialDistance = transform.localPosition.z;
MaxDistance = InitialDistance - MaxAdditionalDistance;
}
public void AddPlayer(GameObject player)
{
players[player.GetInstanceID()] = player;
}
public void RemovePlayer(int id)
{
players.Remove(id);
}
/// <summary>
/// Rotates the camera to point at the center between the players.
/// </summary>
private void LateUpdate()
{
CenterBetweenPlayers();
AdjustZoom();
}
private void CenterBetweenPlayers()
{
if (players.Count < 1)
{
return;
}
float x = transform.localPosition.x;
float y = transform.localPosition.y;
float z = transform.localPosition.z;
foreach (GameObject p in players.Values)
{
if (p.IsDestroyed())
continue;
Vector3 position = p.transform.localPosition;
z = position.z;
x += position.x;
y += position.y;
}
x /= players.Count();
y /= players.Count();
float a = z - InitialDistance;
float cXAxis = (float)Sqrt(Pow(a, 2) + Pow(x, 2));
float cYAxis = (float)Sqrt(Pow(a, 2) + Pow(y, 2));
Vector3 xyRotation = new Vector3(Rad2Deg * Acos(a / cYAxis) * -Math.Sign(y),
Rad2Deg * Acos(a / cXAxis) * Math.Sign(x), 0);
if (transform.localEulerAngles != xyRotation / 2)
{
transform.localEulerAngles = xyRotation / 2;
}
}
private void AdjustZoom()
{
if (players.Count < 2)
{
return;
}
float Margin = Screen.height / 2;
float maxXDistance = 0;
float maxYDistance = 0;
foreach (GameObject player in players.Values)
{
var screenPos1 = cam.WorldToScreenPoint(player.transform.position);
foreach (GameObject p in players.Values)
{
if (p == player)
continue;
var screenPos2 = cam.WorldToScreenPoint(p.transform.position);
var distance = screenPos2 - screenPos1;
float xDistance = Abs(distance.x);
if (maxXDistance < xDistance)
maxXDistance = xDistance;
float yDistance = Abs(distance.y);
if (maxYDistance < yDistance)
maxYDistance = Abs(distance.y);
}
}
if (maxXDistance < Screen.width - Margin
&& maxYDistance < Screen.height - Margin)
{
if (transform.localPosition.z < InitialDistance + 0.1f)
transform.localPosition += new Vector3(0, 0, 0.1f);
return;
}
if (transform.localPosition.z > MaxDistance - 0.1f)
transform.localPosition -= new Vector3(0, 0, 0.1f);
}
}