环绕相机控制脚本

该脚本需要挂载在环绕相机上,而环绕相机不绑定在角色身上,而是作为一个单独的存在

此外,由于一般来说,角色的原点都在脚底,所以需要特别在角色的中心位置放置一个空对象作为视野中心,并在面板指定

相机被遮挡的判断与处理

具体分析见  Unity 相机被遮挡的判断与处理

相机的惯性旋转

具体分析见  Unity 自由视角的惯性旋转

效果

操作方式

按下鼠标左键并拖拽,可以让相机在上下和左右方向以角色为轴心旋转

鼠标滚轮可以调节视角的大小

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SurroundCamera : MonoBehaviour
{//视野中心public Transform focus;//相机相对角色的位置Vector3 RelativePosition;void Start(){RelativePosition = transform.position - focus.position;     //以人为原点A,相机为B,向量AB=B-A,B的坐标等于向量AB。unit = RelativePosition.magnitude;}void Update(){Follow();               //相机跟随if (cameraRotateBy == CameraRotateBy.MouseVelocity)              //调节视角DragToRotateView_Velocity();elseDragToRotateView_Distance();OcclusionJudge();               //视野遮挡判断if (scaleViewBy == ScaleViewBy.Distance)              //调节视野ScrollToScaleDistance();else if (scaleViewBy == ScaleViewBy.FieldOfView)ScrollToScaleView();else if (scaleViewBy == ScaleViewBy.Level)ScrollToAdjustView();}/*-----------------相机跟随------------------*/void Follow(){transform.position = focus.position + RelativePosition;             //每一帧都跟随移动}/*-----------------调整视角------------------*///相机旋转方案public CameraRotateBy cameraRotateBy = CameraRotateBy.MouseVelocity;public enum CameraRotateBy{MouseVelocity,Distance,}//最小水平夹角public float MinimumDegree = 0;//最大水平夹角public float MaximumDegree = 60;//两点连线与水平方向的夹角float currentAngleY;/*方案一以两帧之间的鼠标移动速度为依据进行旋转*/float mouseVelocityX;float mouseVelocityY;Vector3? point1;//旋转每度,在一帧中需要的速度int DragVelocityPerAngle = 170;//脱手瞬间鼠标速度float lastMouseVelocityX;float lastMouseVelocityY;void DragToRotateView_Velocity(){if (Input.GetMouseButton(0))                //按下鼠标左键的每一帧都执行{var point2 = Input.mousePosition;if (point1 != null){mouseVelocityX = -(point1.Value.x - point2.x) / Time.deltaTime;mouseVelocityY = -(point1.Value.y - point2.y) / Time.deltaTime;}point1 = point2;float anglex = mouseVelocityX / DragVelocityPerAngle;                   //将鼠标在屏幕上拖拽的速度转化为角度float angley = mouseVelocityY / DragVelocityPerAngle;currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down);            //计算两点连线与水平方向的夹角if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)angley = 0;transform.RotateAround(focus.position, Vector3.up, anglex);transform.RotateAround(focus.position, -transform.right, angley);transform.LookAt(focus);                    //如果没有这一句,摄像头转着转着就会歪RelativePosition = transform.position - focus.position;                 //更新相对位置}if(Input.GetMouseButtonUp(0))       //脱手瞬间{point1 = null;inertialRotation = true;lastMouseVelocityX = mouseVelocityX;lastMouseVelocityY = mouseVelocityY;if (lastMouseVelocityX > maxlastMouseVelocityX) lastMouseVelocityX = maxlastMouseVelocityX;else if (lastMouseVelocityX < -maxlastMouseVelocityX) lastMouseVelocityX = -maxlastMouseVelocityX;if (lastMouseVelocityX > 0) isCounterClockwise = true;else if (lastMouseVelocityX < 0) isCounterClockwise = false;//print(lastMouseVelocityX);}if(inertialRotation==true)StartCoroutine("InertialRotation");     //通过协程来实现视角的惯性旋转,调用协程只有写在Update里并且在每一帧都被调用时才会继续执行}bool inertialRotation = false;      //是否需要视角的惯性旋转float maxlastMouseVelocityX = 3000; bool isCounterClockwise;            //旋转方向IEnumerator InertialRotation()      //在旋转末尾补上一个逐渐减缓的惯性旋转{yield return null;float anglex = lastMouseVelocityX / DragVelocityPerAngle;                   //将鼠标在屏幕上拖拽的速度转化为角度float angley = lastMouseVelocityY / DragVelocityPerAngle;currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down);            //计算两点连线与水平方向的夹角if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree + 10)angley = 0;lastMouseVelocityX -= lastMouseVelocityX * 0.08f;lastMouseVelocityY -= lastMouseVelocityY * 0.08f;//print(lastMouseVelocityX);if ((isCounterClockwise && (anglex < 1))||!isCounterClockwise && (anglex > -1)){StopCoroutine("InertialRotation");inertialRotation = false;}    transform.RotateAround(focus.position, Vector3.up, anglex/3);transform.RotateAround(focus.position, -transform.right, Mathf.Abs(angley/25));transform.LookAt(focus);RelativePosition = transform.position - focus.position;}/*方案二以两帧之间的鼠标移动距离为依据进行旋转*/Vector3 Point1;Vector3 Point2;//旋转每度,在一帧中需要拖拽的距离int DragDistancePerAngle = 20;void DragToRotateView_Distance(){float v = Input.GetAxis("Vertical");float h = Input.GetAxis("Horizontal");if (!(h==0&&v==0))                  //不运动时的旋转灵敏度{DragDistancePerAngle = 17;      //松手前拖拽灵敏度sactor = 10;                    //松手后拖拽灵敏度}else                                //运动时的旋转灵敏度{DragDistancePerAngle = 8;sactor = 4;}if (Input.GetMouseButtonDown(0))                //按下鼠标左键的瞬间,记录起始位置{Point1 = Input.mousePosition;StartPoint = Point1;}if (Input.GetMouseButton(0))                //按下鼠标左键的每一帧都执行{Point2 = Input.mousePosition;float dx = Point2.x - Point1.x;float dy = Point2.y - Point1.y;float anglex = dx / DragDistancePerAngle;                   //将鼠标在屏幕上拖拽的距离转化为角度float angley = dy / DragDistancePerAngle;currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down);                    //计算两点连线与水平方向的夹角if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)angley = 0;transform.RotateAround(focus.position, Vector3.up, anglex);transform.RotateAround(focus.position, -transform.right, angley);transform.LookAt(focus);                    //如果没有这一句,摄像头转着转着就会歪RelativePosition = transform.position - focus.position;                 //更新相对位置Point1 = Point2;Point2 = Vector3.zero;}if(Input.GetMouseButtonUp(0)){EndPoint = Input.mousePosition;if (Point1!=EndPoint)                       //鼠标无速度则不进行惯性旋转inertialRotation = true;dragX = EndPoint.x - StartPoint.x;dragY = EndPoint.y - StartPoint.y;if (dragX > maxdragX) dragX = maxdragX;else if (dragX < -maxdragX) dragX = -maxdragX;if (dragX > 0) isCounterClockwise = true;else if (dragX < 0) isCounterClockwise = false;print(dragX);}if (inertialRotation == true)StartCoroutine("InertialRotation2");}Vector3 StartPoint;     //拖拽起点Vector3 EndPoint;       //拖拽终点float dragX;        //水平拖拽距离float dragY;        //垂直拖拽距离float maxdragX = 3000;float sactor = 10;  //惯性系数IEnumerator InertialRotation2()      //在旋转末尾补上一个逐渐减缓的惯性旋转{yield return null;float anglex = dragX / DragDistancePerAngle / sactor;                   //将鼠标在屏幕上拖拽的距离转化为角度float angley = dragY / DragDistancePerAngle / sactor;                   currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down);            //计算两点连线与水平方向的夹角if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree + 10)angley = 0;dragX -= dragX * 0.05f;dragY -= dragY * 0.05f;print(dragX);if ((isCounterClockwise && (anglex < 1)) || !isCounterClockwise && (anglex > -1)){StopCoroutine("InertialRotation2");inertialRotation = false;}transform.RotateAround(focus.position, Vector3.up, anglex / 4);transform.RotateAround(focus.position, -transform.right, Mathf.Abs(angley/4));transform.LookAt(focus);RelativePosition = transform.position - focus.position;}/*-----------------调整视野------------------*///鼠标滚轮灵敏度float mouseWheelSensitivity = 30;//视野调整方案public enum ScaleViewBy{Distance,FieldOfView,Level,}//视野选择列表public ScaleViewBy scaleViewBy = ScaleViewBy.Level;/*方案一调节FieldOfView*/float MinFieldOfView = 20f;float MaxFieldOfView = 100f;void ScrollToScaleView(){if (Input.GetAxis("Mouse ScrollWheel") == 0) return;GetComponent<Camera>().fieldOfView = GetComponent<Camera>().fieldOfView - Input.GetAxis("Mouse ScrollWheel") * mouseWheelSensitivity;GetComponent<Camera>().fieldOfView = Mathf.Clamp(GetComponent<Camera>().fieldOfView, MinFieldOfView, MaxFieldOfView);}/*方案二自由调节相机距离*/float MinViewDistance = 1;float MaxViewDistance = 4;void ScrollToScaleDistance(){if (Input.GetAxis("Mouse ScrollWheel") > 0){if (RelativePosition.magnitude <= MinViewDistance) return;transform.Translate(-RelativePosition / mouseWheelSensitivity *10, Space.World);RelativePosition = transform.position - focus.position;}else if (Input.GetAxis("Mouse ScrollWheel") < 0){if (RelativePosition.magnitude >= MaxViewDistance) return;transform.Translate(RelativePosition / mouseWheelSensitivity *10, Space.World);RelativePosition = transform.position - focus.position;}}/*方案三取初始距离为单位长度,随后每次调整都以此为单位用单位向量乘以单位长度即可得到位移矢量*///单位长度float unit;void ScrollToAdjustView(){if (Input.GetAxis("Mouse ScrollWheel") > 0){ViewPlus();preferdLevel = currentLevel;}else if (Input.GetAxis("Mouse ScrollWheel") < 0){ViewMinus();preferdLevel = currentLevel;}}void ViewPlus(){if (RelativePosition.magnitude <= MinViewDistance) return;transform.Translate(-RelativePosition.normalized * unit, Space.World);RelativePosition = transform.position - focus.position;currentLevel--;}void ViewMinus(){if (RelativePosition.magnitude >= MaxViewDistance) return;transform.Translate(RelativePosition.normalized * unit, Space.World);RelativePosition = transform.position - focus.position;currentLevel++;}/*-----------------视野遮挡处理------------------*//*如果视野被遮挡,就逐级拉近相机的距离如果原机位不再被遮挡,则恢复原机位*///当前视角级别int currentLevel = 1;//偏好视野级别int preferdLevel = 1;//是否需要恢复原机位bool resumable = false;void OcclusionJudge(){if (Physics.Raycast(transform.position, -RelativePosition.normalized, RelativePosition.magnitude - unit))               //如果机位被遮挡{resumable = true;while (Physics.Raycast(transform.position, -RelativePosition.normalized, RelativePosition.magnitude - unit)){ViewPlus();}}if (!resumable) return;             //如果不需要恢复Vector3 PositionToResume = focus.position + RelativePosition.normalized * unit * preferdLevel;              //计算偏好距离所在位置if (resumable && !Physics.Raycast(PositionToResume, -RelativePosition.normalized, (preferdLevel - 1) * unit))       //原机位没被遮挡,恢复原位{while (currentLevel != preferdLevel){ViewMinus();}resumable = false;}}//todo
}

