- Home /
Pinch Zoom and Pan while not calling other functions
I am trying to be able to pinch zoom and pan while not calling other functions. I have my 2D game setup with tiles that are clicked, which brings up a menu to do things to the tile clicked. I have set up pinch zoom and pan, which work mostly well. Problem is that when I either try to pan or zoom over any of the tiles, it also brings up the menu like I clicked the tile as well. I have been reading posts about pinch zoom and pan for hours now, trying to figure this out. I have not seen any other post trying to accomplish this. This is my touch controls part of my InputManager script. Any help is greatly appreciated.
//for panning
private Vector3 lastPanPosition;
private int panFingerId; // Touch mode only
//for zooming
public float perspectiveZoomSpeed = 0.5f; // The rate of change of the field of view in perspective mode.
public float orthoZoomSpeed = 0.5f; // The rate of change of the orthographic size in orthographic mode.
static public float pinchDistanceDelta;
static public float pinchDistance;
const float minPinchDistance = 0;
const float pinchRatio = 1;
//touch player input
public void GetPlayerInput()
{
int nbTouches = Input.touchCount;
switch (Input.touchCount)
{
case 1: // Panning //one finger
// If the touch began, capture its position and its finger ID.
// Otherwise, if the finger ID of the touch doesn't match, skip it.
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
lastPanPosition = Input.GetTouch(0).position;
panFingerId = Input.GetTouch(0).fingerId;
//checks if over UI, false = not UI, true = Ui
if (!IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
//creates ray from camera to touch location
ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, LayerMask.GetMask("InnerCity", "OuterCity")))
{
currentGameObject = hitInfo.transform.gameObject;
clickedTileCheck(currentGameObject);
}
}
else if(IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
Debug.Log("Hit UI");
}
}
else if (Input.GetTouch(0).fingerId == panFingerId && Input.GetTouch(0).phase == TouchPhase.Moved)
{
//sends touch position to PanCamera function
PanCamera(Input.GetTouch(0).position);
}
break;
case 2: // Zooming //2 fingers
//wasZoomingLastFrame = false;
Debug.Log("Used two fingers.");
pinchDistance = pinchDistanceDelta = 0;
// Store both touches.
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
//checks if either finger is moving
if (touchZero.phase == TouchPhase.Moved || touchOne.phase == TouchPhase.Moved)
{
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
// Check if greater than threshold. If it is, then it is a pinch
if(Mathf.Abs( deltaMagnitudeDiff) > minPinchDistance)
{
deltaMagnitudeDiff *= pinchRatio;
}
else
{
pinchDistance = pinchDistanceDelta = 0;
}
// If the camera is orthographic...
if (cam.orthographic)
{
// ... change the orthographic size based on the change in distance between the touches.
cam.orthographicSize += deltaMagnitudeDiff * orthoZoomSpeed;
// Make sure the orthographic size never drops below zero.
cam.orthographicSize = Mathf.Max(cam.orthographicSize, 0.1f);
}
else// perspective view
{
// Otherwise change the field of view based on the change in distance between the touches.
cam.fieldOfView += deltaMagnitudeDiff * perspectiveZoomSpeed;
// Clamp the field of view to make sure it's between 0 and 180.
cam.fieldOfView = Mathf.Clamp(cam.fieldOfView, 0.1f, 179.9f);
}
}
break;
default:
//wasZoomingLastFrame = false;
break;
}
}
void PanCamera(Vector3 newPanPosition)
{
Debug.Log(newPanPosition+" Pan Camera Function.");
// Determine how much to move the camera
Vector3 offset = Camera.main.ScreenToViewportPoint(lastPanPosition - newPanPosition);
Vector3 move = new Vector3(offset.x * PanSpeed, 0, offset.y * PanSpeed);
// Perform the movement
cam.transform.Translate(move, Space.World);
// Ensure the camera remains within bounds.
Vector3 pos = cam.transform.position;
pos.x = Mathf.Clamp(cam.transform.position.x, BoundsX[0], BoundsX[1]);
pos.z = Mathf.Clamp(cam.transform.position.z, BoundsZ[0], BoundsZ[1]);
cam.transform.position = pos;
// Cache the position
lastPanPosition = newPanPosition;
}
Answer by panoramabeats · Jul 11, 2017 at 07:57 AM
My first thought would be that with a 2-finger zoom, it would really matter which finger came down first- particularly if the first touch (even if seemingly simultaneous) touched one of the tiles.
Some scripting could be applied where a tile doesn't expand a menu until after at least a half second, with logic that prevented a menu from opening if 2 fingers are present.
I will try your suggestion and report back once I get it and test it. Thank you for your reply
I got it to work mostly by using a coroutine that waits 0.5f seconds before doing single click operations. I have to hold the tile for 0.5f without moving to open menu though. But this helped me get way closer to the goal.
public void GetPlayerInput(){
switch(Input.touchCount){
case 1:
StartCoroutine(SingleClick());
break;
case 2:
//Do stuff
break;
}
}
IEnumerator SingleClick()
{
//wait half a second
yield return new WaitForSeconds(0.5f);
if (Input.touchCount == 1)
{
// If the touch began, capture its position and its finger ID.
// Otherwise, if the finger ID of the touch doesn't match, skip it.
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
lastPanPosition = Input.GetTouch(0).position;
panFingerId = Input.GetTouch(0).fingerId;
//called to add wait before sending raycast
StartCoroutine(SingleClick());
//checks if over UI, false = not UI, true = Ui
if (!IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
//creates ray from camera to touch location
ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
if (Physics.Raycast(ray, out hitInfo, $$anonymous$$athf.Infinity, Layer$$anonymous$$ask.Get$$anonymous$$ask("InnerCity", "OuterCity")))
{
currentGameObject = hitInfo.transform.gameObject;
clickedTileCheck(currentGameObject);
}
}
else if (IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
Debug.Log("Hit UI");
}
}
else if (Input.GetTouch(0).fingerId == panFingerId && Input.GetTouch(0).phase == TouchPhase.$$anonymous$$oved)
{
//sends touch position to PanCamera function
PanCamera(Input.GetTouch(0).position);
}
}
}