效果如下:

代码如下:

public class TPSCamera : MonoBehaviour
{
/// <summary>
/// 目标对象
/// </summary>
[SerializeField]
Transform target = null; /// <summary>
/// 旋转参数
/// </summary>
[SerializeField]
Vector2 rotate; /// <summary>
/// 旋转速度
/// </summary>
[SerializeField]
float rotateSpeed = ; /// <summary>
/// 视口大小
/// </summary>
[SerializeField]
float viewSize = ; /// <summary>
/// 默认角度
/// 在目标对象的哪个方向
/// </summary>
[SerializeField]
float defaultAngle = -; /// <summary>
/// 离目标对象的距离
/// </summary>
[SerializeField]
float radius = ; /// <summary>
/// 离目标对象的高度
/// </summary>
[SerializeField]
float height = 1.5f; public bool Aim; public bool visiable = false; public CursorLockMode lockMode; Camera cam; /// <summary>
/// 绕任意轴旋转的参考点
/// 暂时用这个办法替代
/// </summary>
Transform tr; static TPSCamera _inst; public static TPSCamera inst
{
get {
return _inst;
}
} void Awake ()
{
_inst = this;
} void Start ()
{
cam = this.GetComponent<Camera> ();
tr = new GameObject ().transform;
} void FixedUpdate ()
{
rotate.x += Input.GetAxis ("Mouse X") * rotateSpeed;
rotate.y += Input.GetAxis ("Mouse Y") * rotateSpeed;
viewSize -= Input.mouseScrollDelta.y * ; //一些约束,不用管
if (viewSize < )
{
viewSize = ;
} else if (viewSize > )
{
viewSize = ;
} if (rotate.y < -)
{
rotate.y = -;
} else if (rotate.y > )
{
rotate.y = ;
} cam.fieldOfView = viewSize;
Cursor.visible = visiable;
Cursor.lockState = lockMode;
} void LateUpdate ()
{
Transform self = this.transform;
Vector3 targetPos = target.position;
targetPos.y += height; //旋转y轴,左右滑动
Vector2 v1 = IMath.CalcAbsolutePoint (rotate.x, radius);
self.position = targetPos + new Vector3 (v1.x, 0, v1.y); //相机的观察点
Vector2 v2 = IMath.CalcAbsolutePoint (rotate.x + defaultAngle, radius);
Vector3 viewPoint = new Vector3 (v2.x, , v2.y) + targetPos; //计算2点之间的距离
float dist = Vector3.Distance (self.position, viewPoint); //取中点作为旋转轴
Vector3 center = Vector3.MoveTowards (self.position, viewPoint, dist / ); //这里我不知道怎么计算这个任意轴,暂时先用这个方法替代
tr.position = center;
tr.LookAt (targetPos);
tr.eulerAngles += new Vector3 (, , rotate.y); //旋转x轴,上下滑动
Vector3 temp = tr.right * dist / ;
self.position = tr.position - temp;
self.LookAt (tr.position + temp); } }
public static Vector2 CalcAbsolutePoint (float angle, float dist)
{
angle += ;
dist = -dist;
float x = dist * Mathf.Cos (-angle * Mathf.PI / );
float y = dist * Mathf.Sin (-angle * Mathf.PI / );
return new Vector2 (x, y);
}

