using System; using UnityEngine; using UnityEngine.EventSystems; [RequireComponent(typeof(BoxCollider2D))] public class WorldMapCameraOperator : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler, IBeginPinchHandler, IPinchHandler, IEndPinchHandler, IEventSystemHandler { private void Awake() { this._pinching = false; this._animationMode = WorldMapCameraOperator.AnimationMode.None; this._cameraZ = this._cameraToOperate.transform.position.z; } private void Start() { this.RestrictCameraBounds(); } private void LateUpdate() { this.SoftRestrictCameraZoom(Time.deltaTime); if (this._animationMode == WorldMapCameraOperator.AnimationMode.None) { return; } Transform transform = this._cameraToOperate.transform; float num = this._cameraToOperate.orthographicSize * 2f; float num2 = num * this._cameraToOperate.aspect; if (this._animationMode == WorldMapCameraOperator.AnimationMode.Velocity) { this._animationVelocity *= 0.95f; Vector3 zero = Vector3.zero; zero.x = -this._animationVelocity.x * Time.deltaTime / (float)this._cameraToOperate.pixelWidth * num2; zero.y = -this._animationVelocity.y * Time.deltaTime / (float)this._cameraToOperate.pixelHeight * num; transform.localPosition += zero; if (this._animationVelocity.magnitude < 5f) { this._animationMode = WorldMapCameraOperator.AnimationMode.None; } } else if (this._animationMode == WorldMapCameraOperator.AnimationMode.Destination) { float num3 = this._destinationAnimationCurve.Evaluate((Time.time - this._animationStartTime) / this._destinationAnimationDuration); Vector3 position = transform.position; if (num3 >= 1f) { position.x = this._animationDestination.x; position.y = this._animationDestination.y; this._animationMode = WorldMapCameraOperator.AnimationMode.None; } else { position = Vector2.Lerp(this._animationSource, this._animationDestination, num3); position.z = this._cameraZ; } transform.position = position; } this.RestrictCameraBounds(); } public void OnPointerClick(PointerEventData eventData) { } public void OnPointerDown(PointerEventData eventData) { if (this._animationMode != WorldMapCameraOperator.AnimationMode.None) { this._animationMode = WorldMapCameraOperator.AnimationMode.None; } } public void OnPointerUp(PointerEventData eventData) { } public void OnBeginPinch(PinchEventData pinchEvent) { this._pinching = true; this._pinchingOrthoSize = this._cameraToOperate.orthographicSize; if (this._animationMode != WorldMapCameraOperator.AnimationMode.None) { this._animationMode = WorldMapCameraOperator.AnimationMode.None; } } public void OnPinch(PinchEventData pinchEvent) { this._pinchingOrthoSize /= pinchEvent.ScaleDelta; float num = this.CalculateZoomOffset(this._pinchingOrthoSize); float num2 = this._minZoom - this._maxZoom; if (num < 0f) { num2 /= 2f; } float num3 = this.DampenOffset(num, num2); float orthographicSize = this._pinchingOrthoSize + num - num3; Transform transform = this._cameraToOperate.transform; float num4 = this._cameraToOperate.orthographicSize * 2f; float num5 = num4 * this._cameraToOperate.aspect; Vector2 zero = Vector2.zero; zero.x = transform.localPosition.x - num5 * 0.5f + pinchEvent.Center.x / (float)this._cameraToOperate.pixelWidth * num5; zero.y = transform.localPosition.y - num4 * 0.5f + pinchEvent.Center.y / (float)this._cameraToOperate.pixelHeight * num4; Vector3 zero2 = Vector3.zero; zero2.x = -pinchEvent.Delta.x / (float)this._cameraToOperate.pixelWidth * num5; zero2.y = -pinchEvent.Delta.y / (float)this._cameraToOperate.pixelHeight * num4; zero2.x += (transform.localPosition.x - zero.x) * (1f - pinchEvent.ScaleDelta); zero2.y += (transform.localPosition.y - zero.y) * (1f - pinchEvent.ScaleDelta); transform.localPosition += zero2; this._cameraToOperate.orthographicSize = orthographicSize; this.RestrictCameraBounds(); } public void OnEndPinch(PinchEventData pinchEvent) { if (this._animationMode == WorldMapCameraOperator.AnimationMode.None && pinchEvent.Velocity.magnitude >= 30f) { this._animationVelocity = pinchEvent.Velocity; this._animationMode = WorldMapCameraOperator.AnimationMode.Velocity; } this._pinching = false; } public void Init() { } public void ScrollTo(Transform t, bool animated) { this.ScrollTo(t.position, animated); } public void ScrollTo(GameObject go, bool animated) { Collider2D component = go.GetComponent(); Vector2 position; if (component != null) { position = component.bounds.center; } else { position = go.transform.position; } this.ScrollTo(position, animated); } public void ScrollTo(Vector2 position, bool animated) { if (this._pinching) { return; } Transform transform = this._cameraToOperate.transform; if (animated) { this._animationSource = transform.position; this._animationDestination = position; this._animationStartTime = Time.time; this._animationMode = WorldMapCameraOperator.AnimationMode.Destination; } else { this._animationMode = WorldMapCameraOperator.AnimationMode.None; Vector3 position2 = transform.position; position2.x = position.x; position2.y = position.y; transform.position = position2; this.RestrictCameraBounds(); } } public Vector3 CameraWorldPosition { get { return this._cameraToOperate.transform.position; } } private void SoftRestrictCameraZoom(float deltaTime) { if (!this._pinching) { float num = this._cameraToOperate.orthographicSize; float num2 = this.CalculateZoomOffset(num); if (!Mathf.Approximately(num2, 0f)) { float num3 = 0f; num = Mathf.SmoothDamp(num, num + num2, ref num3, this._zoomElasticity, float.PositiveInfinity, deltaTime); num += num3; this._cameraToOperate.orthographicSize = num; } } } private void RestrictCameraBounds() { Transform transform = this._cameraToOperate.transform; float num = this._cameraToOperate.orthographicSize * 2f; float num2 = num * this._cameraToOperate.aspect; Bounds bounds = this._cameraBounds.bounds; if (num2 > bounds.size.x) { num2 = bounds.size.x; num = num2 / this._cameraToOperate.aspect; this._cameraToOperate.orthographicSize = num * 0.5f; } if (num > bounds.size.y) { num = bounds.size.y; num2 = num * this._cameraToOperate.aspect; this._cameraToOperate.orthographicSize = num * 0.5f; } Vector3 position = transform.position; if (position.x - num2 * 0.5f < bounds.min.x) { position.x = bounds.min.x + num2 * 0.5f; } if (position.x + num2 * 0.5f > bounds.max.x) { position.x = bounds.max.x - num2 * 0.5f; } if (position.y - num * 0.5f < bounds.min.y) { position.y = bounds.min.y + num * 0.5f; } if (position.y + num * 0.5f > bounds.max.y) { position.y = bounds.max.y - num * 0.5f; } transform.position = position; } private float CalculateZoomOffset(float orthoSize) { float result = 0f; if (orthoSize < this._maxZoom) { result = this._maxZoom - orthoSize; } else if (orthoSize > this._minZoom) { result = this._minZoom - orthoSize; } return result; } private float DampenOffset(float overStretching, float zoomRange) { if (Mathf.Approximately(overStretching, 0f)) { return 0f; } return (1f - 1f / (Mathf.Abs(overStretching) / (this._zoomStiffness * zoomRange) + 1f)) * zoomRange * Mathf.Sign(overStretching); } private const float VelocityReductionFactor = 0.95f; private const float VelocityStartMagnitudeThreshold = 30f; private const float VelocityEndMagnitudeThreshold = 5f; [SerializeField] private Camera _cameraToOperate; [SerializeField] private float _destinationAnimationDuration = 0.6f; [SerializeField] private AnimationCurve _destinationAnimationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); [SerializeField] private float _minZoom = 500f; [SerializeField] private float _maxZoom = 200f; [SerializeField] private float _zoomElasticity = 0.6f; [SerializeField] private float _zoomStiffness = 1.5f; [SerializeField] private BoxCollider2D _cameraBounds; private bool _pinching; private float _pinchingOrthoSize; private WorldMapCameraOperator.AnimationMode _animationMode; private Vector2 _animationVelocity; private Vector2 _animationSource; private Vector2 _animationDestination; private float _animationStartTime; private float _cameraZ; private enum AnimationMode { None, Velocity, Destination } }