Files
test/Assets/PerfectWorld/Scripts/Camera/CameraController.cs
T
2026-04-09 11:12:40 +07:00

254 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Unity.Cinemachine;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
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("Lock view")]
[Tooltip("When locked: no zoom; drag only orbits around world Y (horizontal axis).")]
[SerializeField] private bool _lockView;
[SerializeField] private UnityEvent<bool> onViewLockChanged;
[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;}
public bool ViewLocked => _lockView;
public void SetViewLocked(bool locked)
{
if (_lockView == locked)
{
return;
}
_lockView = locked;
onViewLockChanged?.Invoke(_lockView);
}
public void ToggleViewLocked()
{
SetViewLocked(!_lockView);
}
private bool CanApplyZoom => enableZoom && !_lockView;
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;
if (!_lockView)
{
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 (!CanApplyZoom || 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 (!CanApplyZoom || 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 (CanApplyZoom && 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();
}
}
}