Created
May 11, 2020 21:53
-
-
Save bhupiister/dcdde0a6618fd847ed31824595604ed0 to your computer and use it in GitHub Desktop.
Pan and Zoom script for unity for all platforms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Collections.Generic; | |
using UnityEngine.EventSystems; | |
/// <summary> A modular and easily customisable Unity MonoBehaviour for handling swipe and pinch motions on mobile. </summary> | |
public class PanAndZoom : MonoBehaviour | |
{ | |
/// <summary> Called as soon as the player touches the screen. The argument is the screen position. </summary> | |
public event Action<Vector2> onStartTouch; | |
/// <summary> Called as soon as the player stops touching the screen. The argument is the screen position. </summary> | |
public event Action<Vector2> onEndTouch; | |
/// <summary> Called if the player completed a quick tap motion. The argument is the screen position. </summary> | |
public event Action<Vector2> onTap; | |
/// <summary> Called if the player swiped the screen. The argument is the screen movement delta. </summary> | |
public event Action<Vector2> onSwipe; | |
/// <summary> Called if the player pinched the screen. The arguments are the distance between the fingers before and after. </summary> | |
public event Action<float, float> onPinch; | |
[Header("Tap")] | |
[Tooltip("The maximum movement for a touch motion to be treated as a tap")] | |
public float maxDistanceForTap = 40; | |
[Tooltip("The maximum duration for a touch motion to be treated as a tap")] | |
public float maxDurationForTap = 0.4f; | |
[Header("Desktop debug")] | |
[Tooltip("Use the mouse on desktop?")] | |
public bool useMouse = true; | |
[Tooltip("The simulated pinch speed using the scroll wheel")] | |
public float mouseScrollSpeed = 2; | |
[Header("Camera control")] | |
[Tooltip("Does the script control camera movement?")] | |
public bool controlCamera = true; | |
[Tooltip("The controlled camera, ignored of controlCamera=false")] | |
public Camera cam; | |
public Camera cam2; | |
[Header("UI")] | |
[Tooltip("Are touch motions listened to if they are over UI elements?")] | |
public bool ignoreUI = false; | |
[Header("Bounds")] | |
[Tooltip("Is the camera bound to an area?")] | |
public bool useBounds; | |
public bool EnablePan; | |
public float boundMinX = -150; | |
public float boundMaxX = 150; | |
public float boundMinY = -150; | |
public float boundMaxY = 150; | |
Vector2 touch0StartPosition; | |
Vector2 touch0LastPosition; | |
float touch0StartTime; | |
bool cameraControlEnabled = true; | |
bool canUseMouse; | |
/// <summary> Has the player at least one finger on the screen? </summary> | |
public bool isTouching { get; private set; } | |
/// <summary> The point of contact if it exists in Screen space. </summary> | |
public Vector2 touchPosition { get { return touch0LastPosition; } } | |
void Start() | |
{ | |
EnablePan = true; | |
canUseMouse = Application.platform != RuntimePlatform.Android && Application.platform != RuntimePlatform.IPhonePlayer && Input.mousePresent; | |
} | |
void Update() | |
{ | |
if (EnablePan) | |
{ | |
if (useMouse && canUseMouse) | |
{ | |
UpdateWithMouse(); | |
} | |
else | |
{ | |
UpdateWithTouch(); | |
} | |
} | |
} | |
void LateUpdate() | |
{ | |
CameraInBounds(); | |
} | |
public void DeselectScript() | |
{ | |
EnablePan = false; | |
//isTouching = false; | |
Debug.Log("DeselectScript is working ? " + EnablePan); | |
//Debug.Log("isTouching is working 1 ? " + ignoreUI); | |
Update(); | |
} | |
public void SelectScript() | |
{ | |
EnablePan = true; | |
Debug.Log("SelectScript is working ? " + EnablePan); | |
//Start(); | |
Update(); | |
} | |
public void UpdateWithMouse() | |
{ | |
if (Input.GetMouseButtonDown(0)) | |
{ | |
if (ignoreUI || !IsPointerOverUIObject()) | |
{ | |
touch0StartPosition = Input.mousePosition; | |
touch0StartTime = Time.time; | |
touch0LastPosition = touch0StartPosition; | |
isTouching = true; | |
if (onStartTouch != null) onStartTouch(Input.mousePosition); | |
} | |
} | |
if (Input.GetMouseButton(0) && isTouching) | |
{ | |
Vector2 move = (Vector2)Input.mousePosition - touch0LastPosition; | |
touch0LastPosition = Input.mousePosition; | |
if (move != Vector2.zero) | |
{ | |
OnSwipe(move); | |
} | |
} | |
if (Input.GetMouseButtonUp(0) && isTouching) | |
{ | |
if (Time.time - touch0StartTime <= maxDurationForTap | |
&& Vector2.Distance(Input.mousePosition, touch0StartPosition) <= maxDistanceForTap) | |
{ | |
OnClick(Input.mousePosition); | |
} | |
if (onEndTouch != null) onEndTouch(Input.mousePosition); | |
isTouching = false; | |
cameraControlEnabled = true; | |
} | |
if (Input.mouseScrollDelta.y != 0) | |
{ | |
OnPinch(Input.mousePosition, 1, Input.mouseScrollDelta.y < 0 ? (1 / mouseScrollSpeed) : mouseScrollSpeed, Vector2.right); | |
} | |
} | |
void UpdateWithTouch() | |
{ | |
int touchCount = Input.touches.Length; | |
if (touchCount == 1) | |
{ | |
Touch touch = Input.touches[0]; | |
switch (touch.phase) | |
{ | |
case TouchPhase.Began: | |
{ | |
if (ignoreUI || !IsPointerOverUIObject()) | |
{ | |
touch0StartPosition = touch.position; | |
touch0StartTime = Time.time; | |
touch0LastPosition = touch0StartPosition; | |
isTouching = true; | |
if (onStartTouch != null) onStartTouch(touch0StartPosition); | |
} | |
break; | |
} | |
case TouchPhase.Moved: | |
{ | |
touch0LastPosition = touch.position; | |
if (touch.deltaPosition != Vector2.zero && isTouching) | |
{ | |
OnSwipe(touch.deltaPosition); | |
} | |
break; | |
} | |
case TouchPhase.Ended: | |
{ | |
if (Time.time - touch0StartTime <= maxDurationForTap | |
&& Vector2.Distance(touch.position, touch0StartPosition) <= maxDistanceForTap | |
&& isTouching) | |
{ | |
OnClick(touch.position); | |
} | |
if (onEndTouch != null) onEndTouch(touch.position); | |
isTouching = false; | |
cameraControlEnabled = true; | |
break; | |
} | |
case TouchPhase.Stationary: | |
case TouchPhase.Canceled: | |
break; | |
} | |
} | |
else if (touchCount == 2) | |
{ | |
Touch touch0 = Input.touches[0]; | |
Touch touch1 = Input.touches[1]; | |
if (touch0.phase == TouchPhase.Ended || touch1.phase == TouchPhase.Ended) return; | |
isTouching = true; | |
float previousDistance = Vector2.Distance(touch0.position - touch0.deltaPosition, touch1.position - touch1.deltaPosition); | |
float currentDistance = Vector2.Distance(touch0.position, touch1.position); | |
if (previousDistance != currentDistance) | |
{ | |
OnPinch((touch0.position + touch1.position) / 2, previousDistance, currentDistance, (touch1.position - touch0.position).normalized); | |
} | |
} | |
else | |
{ | |
if (isTouching) | |
{ | |
if (onEndTouch != null) onEndTouch(touch0LastPosition); | |
isTouching = false; | |
} | |
cameraControlEnabled = true; | |
} | |
} | |
void OnClick(Vector2 position) | |
{ | |
if (onTap != null && (ignoreUI || !IsPointerOverUIObject())) | |
{ | |
onTap(position); | |
} | |
} | |
void OnSwipe(Vector2 deltaPosition) | |
{ | |
if (onSwipe != null) | |
{ | |
onSwipe(deltaPosition); | |
} | |
if (controlCamera && cameraControlEnabled) | |
{ | |
if (cam == null) cam = Camera.main; | |
cam.transform.position -= (cam.ScreenToWorldPoint(deltaPosition) - cam.ScreenToWorldPoint(Vector2.zero)); | |
} | |
} | |
void OnPinch(Vector2 center, float oldDistance, float newDistance, Vector2 touchDelta) | |
{ | |
if (onPinch != null) | |
{ | |
onPinch(oldDistance, newDistance); | |
} | |
if (controlCamera && cameraControlEnabled) | |
{ | |
/*if (cam == null)*/ | |
//cam = Camera.main; | |
if (cam.orthographic) | |
{ | |
var currentPinchPosition = cam.ScreenToWorldPoint(center); | |
cam.orthographicSize = Mathf.Max(0.1f, cam.orthographicSize * oldDistance / newDistance); | |
//Debug.Log("Camera Size is: " + cam.orthographicSize); | |
var newPinchPosition = cam.ScreenToWorldPoint(center); | |
cam.transform.position -= newPinchPosition - currentPinchPosition; | |
//Debug.Log("Camera new Size is: " + cam.transform.position); | |
} | |
else | |
{ | |
cam.fieldOfView = Mathf.Clamp(cam.fieldOfView * oldDistance / newDistance, 0.1f, 179.9f); | |
} | |
if (cam2.orthographic) | |
{ | |
var currentPinchPosition2 = cam2.ScreenToWorldPoint(center); | |
cam2.orthographicSize = cam.orthographicSize - 154.665f; | |
//Debug.Log("Camera Size is: " + cam2.orthographicSize); | |
var newPinchPosition2 = cam2.ScreenToWorldPoint(center); | |
cam2.transform.position -= newPinchPosition2 - currentPinchPosition2; | |
//Debug.Log("Camera new Size is: " + cam2.transform.position); | |
} | |
else | |
{ | |
cam2.fieldOfView = Mathf.Clamp(cam2.fieldOfView * oldDistance / newDistance, 0.1f, 179.9f); | |
} | |
} | |
} | |
/// <summary> Checks if the the current input is over canvas UI </summary> | |
public bool IsPointerOverUIObject() | |
{ | |
if (EventSystem.current == null) return false; | |
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); | |
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y); | |
List<RaycastResult> results = new List<RaycastResult>(); | |
EventSystem.current.RaycastAll(eventDataCurrentPosition, results); | |
return results.Count > 0; | |
} | |
/// <summary> Cancels camera movement for the current motion. Resets to use camera at the end of the touch motion.</summary> | |
public void CancelCamera() | |
{ | |
cameraControlEnabled = false; | |
} | |
void CameraInBounds() | |
{ | |
if (controlCamera && useBounds && cam != null && cam.orthographic) | |
{ | |
cam.orthographicSize = Mathf.Min(cam.orthographicSize, ((boundMaxY - boundMinY) / 2) - 0.001f); | |
cam.orthographicSize = Mathf.Min(cam.orthographicSize, (Screen.height * (boundMaxX - boundMinX) / (2 * Screen.width)) - 0.001f); | |
Vector2 margin = cam.ScreenToWorldPoint((Vector2.up * Screen.height / 2) + (Vector2.right * Screen.width / 2)) - cam.ScreenToWorldPoint(Vector2.zero); | |
float marginX = margin.x; | |
float marginY = margin.y; | |
float camMaxX = boundMaxX - marginX; | |
float camMaxY = boundMaxY - marginY; | |
float camMinX = boundMinX + marginX; | |
float camMinY = boundMinY + marginY; | |
float camX = Mathf.Clamp(cam.transform.position.x, camMinX, camMaxX); | |
float camY = Mathf.Clamp(cam.transform.position.y, camMinY, camMaxY); | |
cam.transform.position = new Vector3(camX, camY, cam.transform.position.z); | |
} | |
} | |
} |
It is indeed copied. But with the changes i wanted to implement. You can diff and see yourself. Neither did i claim it to be mine.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Looks like a direct rip of https://github.com/GibsS/unity-pan-and-zoom/blob/master/PanAndZoom.cs