自由视角的角色控制脚本

不同于一般的固定视角的角色控制脚本,该脚本适用于自由视角的角色控制。

该脚本需要挂载在角色上,并指定环绕相机的Transform属性。

操作方式

W 朝着屏幕前方走        S 面向屏幕走        A 朝着屏幕左边走        D 朝着屏幕右边走

空格 跳跃        LeftShift 行走

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//Move by Screen Reference System
public class PlayerControl : MonoBehaviour
{public Transform camera;private Rigidbody rigidbody;public float moveSpeed = 4;public float jumpForce = 200f;Animator anim;private int jumpLimit = 2;      //二段跳void Start(){rigidbody = GetComponent<Rigidbody>();anim = GetComponent<Animator>();}void FixedUpdate(){Move();Jump();}void Move(){float v = Input.GetAxis("Vertical");float h = Input.GetAxis("Horizontal");if (Input.GetKey(KeyCode.LeftShift)){h *= 0.5f;v *= 0.5f;}anim.SetFloat("SpeedX", h);anim.SetFloat("SpeedY", v);Vector3 screenRight = camera.right;             //以屏幕为参考系移动Vector3 screenForward = camera.forward;screenForward.y = 0;                            //不能有竖直分量Vector3 sumVector = screenForward * v + screenRight * h;                //矢量之和if (!(h==0&&v==0)){transform.rotation = Quaternion.LookRotation(sumVector);}transform.Translate(sumVector * moveSpeed * Time.deltaTime, Space.World);       //Space.World绝对不能少}bool IsGrounded()                   // 通过射线检测角色是在地面或者物体(角色的零点需要设置在脚底处){return Physics.Raycast(transform.position, -Vector3.up, 0.1f);}void Jump(){if (IsGrounded())                       //如果接触地面,则恢复可跳跃次数{jumpLimit = 2;anim.SetBool("Jump", false);}if (Input.GetKeyDown(KeyCode.Space)){if (jumpLimit > 0){rigidbody.AddForce(Vector3.up * jumpForce);anim.SetBool("Jump", true);jumpLimit--;}}}
}

