Unity3d学习 相机的跟随
最近在写关于相机跟随的逻辑,其实最早接触相机跟随是在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学习 相机的跟随的更多相关文章
- unity3d之相机跟随人物
一.第三人称视角 _1 先设置好相机与玩家之间的角度 给相机添加代码 using UnityEngine; using System.Collections; namespace CompletePr ...
- unity3d学习笔记(一) 第一人称视角实现和倒计时实现
unity3d学习笔记(一) 第一人称视角实现和倒计时实现 1. 第一人称视角 (1)让mainCamera和player(视角对象)同步在一起 因为我们的player是生成的,所以不能把mainCa ...
- Unity3D学习笔记12——渲染纹理
目录 1. 概述 2. 详论 3. 问题 1. 概述 在文章<Unity3D学习笔记11--后处理>中论述了后处理是帧缓存(Framebuffer)技术实现之一:而另外一个帧缓存技术实现就 ...
- Unity3D学习笔记2——绘制一个带纹理的面
目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...
- 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. 渲染 ...
- Unity3D学习笔记4——创建Mesh高级接口
目录 1. 概述 2. 详论 3. 其他 4. 参考 1. 概述 在文章Unity3D学习笔记2--绘制一个带纹理的面中使用代码的方式创建了一个Mesh,不过这套接口在Unity中被称为简单接口.与其 ...
- Unity3D学习笔记6——GPU实例化(1)
目录 1. 概述 2. 详论 3. 参考 1. 概述 在之前的文章中说到,一种材质对应一次绘制调用的指令.即使是这种情况,两个三维物体使用同一种材质,但它们使用的材质参数不一样,那么最终仍然会造成两次 ...
- Unity3D学习笔记7——GPU实例化(2)
目录 1. 概述 2. 详论 2.1. 实现 2.2. 解析 3. 参考 1. 概述 在上一篇文章<Unity3D学习笔记6--GPU实例化(1)>详细介绍了Unity3d中GPU实例化的 ...
- Unity3D学习笔记8——GPU实例化(3)
目录 1. 概述 2. 详论 2.1. 自动实例化 2.2. MaterialPropertyBlock 3. 参考 1. 概述 在前两篇文章<Unity3D学习笔记6--GPU实例化(1)&g ...
随机推荐
- javascript中的Array对象 —— 数组的合并、转换、迭代、排序、堆栈
Array 是javascript中经常用到的数据类型.javascript 的数组其他语言中数组的最大的区别是其每个数组项都可以保存任何类型的数据.本文主要讨论javascript中数组的声明.转换 ...
- alias导致virtualenv异常的分析和解法
title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...
- Unity3d入门 - 关于unity工具的熟悉
上周由于工作内容较多,花在unity上学习的时间不多,但总归还是学习了一些东西,内容如下: .1 根据相关的教程在mac上安装了unity. .2 学习了unity的主要的工具分布和对应工具的相关的功 ...
- 【AutoMapper官方文档】DTO与Domin Model相互转换(上)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- 当忘记mysql数据库密码时如何进行修改
因为长时间没有使用数据库了,或者把密码改完之后就忘了数据库密码,不能正常进入数据库,也无法修改密码,有一个简单的常用修改密码方式: 1.首先找到和打开mysql.exe和mysqld.exe所在的文件 ...
- HTML 获取屏幕、浏览器、页面的高度宽度
本篇主要介绍Web环境中屏幕.浏览器及页面的高度.宽度信息. 目录 1. 介绍:介绍页面的容器(屏幕.浏览器及页面).物理尺寸与分辨率.展示等内容. 2. 屏幕信息:介绍屏幕尺寸信息:如:屏幕.软件可 ...
- 从零开始编写自己的C#框架(25)——网站部署
导航 1.关掉访问保护 2.发布网站 3.复制网站到服务器 4.添加新网站 5.设置网站访问权限 6.设置文件夹访问权限 7.控制可更新文件夹执行权限 8.设置“应用程序池”.net版本与模式 9.附 ...
- JS判断鼠标进入容器方向的方法和分析window.open新窗口被拦截的问题
1.鼠标进入容器方向的判定 判断鼠标从哪个方向进入元素容器是一个经常碰到的问题,如何来判断呢?首先想到的是:获取鼠标的位置,然后经过一大堆的if..else逻辑来确定.这样的做法比较繁琐,下面介绍两种 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...