Unity 实现角色移动视角旋转以及跳跃
Posted 落英芳华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity 实现角色移动视角旋转以及跳跃相关的知识,希望对你有一定的参考价值。
【Unity】 实现角色移动、视角旋转以及跳跃
一、使用UGUI创建角色模型和地面
创建一个Capsule和一个Cube模型,将其放在空物体下面,命名为Player
创建一个Plane作为地面
二、在【Inspector】面板中调整Player属性
在Player中添加Rigidbody和CapsuleCollider组件
Transform中修改Position,将Y改为1
Rigidbody -> Constraints -> FreezeRotaion中勾选 X Y Z
CapsuleCollider中将Height属性改为2
三、为Player添加移动代码
添加PlayerContoller脚本,并拖拽到Player上,具体代码如下
Transform cameraObj;
Vector3 moveDirection;
Rigidbody rb;
//初始化
void Awake()
cameraObj = Camera.main.transform;
rb=GetComponent<Rigidbody>();
// Update is called once per frame
void Update()
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
moveDirection= cameraObj.forward*v;
moveDirection+=cameraObj.right*h;
moveDirection.Normalize();//归一化
moveDirection *= 5f;//移动速度设定为5f
moveDirection.y = 0f;//防止Player运动时倾斜
//物理更新
void FixedUpdate()
rb.velocity = moveDirection;
运行效果如下
在Update中添加物体转向代码,旋转速度为0.3f
transform.forward = Vector3.Slerp(transform.forward, moveDirection, 0.3f);
此时物体在移动的过程中的朝向问题就解决了
四、添加角色跳跃
声明一个跳跃高度变量的
float jumpHeight;
在Awake下初始化jumpHeight
jumpHeight = 0;
调整FixedUpdate中的代码
rb.velocity = new Vector3(moveDirection.x, rb.velocity.y, moveDirection.z) + Vector3.up * jumpHeight;
jumpHeight = 0f;//初始化跳跃高度
添加跳跃方法
void Jump()
jumpHeight = 5f;
在Update中添加键盘事件,当按下空格时触发跳跃
if (Input.GetKeyDown(KeyCode.Space))
Jump();
恭喜你完成了本次教学,后续更新的文章多多支持
Unity 如何实现游戏Avatar角色头部跟随视角转动
文章目录
功能简介
如图所示,当相机的视角转动时,Avatar角色的头部会同步转动,看向视角的方向。
实现步骤
获取看向的位置
Avatar看向的位置即相机前方一定距离的某个坐标,该距离偏大于相机与Avatar角色的距离即可,可以取100来代表:
//获取看向的位置
private Vector3 GetLookAtPosition()
//主相机前方100个单位的位置
return mainCamera.transform.position + mainCamera.transform.forward * 100f;
获取头部的位置
头部位置可以通过Animator
组件中的GetBoneTransform
接口来获取
示例如下:
using UnityEngine;
namespace SK.Framework.Avatar
public class HeadTrack : MonoBehaviour
//动画组件
[SerializeField] private Animator animator;
private Camera mainCamera; //主相机
private Transform head; //头部
private void Start()
mainCamera = Camera.main ?? FindObjectOfType<Camera>();
head = animator.GetBoneTransform(HumanBodyBones.Head);
//获取看向的位置
private Vector3 GetLookAtPosition()
//主相机前方100个单位的位置
return mainCamera.transform.position + mainCamera.transform.forward * 100f;
有了头部的位置后,就可以计算头部的高度,声明一个变量headHeight
来记录头部高度:
headHeight = Vector3.Distance(transform.position, head.position);
修改头部的朝向
有了看向的坐标和头部的坐标,就取得了看向的朝向,在LateUpdate
中赋值该头部朝向,注意一定要使用LateUpdate
,因为Animator动画组件在控制Avatar各骨骼的朝向,使用LateUpdate
可以确保我们的旋转值修改起作用。
using UnityEngine;
namespace SK.Framework.Avatar
public class HeadTrack : MonoBehaviour
//动画组件
[SerializeField] private Animator animator;
private Camera mainCamera; //主相机
private Transform head; //头部
private float headHeight; //头部的高度
private void Start()
mainCamera = Camera.main ?? FindObjectOfType<Camera>();
head = animator.GetBoneTransform(HumanBodyBones.Head);
headHeight = Vector3.Distance(transform.position, head.position);
/// <summary>
/// 看向某点
/// </summary>
/// <param name="position"></param>
public void LookAtPosition(Vector3 position)
//头部位置
Vector3 headPosition = transform.position + transform.up * headHeight;
//朝向
Quaternion lookRotation = Quaternion.LookRotation(position - headPosition);
head.rotation = lookRotation;
private void LateUpdate()
Debug.DrawLine(transform.position + transform.up * headHeight, GetLookAtPosition());
LookAtPosition(GetLookAtPosition());
//获取看向的位置
private Vector3 GetLookAtPosition()
//主相机前方100个单位的位置
return mainCamera.transform.position + mainCamera.transform.forward * 100f;
如图所示,我们已经实现了头部的转向,但是旋转值过大会导致反人类现象,因此需要将旋转值进行限制。
限制旋转角度
//水平方向上的角度限制
[SerializeField] private Vector2 horizontalAngleLimit = new Vector2(-100f, 100f);
//垂直方向上的角度限制
[SerializeField] private Vector2 verticalAngleLimit = new Vector2(-60f, 60f);
封装一个角度标准化的函数,当角度大于180度时减360度,当角度小于180度时加360度:
//角度标准化
private float NormalizeAngle(float angle)
if (angle > 180) angle -= 360f;
else if (angle < -180) angle += 360f;
return angle;
封装看向某点的函数:
/// <summary>
/// 看向某点
/// </summary>
/// <param name="position"></param>
public void LookAtPosition(Vector3 position)
//头部位置
Vector3 headPosition = transform.position + transform.up * headHeight;
//朝向
Quaternion lookRotation = Quaternion.LookRotation(position - headPosition);
Vector3 eulerAngles = lookRotation.eulerAngles - transform.rotation.eulerAngles;
float x = NormalizeAngle(eulerAngles.x);
float y = NormalizeAngle(eulerAngles.y);
x = Mathf.Clamp(x, verticalAngleLimit.x, verticalAngleLimit.y);
y = Mathf.Clamp(y, horizontalAngleLimit.x, horizontalAngleLimit.y);
Quaternion rotY = Quaternion.AngleAxis(y, head.InverseTransformDirection(transform.up));
head.rotation *= rotY;
Quaternion rotX = Quaternion.AngleAxis(x, head.InverseTransformDirection(transform.TransformDirection(Vector3.right)));
head.rotation *= rotX;
超出限制范围时自动回正
当角度超出限制的范围时,将头部自动回正,可以在GetLookAtPosition
函数中加入判断,声明autoTurnback
变量标识是否自动回正:
//获取看向的位置
private Vector3 GetLookAtPosition()
Vector3 position = mainCamera.transform.position + mainCamera.transform.forward * 100f;
if (!autoTurnback) return position;
Vector3 direction = position - (transform.position + transform.up * headHeight);
Quaternion lookRotation = Quaternion.LookRotation(direction, transform.up);
Vector3 angle = lookRotation.eulerAngles - transform.eulerAngles;
float x = NormalizeAngle(angle.x);
float y = NormalizeAngle(angle.y);
bool isInRange = x >= verticalAngleLimit.x && x <= verticalAngleLimit.y
&& y >= horizontalAngleLimit.x && y <= horizontalAngleLimit.y;
return isInRange ? position : (transform.position + transform.up * headHeight + transform.forward);
加入插值运算,使自动回正时有过渡过程,代码如下:
using UnityEngine;
namespace SK.Framework.Avatar
public class HeadTrack : MonoBehaviour
[Tooltip("动画组件"), SerializeField] private Animator animator;
[Tooltip("水平方向上的角度限制"), SerializeField] private Vector2 horizontalAngleLimit = new Vector2(-70f, 70f);
[Tooltip("垂直方向上的角度限制"), SerializeField] private Vector2 verticalAngleLimit = new Vector2(-60f, 60f);
[Tooltip("超出限制范围时自动回正"), SerializeField] private bool autoTurnback = true;
[Tooltip("插值速度"), SerializeField] private float lerpSpeed = 5f;
private Camera mainCamera; //主相机
private Transform head; //头部
private float headHeight; //头部的高度
private float angleX;
private float angleY;
private void Start()
mainCamera = Camera.main ?? FindObjectOfType<Camera>();
head = animator.GetBoneTransform(HumanBodyBones.Head);
headHeight = Vector3.Distance(transform.position, head.position);
/// <summary>
/// 看向某点
/// </summary>
/// <param name="position"></param>
public void LookAtPosition(Vector3 position)
//头部位置
Vector3 headPosition = transform.position + transform.up * headHeight;
//朝向
Quaternion lookRotation = Quaternion.LookRotation(position - headPosition);
Vector3 eulerAngles = lookRotation.eulerAngles - transform.rotation.eulerAngles;
float x = NormalizeAngle(eulerAngles.x);
float y = NormalizeAngle(eulerAngles.y);
angleX = Mathf.Clamp(Mathf.Lerp(angleX, x, Time.deltaTime * lerpSpeed), verticalAngleLimit.x, verticalAngleLimit.y);
angleY = Mathf.Clamp(Mathf.Lerp(angleY, y, Time.deltaTime * lerpSpeed), horizontalAngleLimit.x, horizontalAngleLimit.y);
Quaternion rotY = Quaternion.AngleAxis(angleY, head.InverseTransformDirection(transform.up));
head.rotation *= rotY;
Quaternion rotX = Quaternion.AngleAxis(angleX, head.InverseTransformDirection(transform.TransformDirection(Vector3.right)));
head.rotation *= rotX;
//角度标准化
private float NormalizeAngle(float angle)
if (angle > 180) angle -= 360f;
else if (angle < -180) angle += 360f;
return angle;
private void LateUpdate()
LookAtPosition(GetLookAtPosition());
//获取看向的位置
private Vector3 GetLookAtPosition()
Vector3 position = mainCamera.transform.position + mainCamera.transform.forward * 100f;
if (!autoTurnback) return position;
Vector3 direction = position - (transform.position + transform.up * headHeight);
Quaternion lookRotation = Quaternion.LookRotation(direction, transform.up);
Vector3 angle = lookRotation.eulerAngles - transform.eulerAngles;
float x = NormalizeAngle(angle.x);
float y = NormalizeAngle(angle.y);
bool isInRange = x >= verticalAngleLimit.x && x <= verticalAngleLimit.y
&& y >= horizontalAngleLimit.x && y <= horizontalAngleLimit.y;
return isInRange ? position : (transform.position + transform.up * headHeight + transform.forward);
如何让指定动画不受影响
如果我们想要在播放某个动画时不让头部转动,可以通过Tag标签来解决,如下图所示,为Hi动画增加IgnoreHeadTrack
标签:
在代码中加入判断:
//获取看向的位置
private Vector3 GetLookAtPosition()
AnimatorStateInfo animatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (animatorStateInfo.IsTag("IgnoreHeadTrack"))
return transform.position + transform.up * headHeight + transform.forward;
Vector3 position = mainCamera.transform.position + mainCamera.transform.forward * 100f;
if (!autoTurnback) return position;
Vector3 direction = position - (transform.position + transform.up * headHeight);
Quaternion lookRotation = Quaternion.LookRotation(direction, transform.up);
Vector3 angle = lookRotation.eulerAngles - transform.eulerAngles;
float x = NormalizeAngle(angle.x);
float y = NormalizeAngle(angle.y);
bool isInRange = x >= verticalAngleLimit.x && x <= verticalAngleLimit.y
&& y >= horizontalAngleLimit.x && y <= horizontalAngleLimit.y;
return isInRange ? position : (transform.position + transform.up * headHeight + transform.forward);
完整代码:
using UnityEngine;
namespace SK.Framework.Avatar
public class HeadTrack : MonoBehaviour
[Tooltip("动画组件"), SerializeField] private Animator animator;
[Tooltip("水平方向上的角度限制"), SerializeField] private Vector2 horizontalAngleLimit = new Vector2(-70f, 70f);
[Tooltip("垂直方向上的角度限制"), SerializeField] private Vector2 verticalAngleLimit = new Vector2(-60f, 60f);
[Tooltip("超出限制范围时自动回正"), SerializeField] private bool autoTurnback = true;
[Tooltip("插值速度"), SerializeField] private float lerpSpeed = 5f;
private Camera mainCamera; //主相机
private Transform head; //头部
private float headHeight; //头部的高度
private float angleX;
private float angleY;
private void Start()
mainCamera = Camera.main ?? FindObjectOfType<Camera>();
head = animator.GetBoneTransform(HumanBodyBones.Head);
headHeight = Vector3.Distance(transform.position, head.position);
/// <summary>
/// 看向某点
/// </summary>
/// <param name="position"></param>
public void LookAtPosition(Vector3 position)
//头部位置
Vector3 headPosition = transform.position + transform.up * headHeight;
//朝向
Quaternion lookRotation = Quaternion.LookRotation(position - headPosition);
Vector3 eulerAngles = lookRotation.eulerAngles - transform.rotation.eulerAngles;
float x = NormalizeAngle(eulerAngles.x);
float y = NormalizeAngle(eulerAngles.y);
angleX = Mathf.Clamp(Mathf.Lerp(angleX, x, Time.deltaTime * lerpSpeed), verticalAngleLimit.x, verticalAngleLimit.y);
angleY = Mathf.Clamp(Mathf.Lerp(angleY, y, Time.deltaTime * lerpSpeed), horizontalAngleLimit.x, horizontalAngleLimit.<以上是关于Unity 实现角色移动视角旋转以及跳跃的主要内容,如果未能解决你的问题,请参考以下文章