zoukankan      html  css  js  c++  java
  • 相机多点触摸放大,旋转,聚焦功能实现

    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;
    }

    }
    }

  • 相关阅读:
    Flask莫名其妙特别慢
    MySQL老是提示视图没有主键
    Mysql写入中文出错
    Sqlite向MySql导入数据
    大智慧专业财务PFFIN(N,M)函数N的取值一览表
    js的技巧
    拍拍贷年化收益率的推算
    Sqlite的多表连接更新
    Kali Linux 64位架构安装Veil-Evasion
    修改Kali Linux 2020.1主题颜色
  • 原文地址:https://www.cnblogs.com/xwwFrank/p/4778542.html
Copyright © 2011-2022 走看看