最近在写关于相机跟随的逻辑,其实最早接触相机跟随是在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. Xamarin+Prism开发详解六:DependencyService与IPlatformInitializer的关系

    祝各位2017年事业辉煌!开年第一篇博客,继续探索Xamarin.Forms… 为什么我做Xamarin开发的时候中意于Prism.Forms框架?本章为你揭晓. 实例代码地址:https://git ...

  2. 在.NET Core 里使用 BouncyCastle 的DES加密算法

    .NET Core上面的DES等加密算法要等到1.2 才支持,我们可是急需这个算法的支持,文章<使用 JavaScriptService 在.NET Core 里实现DES加密算法>需要用 ...

  3. .Net中的AOP系列之构建一个汽车租赁应用

    返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...

  4. KMP算法求解

    // KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...

  5. TSQL Identity 用法全解

    Identity是标识值,在SQL Server中,有ID列,ID属性,ID值,ID列的值等术语. Identity属性是指在创建Table时,为列指定的Identity属性,其语法是:column_ ...

  6. iOS逆向工程之Hopper+LLDB调试第三方App

    LLDB是Low Level Debugger的简称,在iOS开发的调试中LLDB是经常使用的,LLDB是Xcode内置的动态调试工具.使用LLDB可以动态的调试你的应用程序,如果你不做其他的额外处理 ...

  7. JS实现页面进入、返回定位到具体位置

    最为一个刚入职不久的小白...慢慢磨练吧... JS实现页面返回定位到具体位置 其实浏览器也自带了返回的功能,也就是说,自带了返回定位的功能.正常的跳转,返回确实可以定位,但是有些特殊场景就不适用了. ...

  8. 走进缓存的世界(三) - Memcache

    系列文章 走进缓存的世界(一) - 开篇 走进缓存的世界(二) - 缓存设计 走进缓存的世界(三) - Memcache 简介 Memcache是一个高性能的分布式内存对象缓存系统,用于动态Web应用 ...

  9. Kooboo CMS技术文档之四:Kooboo CMS的站点组成部分

    Kooboo CMS本着功能独立分离的原则,将站点分为三部分组成:用户管理,站点管理和内容数据库管理.各个功能之间既可独立使用,也可以容易组成在一起形成一个完整的系统. 用户管理 管理整个系统内的用户 ...

  10. iOS之开发中一些相关的路径以及获取路径的方法

    模拟器的位置: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs ...