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

 using UnityEngine;
using System.Collections; public class CameraController : MonoBehaviour { public GameObject player; private Vector3 offset; void Start ()
{
offset = transform.position - player.transform.position;
} void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}

简单相机移动

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

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

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

 using UnityEngine;
using System.Collections; public class FollowBehavior : MonoBehaviour { public Transform trackingTarget;
public float offsetX = 5.0f;
public float offsetY = 4.0f;
public float followSpeed = 1.0f; public bool isXLocked = false;
public bool isYLocked = false;
// Use this for initialization
void Start () {
//m_offset = transform.position - trackingTarget.position;
} // Update is called once per frame
void LateUpdate () {
//transform.position = trackingTarget.position + m_offset;
float newX = transform.position.x;
float targetX = trackingTarget.position.x + offsetX;
if (!isXLocked)
{
newX = Mathf.Lerp(newX, targetX, Time.deltaTime * followSpeed);
}
float newY = transform.position.y;
float targetY = trackingTarget.position.y + offsetY;
if (!isYLocked)
{
newY = Mathf.Lerp(newY, targetY, Time.deltaTime * followSpeed);
}
transform.position = new Vector3(newX , newY , transform.position.z);
}
}

平滑的跟踪

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

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

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

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

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

         void DragCamera()
{
Vector3 nowMousePos = Input.mousePosition;
Vector3 move = nowMousePos - m_originDragPos;
move = Camera.main.ScreenToViewportPoint(move) * DragSpeed * -;
//平移没有差值运算
transform.Translate(move);
float x = Mathf.Clamp(transform.position.x, minXAndY.x, maxXAndY.x);
float y = Mathf.Clamp(transform.position.y, minXAndY.y, maxXAndY.y);
Vector3 pos = new Vector3(x , y , transform.position.z);
transform.position = pos;
m_originDragPos = nowMousePos;
} // Update is called once per frame
void Update()
{
int mouse = (int)MouseType.LEFT;
//记录某一帧时按下的状态(之后的持续按下都返回false,知道下次释放在按下返回true)
if (Input.GetMouseButtonDown(mouse))
{
m_bIsDrag = true;
//屏幕坐标系
m_originDragPos = Input.mousePosition;
return;
}
//表示当前的释放
if (!Input.GetMouseButton(mouse))
{
m_bIsDrag = false;
return;
}
} void LateUpdate()
{
if (m_bIsDrag)
{
DragCamera();
}
}

拖拽代码

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

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

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

 // Update is called once per frame
void Update()
{
int mouse = (int)MouseType.LEFT;
//记录某一帧时按下的状态(之后的持续按下都返回false,知道下次释放在按下返回true)
if (Input.GetMouseButtonDown(mouse))
{
//不能是UI层
PointerEventData pointerData = new PointerEventData(EventSystem.current);
pointerData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, results); if (results.Count > )
{
if (results[].gameObject.layer == LayerMask.NameToLayer("UI"))
{
return;
}
}
m_bIsDrag = true;
//屏幕坐标系
m_originDragPos = Input.mousePosition;
return;
}
//表示当前的释放
if (!Input.GetMouseButton(mouse))
{
m_bIsDrag = false;
return;
}
}

屏蔽UI

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

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

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

   相机移动的例子

Unity3d学习 相机的跟随的更多相关文章

  1. unity3d之相机跟随人物

    一.第三人称视角 _1 先设置好相机与玩家之间的角度 给相机添加代码 using UnityEngine; using System.Collections; namespace CompletePr ...

  2. unity3d学习笔记(一) 第一人称视角实现和倒计时实现

    unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...

  3. Unity3D学习笔记12——渲染纹理

    目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实现就 ...

  4. Unity3D学习笔记2——绘制一个带纹理的面

    目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...

  5. Unity3D学习笔记3——Unity Shader的初步使用

    目录 1. 概述 2. 详论 2.1. 创建材质 2.2. 着色器 2.2.1. 名称 2.2.2. 属性 2.2.3. SubShader 2.2.3.1. 标签(Tags) 2.2.3.2. 渲染 ...

  6. Unity3D学习笔记4——创建Mesh高级接口

    目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...

  7. Unity3D学习笔记6——GPU实例化(1)

    目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...

  8. Unity3D学习笔记7——GPU实例化(2)

    目录 1. 概述 2. 详论 2.1. 实现 2.2. 解析 3. 参考 1. 概述 在上一篇文章<Unity3D学习笔记6--GPU实例化(1)>详细介绍了Unity3d中GPU实例化的 ...

  9. Unity3D学习笔记8——GPU实例化(3)

    目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...

随机推荐

  1. LDR详解

    ARM指令集中,LDR通常都是作加载指令的,但是它也可以作伪指令. LDR伪指令的形式是"LDR Rn,=expr".下面举一个例子来说明它的用法. COUNT EQU       ...

  2. 首个threejs项目-前端填坑指南

    第一次使用threejs到实际项目中,开始的时候心情有点小激动,毕竟是第一次嘛,然而做着做着就感受到这玩意水好深,满满的都是坑,填都填不过来.经过老板20天惨无人道的摧残,终于小有成就. 因为第一次搞 ...

  3. 做一个gulp+webpack+vue的单页应用开发架子

    1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...

  4. 用scikit-learn学习谱聚类

    在谱聚类(spectral clustering)原理总结中,我们对谱聚类的原理做了总结.这里我们就对scikit-learn中谱聚类的使用做一个总结. 1. scikit-learn谱聚类概述 在s ...

  5. Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用(后续)

    在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]里面提到了Microsoft 身份认证,其实这也是一大块需要注意的地方,特作为后续补充这些知识点.上章是使用了Microsof ...

  6. 尝试asp.net mvc 基于controller action 方式权限控制方案可行性

    微软在推出mvc框架不久,短短几年里,版本更新之快,真是大快人心,微软在这种优秀的框架上做了大量的精力投入,是值得赞同的,毕竟程序员驾驭在这种框架上,能够强力的精化代码,代码层次也更加优雅,扩展较为方 ...

  7. 通过sails和阿里大于实现短信验证

    通过sails与阿里大于来实现注册短信验证码的发送,逻辑图如下 1.用户在客户端发送手机号给服务器,服务器接收到手机号,生成对应时间戳,随机四位数验证码 2.服务器将电话号码和验证码告诉阿里大于服务器 ...

  8. Register-SPWorkflowService 404

    最近需要做一个SharePoint 2013工作流演示环境. 于是在自己的本子上安装了一个虚拟机. 虚拟机操作系统是Windows Server 2012 R2,计划把AD.SQL Server 20 ...

  9. iOS 自定义方法 - 不完整边框

    示例代码 ///////////////////////////OC.h////////////////////////// ////  UIView+FreeBorder.h//  BHBFreeB ...

  10. Linux设备管理(五)_写自己的sysfs接口

    我们在Linux设备管理(一)_kobject, kset,ktype分析一文中介绍了kobject的相关知识,在Linux设备管理(二)_从cdev_add说起和Linux设备管理(三)_总线设备的 ...