在实际的项目开发中,一般需要程序抽象出一些在几何意义上有明确意义的参数,这样方便策划或美术在自己的机器上进行调试。

  下面是一个可变参的地下城摄像机的简单实现:

// 第三人称摄像机,平移和旋转会同时进行平滑
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,总有一款适合你(二)的更多相关文章

  1. 各种Camera,总有一款适合你(一)

    根据游戏类型的不一样,会需要各种各样的摄像机,下面将分享三种典型的摄像机类型:(1)地下城摄像机:(2)第三人称跟随摄像机:(3)鼠标控制旋转摄像机.将这些控制脚本拖动到场景的MainCamera上即 ...

  2. 10款流行的Markdown编辑器,总有一款适合你

    摘要:作为一个开源人,如果你不会使用Markdown语法,那你就OUT了!Markdown 是 2004 年由 John Gruberis 设计和开发的纯文本格式的语法,非常的简单实用. 作为一个开源 ...

  3. .NET5都来了,你还不知道怎么部署到linux?最全部署方案,总有一款适合你

    随着2020进入4季度,.NET5正式版也已经与大家见面了.不过,尽管 .NET Core发布已经有四五年的时间,但到目前为止,依旧有很多.NET开发者在坚守者.NET4,原因不尽相同,但最大的问题可 ...

  4. 这么多TiDB负载均衡方案总有一款适合你

    [是否原创]是 [首发渠道]TiDB 社区 前言 分布式关系型数据库TiDB是一种计算和存储分离的架构,每一层都可以独立地进行水平扩展,这样就可以做到有的放矢,对症下药. 从TiDB整体架构图可以看到 ...

  5. [Asp.net]常见word,excel,ppt,pdf在线预览方案,有图有真相,总有一款适合你!

    引言 之前项目需要,查找了office文档在线预览的解决方案,顺便记录一下,方便以后查询. 方案一 直接在浏览器中打开Office文档在页面上的链接.会弹出如下窗口: 优点:主流浏览器都支持. 缺点: ...

  6. 四大VDI客户端 总有一款适合你

    [TechTarget中国原创] 交付虚拟桌面时IT管理员必须要考虑到用户如何访问虚拟桌面,因为这会影响用户体验以及VDI部署最终的成败. IT可以转向简便的HTML5客户端,HTML 5客户端功能丰 ...

  7. 把 Console 部署成 Windows 服务,四种方式总有一款适合你!

    一:背景 1. 讲故事 上周有一个项目交付,因为是医院级项目需要在客户的局域网独立部署. 程序: netcore 2.0,操作系统: windows server 2012,坑爹的事情就来了, net ...

  8. [Asp.net]常见数据导入Excel,Excel数据导入数据库解决方案,总有一款适合你!

    引言 项目中常用到将数据导入Excel,将Excel中的数据导入数据库的功能,曾经也查找过相关的内容,将曾经用过的方案总结一下. 方案一 NPOI NPOI 是 POI 项目的 .NET 版本.POI ...

  9. 40个容易上瘾的HTML5网页游戏,总有一款适合你

    我记得姐姐家的孩子在刚刚才学会走路,说话还不能完整的时候就已经能自己用小手点出小游戏的网站来一个人自娱自乐.我一直在想这一代跟着计算机一起茁壮成长的孩子会不会也和美国那一代人一样,出现9岁的黑客和计算 ...

随机推荐

  1. 关于eclispe保存代码自动格式化的设置

    最近在项目开发,上级要求所有开发人员,代码必须格式和(Ctrl+Shift+F),但是还是会偶尔忘记格式化,今天看了有一种保存之后eclipse可以自动格式代码的设置 1.请大家在eclipse设置下 ...

  2. Spring 之autowired

    Spring中autowired主要用于装配树形值,其关键类为BeanWrapperImpl,阅读代码发现其关键方法setPropertyValue有如下一段代码. PropertyHandler p ...

  3. Linux 常用命令小结

    学习脚本几天了,总结下linux debian下脚本常用命令. Linux    1.添加删除账户 useradd / userdel    2.修改"张三"密码 passwd 张 ...

  4. 解决stackoverflow打开慢不能注册登录

    http://blog.csdn.net/dream_an/article/details/50280977 解决stackoverflow打开慢不能注册登录 标签: stack overflowfi ...

  5. c#之第一课入门

    这几天看到微软的build大会,感觉微软不甘落后他人,曾经的巨头难道又要重新崛起,不管了,为了以后的饭碗,还是简单学习一些c#吧,有时这种紧张感不错的,现在由于这种紧张感,我已经掌握的java(主要弄 ...

  6. Android 设置VPN(pptp连接方式)

    本教程以小米手机的MIUI系统为例子,教大家如何设置VPN 先找到“设置”,打开设置菜单,如下图: 在设置菜单里面找“其它连接方式” 然后找到“VPN”,点击进入: 进入VPN设置界面后,如果VPN未 ...

  7. php 方便快捷导出excel

    /** * 导出excel * @param array $column * eg: $column = [ * 'username' => '姓名', * 'age' => '年龄', ...

  8. 【国内独家首发】iPhone4 iOS7不完美越狱教程新鲜出炉

    准备工作: 1.Mac (OSX 10.8以上系统): 2.iPhone 4 (iPhone3, 1 iOS 7.0.2): 3.iPhone 4数据线一根: 4.下载越狱工具包:ios7_jb_ki ...

  9. DRY原则和Shy原则

    保障可维护性的主要诀窍是遵循DRY原则和Shy原则. 在一个系统的整个生命周期里,理解和改动这类维护工作的比例一般非常之高.为了维护的方便,要尽量将系统划分为可以独立理解与改动的模块.这就要在设计的时 ...

  10. 【Linux】——sleep无法正常休眠

    最近在开发项目的时候遇到一个问题,当使用 sleep(2) 的时候,程序居然没有按照指定的时间去休眠,但是连续执行两次 sleep(2) 的时候,程序可以正常的休眠 2 秒.真是见鬼了.最后查看了以下 ...