• Unity3d学习 相机的跟随


      最近在写关于相机跟随的逻辑,其实最早接触相机跟随是在Unity官网的一个叫Roll-a-ball tutorial上,其中简单的涉及了关于相机如何跟随物体的移动而移动,如下代码:

     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class CameraController : MonoBehaviour {
     5 
     6     public GameObject player;
     7 
     8     private Vector3 offset;
     9 
    10     void Start ()
    11     {
    12         offset = transform.position - player.transform.position;
    13     }
    14     
    15     void LateUpdate ()
    16     {
    17         transform.position = player.transform.position + offset;
    18     }
    19 }
    简单相机移动

      可以很容易的理解上述的代码: 在初始化时计算与对应物体的向量差值,然后在LateUpdate中对相机位置进行及时更新,至于为什么要放在LateUpdate,因为LateUpdate是等所有脚本的Update跑完之后

    在更新自己的逻辑,这样相机得到物体的位置往往是最新的 。具体可以看 Unity关于脚本生命周期 中有提到。

      上述的代码 , 相机是实时跟踪的, 其实相机的跟踪可以变的跟平滑一点,可以利用Unity中的Mathf.Lerp,在每一帧做一个线性的差值,这样的话可以使相机跟随变的更平滑一点,如下优化的代码:

     1 using UnityEngine;
     2 using System.Collections;
     3 
     4 public class FollowBehavior : MonoBehaviour {
     5 
     6     public Transform trackingTarget;
     7     public float offsetX = 5.0f;
     8     public float offsetY = 4.0f;
     9     public float followSpeed = 1.0f;
    10 
    11     public bool isXLocked = false;
    12     public bool isYLocked = false;
    13     // Use this for initialization
    14     void Start () {
    15         //m_offset = transform.position - trackingTarget.position;
    16     }
    17     
    18     // Update is called once per frame
    19     void LateUpdate () {
    20         //transform.position = trackingTarget.position + m_offset;
    21         float newX = transform.position.x;
    22         float targetX = trackingTarget.position.x + offsetX;
    23         if (!isXLocked)
    24         {
    25             newX = Mathf.Lerp(newX, targetX, Time.deltaTime * followSpeed);
    26         }
    27         float newY = transform.position.y;
    28         float targetY = trackingTarget.position.y + offsetY;
    29         if (!isYLocked)
    30         {
    31             newY = Mathf.Lerp(newY, targetY, Time.deltaTime * followSpeed);
    32         }
    33         transform.position = new Vector3(newX , newY , transform.position.z);
    34     }
    35 }
    平滑的跟踪

      上述代码能满足大多数情况,但是如果一个场景里有多个焦点呢? 比如现在要满足的业务条件是:    

    •  当鼠标对屏幕进行拖拽时,需要移动相机
    •  当有多个焦点时,如何更好的切换

      我们先来实现第一个需求,先讲讲现在具备哪些条件:

    • Input.GetMouseButtonDown(0) : 这个表示在某一帧按下鼠标左键,会返回true,如果你一直按着不放(返回的是false),直到你松开再按下(才会再次返回true) 可以参考文档
    • Input.GetMouseButton(0): 这个表示当前是鼠标左键按下,会返回true 可以参考文档

      通过上述接口,我们可以实现拖拽了,思路的话就不细说,看代码就行:

     1         void DragCamera()
     2         {
     3             Vector3 nowMousePos = Input.mousePosition;
     4             Vector3 move = nowMousePos - m_originDragPos;
     5             move = Camera.main.ScreenToViewportPoint(move) * DragSpeed * -1;
     6             //平移没有差值运算
     7             transform.Translate(move);
     8             float x = Mathf.Clamp(transform.position.x, minXAndY.x, maxXAndY.x);
     9             float y = Mathf.Clamp(transform.position.y, minXAndY.y, maxXAndY.y);
    10             Vector3 pos = new Vector3(x , y , transform.position.z);
    11             transform.position = pos;
    12             m_originDragPos = nowMousePos;     
    13         }
    14 
    15         // Update is called once per frame
    16         void Update()
    17         {
    18             int mouse = (int)MouseType.LEFT;
    19             //记录某一帧时按下的状态(之后的持续按下都返回false,知道下次释放在按下返回true)
    20             if (Input.GetMouseButtonDown(mouse))
    21             {
    22                 m_bIsDrag = true;
    23                 //屏幕坐标系
    24                 m_originDragPos = Input.mousePosition;
    25                 return;
    26             }
    27             //表示当前的释放
    28             if (!Input.GetMouseButton(mouse))
    29             {
    30                 m_bIsDrag = false;
    31                 return;
    32             }
    33         }
    34 
    35         void LateUpdate()
    36         {
    37             if (m_bIsDrag)
    38             {
    39                 DragCamera();
    40             }
    41         }
    拖拽代码

      这边提一下在DragCamera函数中如果OriginDragPos不及时更新,屏幕在鼠标移动时会一直移动,因为在计算是产生的move向量一直有值,所以会不断偏移,这边看需求吧。

      上述的代码已经可以实现相机的拖拽了,但是如果你的屏幕上有UI结构,按下UI结构时,点击UI结构 ,其实也会调用 Input.GetMouseButtonDown(0),就会调用拖拽函数,但是

    往往这种情况下,是不需要将m_bIsDrag设为true,所以如何优化屏蔽呢? 看如下代码:

     1 // Update is called once per frame
     2         void Update()
     3         {
     4             int mouse = (int)MouseType.LEFT;
     5             //记录某一帧时按下的状态(之后的持续按下都返回false,知道下次释放在按下返回true)
     6             if (Input.GetMouseButtonDown(mouse))
     7             {
     8                 //不能是UI层
     9                 PointerEventData pointerData = new PointerEventData(EventSystem.current);
    10                 pointerData.position = Input.mousePosition;
    11                 List<RaycastResult> results = new List<RaycastResult>();
    12                 EventSystem.current.RaycastAll(pointerData, results);
    13 
    14                 if (results.Count > 0)
    15                 {
    16                     if (results[0].gameObject.layer == LayerMask.NameToLayer("UI"))
    17                     {
    18                         return;
    19                     }
    20                 }
    21                 m_bIsDrag = true;
    22                 //屏幕坐标系
    23                 m_originDragPos = Input.mousePosition;
    24                 return;
    25             }
    26             //表示当前的释放
    27             if (!Input.GetMouseButton(mouse))
    28             {
    29                 m_bIsDrag = false;
    30                 return;
    31             }
    32         }
    屏蔽UI

      这边要提一下关于Unity5.X中GUI的事件系统 确定事件产生到接收 流程是 输入模块产生事件数据 PointerEventData ,通过投影模块(射线)确定具体UI , 最终到具体UI来接收数据,

    由于这不是本篇的重点,可以看一下 关于事件系统的博文 我们这里模仿了前两步骤,确定当前鼠标输入的点是否UI有就直接return.

      关于焦点确定,其实算是优化项吧 ,我这边采样的是委托/事件方式来发送对应的Tranform,当然也可以直接接口。

        相机移动的例子

  • 相关阅读:
    股票行情
    证券总结
    求职
    Android的Touch事件处理机制
    订货量、成交量、价订货量、成交量、价格与行情之间的关系
    Android下如何理解onMeasure,onLayout的过程
    并发和并行的区别
    网页布局
    计算机发展史--图灵
    计算机发展史
  • 原文地址:https://www.cnblogs.com/yuyaonorthroad/p/6258949.html
Copyright © 2020-2023  润新知