Unity 第三人称自由视角相关推荐

  1. Unity第三人称的实现思路(二)

    Unity第三人称的实现思路(二) 锁定视角动画设置 锁定视角摄像机 角色朝向控制 主要代码 这一次我们在上一篇自由视角的基础上加上锁定视角的功能,没有看过上一篇的点下方链接. Unity第三人称的实 ...

  2. unity第三人称射击游戏_在游戏上第3部分完美的信息游戏

    unity第三人称射击游戏 Previous article 上一篇文章 The economics literature distinguishes the quality of a game's ...

  3. Unity 第三人称射击游戏视角控制与武器瞄准

    ===================更新一下源工程链接: 链接:https://pan.baidu.com/s/15bxH-MPregp2ZIN92fK7XA 提取码:e7bp ========== ...

  4. Unity 第三人称角色控制器:动画混合树、Cinemachine等功能或插件的使用

    前言: 无论是RPG.ACT.AVG还是TPS游戏,都有大量的以第三人称为人物视角的游戏作品,尤其是TPS,直接以第三人称为特点来命名 游戏类型: RPG:角色扮演游戏 ACT:动作游戏 AVG:冒险 ...

  5. Unity第三人称控制实现方式

    第三人称移动,主要两个部分,一是人物,二是相机. 先说人物,unity其实提供了一个CharacteController组件可以方便地用于控制人物移动,但是这个组件会与刚体冲突.如果使用Charact ...

  6. unity 第三人称射击游戏中如何防止跟随摄像机穿墙?

    在制作3d射击类游戏中,会遇到跟随角色的摄像机会穿透墙壁导致视野不佳情况,下面,介绍一下具体的解决方法. 我们需要用到的原理就是unity中射击线函数.具体的原理是,从相机的跟随点向相机的方向发射一条 ...

  7. Unity 第三人称 摄像机

    今天主要是简单的模拟下吃鸡游戏的第三人称摄像机的实现. 观察 我们玩过吃鸡手游的都知道,吃鸡的人物跟随的摄像机有两种状态 1. 滑动屏幕的时候,摄像机左右上下移动,人物也会跟随着左右移动,上下抬头低头 ...

  8. Unity第三人称射击游戏的相机控制

    (关于其他几种角色移动的控制在我之前的博客有写到) 首先我们需要先理解一下第三人称相机控制的原理: 我们要实现的效果就是:获取鼠标的移动输入,转化成角色以及相机的旋转,通过鼠标输入Input.GetA ...

  9. unity第三人称漫游,游戏场景精美,人物可移动

    unity3d第三人称漫游 (下载链接在文末) 游戏场景精美,包含山谷房屋桌椅等等模型,鼠标控制小狐狸移动,有血条,有菜单有按钮等等,需要什么额外功能可以自己再改造,如下图所示: 点我下载 https ...

