相机多点触摸放大,旋转,聚焦功能实现

1.主要是有两个脚本实现的,CameraCntrl 这个脚本主要是显现对一个场景拖拽,旋转,放大缩小,其实就是在该场景中放了一个参考点cameraPivot,然后相机针对这个参考点进行拉近,旋转,这个脚本挂在在摄像机上,其中聚焦功能就是双击一个物体,摄像机朝向该物体移动,并居中显示,该物体上挂在一个脚本DoubleClick,其实所谓的居中显示就是把摄像机的参考点移动到被点击的物体上,然后拉近距离,UI布局和CameraCntrl 脚本如下:

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

public class CameraCntrl : MonoBehaviour
{
public Transform cameraPivot; //摄相机参考点
public float distance = 13.7f; //摄像机与参考点默认距离
public float distanceMax = 30; //距离最大值
public float mouseSpeed = 8f; //鼠标拖动速度
public float mouseScroll = 12.7f; //鼠标滚轮移动速度
public float mouseSmoothingFactor = 0.08f; //缓冲时间
public float camDistanceSpeed = 0.7f; //摄像机移动缓冲时间
public float camBottomDistance = 1f; //摄像机底部一米左右做检测,是否碰到物体

public Vector2 endone; //用来实现手指触摸结束点,偏于实现放大缩小的计算
public Vector2 endtwo;

public float DPI = 0; //根据比值计算移动速度

private bool camBottom; //用来限制上下拖拽场景的范围
private float desiredDistance; //期望的摄像机与参考点的距离
private float lastDistance; //上一次的距离
private float mouseX = 60f; //x旋转角度
public float mouseXSmooth = 0f; //鼠标x缓冲时间
private float mouseXVel = 0f; //x移动速度向量
private float mouseY = 0f;
public float mouseYSmooth = 0f;
private float mouseYVel;
private float mouseYMin = -89.5f; //y旋转最小角度
private float mouseYMax = 89.5f; //
private float distanceVel; //距离向量
private Vector3 desiredPosition; //期望的位置
private float camepivotMoveSpeed = 12f; //摄像机参考点移动速度


// Use this for initialization
void Start ()
{
//DPI比例
DPI = 1080f / Screen.width;

distance = Mathf.Clamp(distance, 0.05f, distanceMax);
desiredDistance = distance;

mouseX = 0f;
mouseY = 60f;

}

// Update is called once per frame
void LateUpdate ()
{
if (cameraPivot == null)
{
return;
}

GetInput();
GetDesiredPosition();
PositionUpdate();


}

void GetInput()
{
if (distance > 0.1)
{
camBottom = Physics.Linecast(transform.position, transform.position - Vector3.up * camBottomDistance);//检测是否有碰撞与摄像机到摄像机底部的射线交叉
Debug.DrawLine(transform.position, transform.position - Vector3.up * camBottomDistance, Color.green);
}

bool constrainMouseY = camBottom && transform.position.y - cameraPivot.transform.position.y <= 0;
Debug.DrawLine(transform.position, cameraPivot.transform.position, Color.green);

if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
mouseX += Input.GetTouch(0).deltaPosition.x * mouseSpeed * DPI;

if (constrainMouseY)
{
if (Input.GetTouch(0).deltaPosition.y < 0)
mouseY -= Input.GetTouch(0).deltaPosition.y * mouseSpeed * DPI;
}
else
mouseY -= Input.GetTouch(0).deltaPosition.y * mouseSpeed * DPI;
}

//当点击UI的时候不能对场景进行旋转和控制
if ( !EventSystem.current.IsPointerOverGameObject())
{
if (Input.GetMouseButton(0))
{
mouseX += Input.GetAxis("Mouse X") * mouseSpeed;

if (constrainMouseY)
{
if (Input.GetAxis("Mouse Y") < 0)
mouseY -= Input.GetAxis("Mouse Y") * mouseSpeed;
}
else
mouseY -= Input.GetAxis("Mouse Y") * mouseSpeed;
}
}

mouseY = ClampAngle(mouseY, 0f, 90f);
mouseXSmooth = Mathf.SmoothDamp(mouseXSmooth, mouseX, ref mouseXVel, mouseSmoothingFactor);
mouseYSmooth = Mathf.SmoothDamp(mouseYSmooth, mouseY, ref mouseYVel, mouseSmoothingFactor);


mouseYSmooth = ClampAngle(mouseYSmooth, mouseYMin, mouseYMax);

if (Input.touchCount == 2)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(1).phase == TouchPhase.Moved)
{
Vector2 startone = Input.GetTouch(0).position;
Vector2 starttwo = Input.GetTouch(1).position;

if (isEnlarge(startone, starttwo, endone, endtwo))
{
if (desiredDistance < 30f)
{
desiredDistance += 0.5f;
}
}
else
{
if (desiredDistance > 5f)
{
desiredDistance -= 0.5f;
}
}
endone = startone;
endtwo = starttwo;
}
}

else
{
desiredDistance = desiredDistance - Input.GetAxis("Mouse ScrollWheel") * mouseScroll;
}

if (desiredDistance > distanceMax)
desiredDistance = distanceMax;

if (desiredDistance < 1.25f)
desiredDistance = 1.25f;

}