Unity 实现一个简单的 TPS 相机的更多相关文章

  1. Unity 3D 一个简单的角色控制脚本

    之所以写这个脚本,是因为我想起了我还是新手的时候,那时为了一个角色控制脚本百度了半天还是一无所获,因为看不懂啊,都写的太高级了 希望这个脚本能够帮助那些 像曾经的我一样迷失于代码中的新手们能够清晰的理 ...

  2. Hololens开发笔记之使用Unity开发一个简单的应用

    一.Hololens概述 Hololens有以下特性 1.空间映射借助微软特殊定制的全息处理单元(HPU),HoloLens 实现了对周边环境的快速扫描和空间匹配.这保证了 HoloLens能够准确地 ...

  3. 【Unity】UGUI系列教程——拼接一个简单界面

    0.简介: 在目前的游戏市场上,手游依然是市场上的主力军,而只有快速上线,玩法系统完善的游戏才能在国内市场中占据份额.而在手游开发过程中,搭建UI系统是非常基本且重要的技能,极端的说如果对Unity的 ...

  4. Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...

  5. IOS开发之小实例--使用UIImagePickerController创建一个简单的相机应用程序

    前言:本篇博文是本人阅读国外的IOS Programming Tutorial的一篇入门文章的学习过程总结,难度不大,因为是入门.主要是入门UIImagePickerController这个控制器,那 ...

  6. 使用Unity3D的设计思想实现一个简单的C#赛车游戏场景

    最近看了看一个C#游戏开发的公开课,在该公开课中使用面向对象思想与Unity3D游戏开发思想结合的方式,对一个简单的赛车游戏场景进行了实现.原本在C#中很方便地就可以完成的一个小场景,使用Unity3 ...

  7. 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  8. Unity NGUI 创建简单的按钮

    Unity版本:4.5.1 NGUI版本:3.6.5 注意NGUI版本,网上的大部分教程都是2.x版本的,在步骤上面略有不同,此文适合初学者. 示例: 通过NGUI创建一个背景和按钮. 1.首先创建一 ...

  9. 实现一个简单的Unity3D三皮卡——3D Picking (1)

    3D Picking 其原理是从摄像机位置到空间发射的射线.基于光线碰到物体回暖. 这里我们使用了触摸屏拿起触摸,鼠标选择相同的原理,仅仅是可选API不同. 从unity3D官网Manual里找到下面 ...

随机推荐

  1. 一篇文章搞懂DOM

    学习JavaScript肯定是会遇到DOM操作,那么什么是DOM?它又是干嘛用的?这篇文章为你揭晓答案. DOM是document object model的缩写,简称文档对象模型. 简单的说DOM是 ...

  2. 1503. [NOI2004]郁闷的出纳员【平衡树-splay】

    Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经 ...

  3. ASP.NET Core读取appsettings.json配置文件信息

    1.在配置文件appsettings.json里新增AppSettings节点 { "Logging": { "LogLevel": { "Defau ...

  4. 非常简单的部署脚本(JavaWeb项目)和部署项目教程

    这个部署方式,前提需要通过WinSCP工具将本地Maven项目打成zip包放到Linux对应的用户目录下,然后执行脚本便可以完成一键部署. 大家看到下面的脚本,可以发现一个显著的特点,部署脚本内容基本 ...

  5. js之radio应用实例

    radio和checkbox还有select,可谓是前后端常用三剑客啊!特别是checkbox和select,关于这两个今天不讲,因为在下面这几篇文章,我已经比较详细的讲解了. SpringMVC之a ...

  6. PAT乙级1001

    https://pintia.cn/problem-sets/994805260223102976/problems/994805325918486528 #include<bits/stdc+ ...

  7. 《You dont know JS》强制类型转换

    强制类型转换 将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况.隐式的情况被称为强制类型转换 在书中,作者还提出一种区分方式: 类型转换发生在静态类型语言的编译阶段,强制类型转换发生在动 ...

  8. P1586 四方定理

    题目描述 四方定理是众所周知的:任意一个正整数nn ,可以分解为不超过四个整数的平方和.例如:25=1^{2}+2^{2}+2^{2}+4^{2}25=12+22+22+42 ,当然还有其他的分解方案 ...

  9. 如何接好CAN的“地”

    [导读]CAN总线以其高可靠性.实时性.灵活性以及严谨的数据处理机制等特点,在工业现场和汽车行业得到广泛应用,但随着环境干扰以及节点数目的增加等对CAN总线的稳定性提出更高的要求,而面对电源地.信号地 ...

  10. 蓝牙开发<coreBluetooth/CoreBluetooth.h>

    /* 建立中心设备 扫描外设(Discover Peripheral) 连接外设(Connect Peripheral) 扫描外设中的服务和特征(Discover Services And Chara ...