226 lines
7.7 KiB
C#
226 lines
7.7 KiB
C#
using Unity.Cinemachine;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
|
||
namespace BrewMonster
|
||
{
|
||
public class CameraController : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
|
||
{
|
||
public static CameraController Instance;
|
||
[SerializeField] private CinemachineCamera _cinemachineCamera;
|
||
[SerializeField] private CinemachineOrbitalFollow orbital;
|
||
private bool fingerDown = false;
|
||
[SerializeField, Min(0f)] private float dragDeadZone = 10f;
|
||
[SerializeField] private float horizontalRotationPerScreen = 60f;
|
||
[SerializeField] private float verticalRotationPerScreen = 500f;
|
||
[SerializeField, HideInInspector] private bool _migratedDeadZoneToNormalized;
|
||
|
||
[Header("Zoom (orbit scale)")]
|
||
[Tooltip("RadialAxis scales camera distance: effective distance = Orbital Follow Radius × this value.")]
|
||
[SerializeField] private bool enableZoom = true;
|
||
[SerializeField] private float orbitScaleMin = 0.5f;
|
||
[SerializeField] private float orbitScaleMax = 2f;
|
||
[SerializeField] private float defaultOrbitScale = 1f;
|
||
[SerializeField] private float zoomSensitivityScroll = 0.15f;
|
||
[SerializeField] private float zoomSensitivityPinch = 0.004f;
|
||
|
||
private float _lastPinchDistance;
|
||
private bool _pinchZoomActive;
|
||
private int _touchCount = 0;
|
||
|
||
public CinemachineOrbitalFollow Orbital { get => orbital;}
|
||
|
||
void OnEnable()
|
||
{
|
||
Instance = this;
|
||
MigrateLegacyDeadZone();
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
SyncRadialAxisRange();
|
||
}
|
||
|
||
public void OnDrag(PointerEventData eventData)
|
||
{
|
||
if (!fingerDown || orbital == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
float screenReference = Mathf.Max(1f, Mathf.Min(Screen.width, Screen.height));
|
||
Vector2 normalizedDelta = eventData.delta / screenReference;
|
||
float normalizedDeadZone = Mathf.Max(0.0001f, dragDeadZone);
|
||
|
||
if (normalizedDelta.sqrMagnitude >= normalizedDeadZone * normalizedDeadZone)
|
||
{
|
||
orbital.HorizontalAxis.Value += normalizedDelta.x * horizontalRotationPerScreen;
|
||
//orbital.HorizontalAxis.Value = Mathf.Clamp(orbital.HorizontalAxis.Value, -360f, 360f);
|
||
orbital.VerticalAxis.Value -= normalizedDelta.y * verticalRotationPerScreen;
|
||
orbital.VerticalAxis.Value = Mathf.Clamp(orbital.VerticalAxis.Value, -360f, 360f);
|
||
}
|
||
}
|
||
|
||
public void OnPointerDown(PointerEventData eventData)
|
||
{
|
||
fingerDown = true;
|
||
if(_touchCount < 2)
|
||
{
|
||
_touchCount++;
|
||
}
|
||
}
|
||
|
||
public void OnPointerUp(PointerEventData eventData)
|
||
{
|
||
fingerDown = false;
|
||
if(_touchCount > 0)
|
||
{
|
||
_touchCount--;
|
||
}
|
||
}
|
||
|
||
private void OnValidate()
|
||
{
|
||
MigrateLegacyDeadZone();
|
||
orbitScaleMin = Mathf.Max(0.01f, orbitScaleMin);
|
||
orbitScaleMax = Mathf.Max(orbitScaleMin, orbitScaleMax);
|
||
defaultOrbitScale = Mathf.Clamp(defaultOrbitScale, orbitScaleMin, orbitScaleMax);
|
||
SyncRadialAxisRange();
|
||
}
|
||
|
||
/// <summary> Keeps Cinemachine RadialAxis range in sync with serialized min/max. </summary>
|
||
private void SyncRadialAxisRange()
|
||
{
|
||
if (orbital == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
float min = Mathf.Min(orbitScaleMin, orbitScaleMax);
|
||
float max = Mathf.Max(orbitScaleMin, orbitScaleMax);
|
||
var radial = orbital.RadialAxis;
|
||
var range = radial.Range;
|
||
range.x = min;
|
||
range.y = max;
|
||
radial.Range = range;
|
||
radial.Value = radial.ClampValue(radial.Value);
|
||
orbital.RadialAxis = radial;
|
||
}
|
||
|
||
private void ResetFollowCameraAxes()
|
||
{
|
||
if (orbital == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
orbital.HorizontalAxis.Value = 208;
|
||
orbital.VerticalAxis.Value = -268;
|
||
SyncRadialAxisRange();
|
||
var radial = orbital.RadialAxis;
|
||
radial.Value = radial.ClampValue(defaultOrbitScale);
|
||
orbital.RadialAxis = radial;
|
||
}
|
||
|
||
private void ApplyRadialZoomDelta(float delta)
|
||
{
|
||
if (!enableZoom || orbital == null || Mathf.Abs(delta) < 1e-6f)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var radial = orbital.RadialAxis;
|
||
radial.Value = radial.ClampValue(radial.Value + delta);
|
||
orbital.RadialAxis = radial;
|
||
}
|
||
|
||
private void UpdatePinchZoom()
|
||
{
|
||
if (!enableZoom || orbital == null)
|
||
{
|
||
_pinchZoomActive = false;
|
||
return;
|
||
}
|
||
|
||
if (_touchCount == 2)
|
||
{
|
||
Touch t0 = Input.GetTouch(0);
|
||
Touch t1 = Input.GetTouch(1);
|
||
float dist = Vector2.Distance(t0.position, t1.position);
|
||
if (!_pinchZoomActive)
|
||
{
|
||
_pinchZoomActive = true;
|
||
_lastPinchDistance = dist;
|
||
}
|
||
else
|
||
{
|
||
float delta = dist - _lastPinchDistance;
|
||
_lastPinchDistance = dist;
|
||
// Pinch outward increases distance → larger scale
|
||
ApplyRadialZoomDelta(delta * zoomSensitivityPinch);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_pinchZoomActive = false;
|
||
}
|
||
}
|
||
|
||
private void MigrateLegacyDeadZone()
|
||
{
|
||
if (_migratedDeadZoneToNormalized)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// Older values were serialized in pixels; convert once to normalized short-side ratio.
|
||
if (dragDeadZone > 0.05f)
|
||
{
|
||
dragDeadZone /= 1080f;
|
||
}
|
||
|
||
dragDeadZone = Mathf.Max(0.0001f, dragDeadZone);
|
||
|
||
_migratedDeadZoneToNormalized = true;
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
//todo: should not always update
|
||
if (_cinemachineCamera.Follow == null && CECGameRun.Instance.GetHostPlayer() != null)
|
||
{
|
||
if(CECGameRun.Instance.GetHostPlayer().PointCam != null)
|
||
{
|
||
_cinemachineCamera.Follow = CECGameRun.Instance.GetHostPlayer().PointCam;
|
||
_cinemachineCamera.ForceCameraPosition(CECGameRun.Instance.GetHostPlayer().PointCam.position, Quaternion.identity);
|
||
ResetFollowCameraAxes();
|
||
}
|
||
else
|
||
{
|
||
_cinemachineCamera.Follow = CECGameRun.Instance.GetHostPlayer().transform;
|
||
_cinemachineCamera.ForceCameraPosition(CECGameRun.Instance.GetHostPlayer().ObjectPosition, Quaternion.identity);
|
||
ResetFollowCameraAxes();
|
||
}
|
||
}
|
||
|
||
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL
|
||
if (enableZoom && orbital != null)
|
||
{
|
||
float scroll = Input.mouseScrollDelta.y;
|
||
if (Mathf.Abs(scroll) > Mathf.Epsilon)
|
||
{
|
||
ApplyRadialZoomDelta(scroll * zoomSensitivityScroll);
|
||
}
|
||
}
|
||
#endif
|
||
UpdatePinchZoom();
|
||
}
|
||
public void UpdateFollowObject(Transform followObject)
|
||
{
|
||
_cinemachineCamera.Follow = followObject;
|
||
_cinemachineCamera.ForceCameraPosition(followObject.position, Quaternion.identity);
|
||
ResetFollowCameraAxes();
|
||
}
|
||
}
|
||
}
|