void GetDesiredPosition()
{
distance = desiredDistance;
desiredPosition = GetCameraPostion(mouseYSmooth, mouseXSmooth, distance);

distance -= Camera.main.nearClipPlane;
if (lastDistance < distance)
{
distance = Mathf.SmoothDamp(lastDistance, distance, ref distanceVel, camDistanceSpeed); //实现差值移动
}
else
{
if (DoubleClick._instance.isClickDouble)
camDistanceSpeed = 0.1f;
else
camDistanceSpeed = 0.7f;

distance = Mathf.SmoothDamp(lastDistance, distance, ref distanceVel, camDistanceSpeed);
}

if (distance < 0.05f)
distance = 0.05f;

lastDistance = distance;
desiredPosition = GetCameraPostion(mouseYSmooth, mouseXSmooth, distance);

}

void PositionUpdate()
{
Quaternion rotate = transform.rotation;

transform.position = desiredPosition;
DoubleClick dc = DoubleClick._instance;

if (dc.isClickDouble)
{
Vector3 targetPos = dc.transform.position; //参考点位置
Vector3 targetDis = targetPos + new Vector3(2,2,2); //相机最终停留位置
cameraPivot.position = Vector3.Lerp(cameraPivot.position, targetPos, Time.deltaTime * camepivotMoveSpeed);
cameraPivot.rotation = dc.transform.rotation;

float startDis = Vector3.Distance(transform.position, targetPos);
float endDis = Vector3.Distance(targetPos, targetDis);

if (startDis - endDis > 0.5f) //高于目标位置点
{
desiredDistance = Mathf.Lerp(startDis, endDis, Time.deltaTime * 10f);
string str = desiredDistance.ToString("F2"); //取整是因为条件为差值,一次双击结束,迅速点击会有轻微抖动效果,取整去除抖动
desiredDistance = float.Parse(str);

}
else //低于目标位置点,之所以这样区分,为了解决相机来回抖动
{
desiredDistance = endDis;
}


if (Mathf.Abs(endDis - desiredDistance) < 0.05f) //双击定位结束,必须是相机定位到目标点,且相机参考点已经移位到被点击物体位置
{
if (Vector3.Distance(targetPos, cameraPivot.position) < 0.5f && Vector3.Distance(cameraPivot.position, targetPos) < 0.005f)
dc.isClickDouble = false;
}

}

if (distance > 0.05f)
{
transform.LookAt(cameraPivot);
if (dc.isClickDouble)
{
transform.rotation = rotate; //消除点击时候的相机摇摆
}
}


float x = Input.GetAxis("Vertical");
cameraPivot.transform.position += Quaternion.Euler(mouseYSmooth, mouseXSmooth, 0) * new Vector3(0, 0, x * 0.15f);
float y = Input.GetAxis("Horizontal");
cameraPivot.transform.position += Quaternion.Euler(mouseYSmooth, mouseXSmooth, 0) * new Vector3(y * 0.15f, 0, 0);

if (Input.GetMouseButton(2))
{
//中间轮子点击进行位置左右上下移动
float yWay = Input.GetAxis("Mouse X");
cameraPivot.transform.position -= Quaternion.Euler(mouseYSmooth, mouseXSmooth, 0) * new Vector3(yWay * 0.85f, 0, 0);
float xWay = Input.GetAxis("Mouse Y");
cameraPivot.transform.position -= Quaternion.Euler(mouseYSmooth, mouseXSmooth, 0) * new Vector3(0, xWay * 1.05f, 0);
}

//限制摄像机参考点的位置范围,从而限制摄像机的位置范围
cameraPivot.transform.position = new Vector3(Mathf.Clamp(cameraPivot.transform.position.x, -20f, 10f), Mathf.Clamp(cameraPivot.transform.position.y, -10f, 10f), Mathf.Clamp(cameraPivot.transform.position.z, -10f, 30f));
}

float ClampAngle(float angle, float min, float max)
{
while (angle < -360 || angle > 360)
{
if (angle < -360)
angle += 360;

if (angle > 360)
angle -= 360;

}
return Mathf.Clamp(angle, min, max);
}

bool isEnlarge(Vector2 oP1, Vector2 oP2, Vector2 nP1, Vector2 nP2)
{
//函数传入上一次触摸两点的位置与本次触摸两点的位置计算出用户的手势
float leng1 = Mathf.Sqrt((oP1.x - oP2.x) * (oP1.x - oP2.x) + (oP1.y - oP2.y) * (oP1.y - oP2.y));
float leng2 = Mathf.Sqrt((nP1.x - nP2.x) * (nP1.x - nP2.x) + (nP1.y - nP2.y) * (nP1.y - nP2.y));
if (leng1 < leng2)
{
//放大手势
return true;
}
else
{
//缩小手势
return false;
}
}

Vector3 GetCameraPostion(float xAxis, float yAxis, float diastance)
{
Vector3 offset = new Vector3(0,0, -distance);
Quaternion rotation = Quaternion.Euler(xAxis, yAxis, 0);
return cameraPivot.position + rotation * offset;
}
}

2.另外一个脚本DoubleClick是挂在的要居中显示的物体上的

代码如下:

using UnityEngine;
using System.Collections;

public class DoubleClick : MonoBehaviour
{
public static DoubleClick _instance;
public bool isClickDouble;

private bool isClickOne;
private float timer = 0.5f;


// Use this for initialization
void Awake ()
{
_instance = this;
}

// Update is called once per frame
void Update ()
{
if (isClickOne)
{
timer -= Time.deltaTime;
if (timer <= 0)
{
isClickOne = false;
timer = 0.5f;
}
}
}

void OnMouseDown()
{
if (isClickOne)
{
//处理双击事件
isClickDouble = true;

}
else
{
isClickOne = true;
}

}
}

原文地址:https://www.cnblogs.com/xwwFrank/p/4778542.html