1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Unity 第三人称自由视角

Unity 第三人称自由视角

时间:2019-05-25 16:08:56

相关推荐

Unity 第三人称自由视角

环绕相机控制脚本

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

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

相机被遮挡的判断与处理

具体分析见 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 Systempublic 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--;}}}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。