各种Camera,总有一款适合你(二)
在实际的项目开发中,一般需要程序抽象出一些在几何意义上有明确意义的参数,这样方便策划或美术在自己的机器上进行调试。
下面是一个可变参的地下城摄像机的简单实现:
// 第三人称摄像机,平移和旋转会同时进行平滑
public class ThirdPersonalCamera : MonoBehaviour
{
/// Camera Control Params
public GameObject Target = null;
public float Distance = 10f;
public float RotateX = 0f; // pitch 俯仰
public float RotateY = 0f; // yaw 偏航
public float SmoothTime = 0.01f; // 平滑时间,默认为1s
public float ScrollWheelSpeed = 1000f; // 中轴调整速度
public Vector3 TargetOffset = Vector3.zero; // 目标偏移量 private Vector3 Velocity = Vector3.zero; // 平滑初速度
private Vector3 Offset = Vector3.zero; // 根据上面三个变量计算出
private const float MinDistance = 5f; // 镜头最近距离
private const float MaxDistance = 100f; // 镜头最远距离 void Start()
{
if (Target == null) return;
} public void Shake()
{
StartCoroutine("ShakeCoroutine");
} void LateUpdate()
{
if (Target == null) return; UpdateDistance(); float radX = Mathf.Deg2Rad * RotateX;
float radY = Mathf.Deg2Rad * RotateY; Offset.x = Distance * Mathf.Cos(radX) * Mathf.Cos(radY);
Offset.z = Distance * Mathf.Cos(radX) * Mathf.Sin(radY);
Offset.y = Distance * Mathf.Sin(radX); Vector3 targetPos = Target.transform.position + Offset + TargetOffset;
transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref Velocity, SmoothTime); transform.LookAt(Target.transform.position + TargetOffset);
} private void UpdateDistance()
{
float horizontal = Input.GetAxis("Mouse ScrollWheel") * ScrollWheelSpeed * Time.deltaTime;
Distance -= horizontal;
} }
可以看到抽象出的控制参数主要包括:摄像机分别绕X轴和Y轴的旋转、摄像机距离角色的距离、以及用来控制平滑时间的参数。
注意,上面这段代码的实现中,position和rotation是同时进行平滑的,下面来看另外一种实现:
using UnityEngine;
using System.Collections; [ExecuteInEditMode]
public class MyDungeonCamera : MonoBehaviour
{
/// [摄像机控制参数]
public GameObject Target = null;
public float RotateX = 0f; // pitch 俯仰
public float RotateY = 0f; // yaw 偏航
public float Distance = 10f; // 摄像机远近
public float MoveSmoothTime = 0.3f; // 位置平滑时间,默认为1s
public float RotateSmoothTime = 0.3f; // 旋转平滑时间
public float ScrollWheelSpeed = 1000f; // 中轴调整速度
public Vector3 TargetOffset = Vector3.zero; // 目标偏移量 private Vector3 Velocity = Vector3.zero; // 平滑初速度
private Vector3 Offset = Vector3.zero; // 根据上面三个变量计算出
private const float MinDistance = 5f; // 镜头最近距离
private const float MaxDistance = 100f; // 镜头最远距离
private Quaternion tmpRotation = Quaternion.identity;
private Vector3 tmpPosition = Vector3.zero; private float RotateDamping
{
get
{
if (RotateSmoothTime <= 0f) RotateSmoothTime = 0.001f;
return 1f / RotateSmoothTime;
}
} void LateUpdate()
{
if (Target == null) return; tmpRotation = transform.rotation;
tmpPosition = transform.position; UpdateDistance();
UpdateRotation();
UpdatePosition(); transform.rotation = tmpRotation;
transform.position = tmpPosition;
} private void UpdateRotation()
{
if (!NeedRotate()) return; Quaternion wantedRotation = Quaternion.Euler(RotateX, RotateY, 0f);
// 旋转采用球形插值
tmpRotation = Quaternion.Slerp(tmpRotation, wantedRotation, Time.deltaTime * RotateDamping);
} private void UpdatePosition()
{
// 如果有旋转插值,则位置根据旋转变换;否则,位置自己进行插值过渡
if (!NeedRotate())
{
Offset = Quaternion.Euler(RotateX, RotateY, 0f) * Vector3.forward * Distance;
Vector3 wantedPos = Target.transform.position - Offset + TargetOffset;
// 位置采用平滑阻尼过渡
tmpPosition = Vector3.SmoothDamp(tmpPosition, wantedPos, ref Velocity, MoveSmoothTime);
}
else
{
Offset = tmpRotation * Vector3.forward * Distance;
tmpPosition = Target.transform.position - Offset + TargetOffset;
}
} private void UpdateDistance()
{
float horizontal = Input.GetAxis("Mouse ScrollWheel") * ScrollWheelSpeed * Time.deltaTime;
Distance -= horizontal;
Distance = Mathf.Clamp(Distance, MinDistance, MaxDistance);
} private bool NeedRotate()
{
Vector3 eulerAngles = transform.rotation.eulerAngles;
return !(FloatEqual(eulerAngles.x, RotateX) && FloatEqual(eulerAngles.y, RotateY));
} public static bool FloatEqual(float value1, float value2)
{
float ret = value1 - value2;
return ret > -0.0005f && ret < 0.0005f;
} }
这个实现中,有几点需要注意的:
(1)rotation使用四元素球形插值,这样保证每次旋转的角速度是恒定的,不过两次旋转各自的角速度不相等,这里可以改进;
(2)position使用Vector3.SmoothDamp进行平滑阻尼过渡效果会比较好;
(3)浮点数相等判断,不要直接用等号哟;
(4)当同时有rotation和position时,以rotation为主;
(5)是否需要旋转的判断,只有需要的时候才走旋转逻辑,这样可以减轻Update的压力。
摄像机振动脚本:
public class ShakeCamera : MonoBehaviour
{
public float ShakeTime = 1f;
public float ShakeStrength = 0.2f;
private Vector3 ShakeOffset = Vector3.zero;
private Vector3 preShakeOffset = Vector3.zero; void LateUpdate()
{
transform.position = transform.position - preShakeOffset + ShakeOffset;
} public void Shake()
{
StopCoroutine("ShakeCoroutine");
StartCoroutine("ShakeCoroutine");
} public void Shake(float time)
{
ShakeTime = time;
Shake();
} IEnumerator ShakeCoroutine()
{
float endTime = Time.time + ShakeTime;
while (Time.time < endTime)
{
ShakeOffset = Random.insideUnitSphere * ShakeStrength;
yield return null;
}
ShakeOffset = Vector3.zero;
} }
各种Camera,总有一款适合你(二)的更多相关文章
- 各种Camera,总有一款适合你(一)
根据游戏类型的不一样,会需要各种各样的摄像机,下面将分享三种典型的摄像机类型:(1)地下城摄像机:(2)第三人称跟随摄像机:(3)鼠标控制旋转摄像机.将这些控制脚本拖动到场景的MainCamera上即 ...
- 10款流行的Markdown编辑器,总有一款适合你
摘要:作为一个开源人,如果你不会使用Markdown语法,那你就OUT了!Markdown 是 2004 年由 John Gruberis 设计和开发的纯文本格式的语法,非常的简单实用. 作为一个开源 ...
- .NET5都来了,你还不知道怎么部署到linux?最全部署方案,总有一款适合你
随着2020进入4季度,.NET5正式版也已经与大家见面了.不过,尽管 .NET Core发布已经有四五年的时间,但到目前为止,依旧有很多.NET开发者在坚守者.NET4,原因不尽相同,但最大的问题可 ...
- 这么多TiDB负载均衡方案总有一款适合你
[是否原创]是 [首发渠道]TiDB 社区 前言 分布式关系型数据库TiDB是一种计算和存储分离的架构,每一层都可以独立地进行水平扩展,这样就可以做到有的放矢,对症下药. 从TiDB整体架构图可以看到 ...
- [Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!
引言 之前项目需要,查找了office文档在线预览的解决方案,顺便记录一下,方便以后查询. 方案一 直接在浏览器中打开Office文档在页面上的链接.会弹出如下窗口: 优点:主流浏览器都支持. 缺点: ...
- 四大VDI客户端 总有一款适合你
[TechTarget中国原创] 交付虚拟桌面时IT管理员必须要考虑到用户如何访问虚拟桌面,因为这会影响用户体验以及VDI部署最终的成败. IT可以转向简便的HTML5客户端,HTML 5客户端功能丰 ...
- 把 Console 部署成 Windows 服务,四种方式总有一款适合你!
一:背景 1. 讲故事 上周有一个项目交付,因为是医院级项目需要在客户的局域网独立部署. 程序: netcore 2.0,操作系统: windows server 2012,坑爹的事情就来了, net ...
- [Asp.net]常见数据导入Excel,Excel数据导入数据库解决方案,总有一款适合你!
引言 项目中常用到将数据导入Excel,将Excel中的数据导入数据库的功能,曾经也查找过相关的内容,将曾经用过的方案总结一下. 方案一 NPOI NPOI 是 POI 项目的 .NET 版本.POI ...
- 40个容易上瘾的HTML5网页游戏,总有一款适合你
我记得姐姐家的孩子在刚刚才学会走路,说话还不能完整的时候就已经能自己用小手点出小游戏的网站来一个人自娱自乐.我一直在想这一代跟着计算机一起茁壮成长的孩子会不会也和美国那一代人一样,出现9岁的黑客和计算 ...
随机推荐
- 匿名管道读取CMD回显信息
之前用了很坑爹的做法去读取了cmd命令的回显信息,现在发现了用匿名管道的实现方法,由于楼主没有学过Windows核心编程,找了一个代码来凑数 存下来以后研究 #include <windows. ...
- KS8U读卡器
凯盛读卡器KS8U 厂家:http://www.chinaiccard.com/feijiechushiduxieqi/947.html 驱动安装目录的COM目录下有网页调用的例子. 公司网站:htt ...
- C#下取得Exif中照片拍摄日期
/// <summary> /// 获取Exif中的照片拍摄日期 /// </summary> /// <param name="fileName"& ...
- 如何在windows7上安装启明星系统。
启明星系统提供多种安装方式.安装包里自带了setup.exe.每个程序的 install下有在线安装(例如请假应用程序为book,则默认为 http://localhost/book/install ...
- How do I check if a type is a subtype OR the type of an object?
To check if a type is a subclass of another type in C#, it's easy: typeof (SubClass).IsSubclassOf(ty ...
- linux云主机怎么安装WDCP
linux云主机 教你成功安装WDCP的2个方法(第一个不成功就试第2个) 工具/原料 Xshell 云服务器 方法/步骤 1 先用Xshell连接你的服务器 2 输入一下代码 wget ...
- Speech两种使用方法
COM组件使用speech: public class Speach { private static Speach _Instance = null ; private SpeechLib.SpVo ...
- 学习Swift,一定不能错过的10大开源项目!
如果你是位iOS开发者,或者你正想进入该行业,那么Swift为你提供了一个绝佳的机会.Swift的设计非常优雅,较Obj-C更易于学习,当然也非常强大. 为了指导开发者使用Swift进行开发,苹果发布 ...
- 【Android开发坑系列】之try-catch
try { mViewPager.postDelayed(new Runnable() { @Override public void run() { getCurrentPage().render( ...
- A Brief History of Scaling LinkedIn
原文地址 LinkedIn started in 2003 with the goal of connecting to your network for better job opportuniti ...