最新文章

  1. OpenCV 图像处理系列(6)—— 图像的几何变化
  2. WinDbg加载不同版本CLR
  3. java数组如何pop_Js数组的操作push,pop,shift,unshift等方法详细介绍
  4. Ubuntu下Qt配置Opencv
  5. C语言数组的一些运算*a,a+1,a+1,a+0
  6. 猫版超级玛丽 附下载
  7. kali锁屏后无法唤醒_看一下吧,自己对线程以及锁的概念和原理了解是否正确...
  8. IDEA去除掉虚线,波浪线,和下划线实线的方法
  9. win10 开启蓝 由于其配置信息(注册表中的)不完整或已损坏
  10. 登录客户端显示不能连接服务器,客户端不能连接服务器,无法登陆
  11. ICLR 2022 | 合作博弈新范式:为可解释性等机器学习估值问题提供新方法
  12. 【干货分享】用AI工具设计一款吸引人的字体效果
  13. Python 正则表达式的$美元符号
  14. Hbuilder 嵌套外部链接
  15. 罗永浩刚直播完,就被罚款拘留?老罗是这么回应的...
  16. MEC与C-V2X融合应用场景白皮书
  17. Python温习(六)——元组操作
  18. html 设置表格间距 表格整体大小,css表格单元格间距怎么调整?
  19. JavaScript(订单的增删改)
  20. 华为机架式服务器型号,华为2488H V5机架式服务器

热门文章

  1. Qt TCP客户端无法连接服务器
  2. modbus协议教程
  3. Java反编译插件JODE介绍
  4. 漫画 | 这个北欧小国发明的编程技术,竟然占领全世界了!
  5. 操作系统实验—存储管理
  6. arduino的nrf24L01收发通信
  7. CentOS7.3服务器内网离线部署docker和容器
  8. Unity UGUI 效果 之 UI 元素 多边形UI (例如雷达图,圆形,不规则多边形 UI等)显示 的简单实现的几种方法整理
  9. IOC(一) - 初识
  10. 【回答问题】ChatGPT上线了!推荐30个以上比较好的中文bert系列的模型/压缩模型