[Unity角色控制专题] 详细解释如何使用Character Controller配合脚本实现跳跃功能与落地抖动?
本文无门槛,并且代码十分简单
有需要的小伙伴可可以查看上一个文章的基本控制 来自行考虑如何实现跳跃功能:[Unity角色控制专题] 详细说明如何使用Character Controller配合脚本实现类似MC的第一人称控制(仅移动与视角摇晃)-CSDN博客
来看实现效果:
1.跳跃模拟
加了角色控制器就不要用刚体了 会产生冲突 如果做物理模拟可以写另外一个脚本 下次再说
因此就需要额外的参数:
[Header("跳跃力度")]
public float jumpForce = 4.0f;
private float verticalVelocity; //垂直高度
[Header("重力系数")]
public float gravity = 9.81f;
额外的代码,写在Move函数里 最后会有所有代码的总结
//跳跃逻辑
if (Controller.isGrounded) {
verticalVelocity = -gravity * Time.deltaTime; // 微小重力保证贴地
if (Input.GetKeyDown(KeyCode.Space)) {
isJumping = true; // 开始跳跃
verticalVelocity = jumpForce;
}
}
else {
verticalVelocity -= gravity * Time.deltaTime;
}
Controller.Move(moveDirection + Vector3.up * verticalVelocity * Time.deltaTime);
具体做了什么 一张图就能解释:
至于为什么gravity要写成9.81其实这个无所谓 我是贴近现实才使用这个数字
官方第三人称项目示例是写成2的(其向上的位移很大),只要能保证功能实现就可以了
2.落地抖动
关键在于一个状态的控制 落地的瞬间检测到两个bool都是ture的话 就让摄像机向下位移一小点,然后lerp回原位就好了
[Header("跳跃落地抖动强度")]
public float landingSharkFrequency = 0.2f;
private bool isJumping;
if (Controller.isGrounded && isJumping) {
JumpShark();
isJumping = false; // 结束跳跃
}
private void JumpShark() {
HeadCamera.transform.localPosition = originalCameraPos + new Vector3(0f, -landingSharkFrequency, 0f);
}
3.总结
落地高度不同 摄像机抖动强度可以不同,因此可以根据跳跃力度大小来让相机抖动强度做出改变 这里我就不再赘述了 我并没有实现这个功能 因为暂时不需要
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.XR;
using static UnityEditor.Searcher.SearcherWindow.Alignment;
public class CCLearn : MonoBehaviour {
private Camera HeadCamera;
private CharacterController Controller;
#region 玩家视角
public Vector2 xY;
[Header("鼠标灵敏度")]
public float mouseSensitivity = 1.0f;
[Header("上下视角钳制角度")]
public Vector2 VirticalPersective = new Vector2(-90, 90);
private float currentVerticalAngle;
#endregion
#region 玩家移动
private Vector2 xZ;
Vector3 moveDirection;
[Header("移动速度")]
public float moveSpeed = 3.0f;
[Header("跑步速度")]
public float runSpeed = 6.0f;
[Header("移动噪音值")]
public float noicse = 1.0f;
#endregion
#region 玩家跳跃
[Header("跳跃力度")]
public float jumpForce = 4.0f;
private float verticalVelocity; //垂直高度
[Header("重力系数")]
public float gravity = 9.81f;
[Header("跳跃落地噪音值")]
public float jumpNoicse = 3.0f;
[Header("跳跃落地抖动强度")]
public float landingSharkFrequency = 0.2f;
private bool isJumping;
#endregion
#region 摄像机摇晃
private Vector3 originalCameraPos;
[Header("移动摇晃强度")]
public float shakeIntensity = 0.05f;
[Header("移动机摇晃频率")]
public float shakeFrequency = 10f;
#endregion
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start() {
Controller = GetComponent<CharacterController>();
HeadCamera = transform.Find("Head").GetComponentInChildren<Camera>();
HideMouse();
originalCameraPos = HeadCamera.transform.localPosition; // 初始化相机的原始位置
}
private void HideMouse() {
// 锁定鼠标光标并隐藏
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
// Update is called once per frame
void Update() {
PersPactive();
Move();
CameraShake();
}
private void PersPactive() {
xY = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")) * mouseSensitivity;
currentVerticalAngle -= xY.y;
currentVerticalAngle = Mathf.Clamp(currentVerticalAngle, VirticalPersective.x, VirticalPersective.y);
//相机上下视角
HeadCamera.transform.localRotation = Quaternion.Euler(currentVerticalAngle, 0f, 0f);
//角色旋转
this.transform.Rotate(Vector3.up * xY.x);
}
private void Move() {
xZ = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
moveDirection = (transform.forward * xZ.y + transform.right * xZ.x).normalized * moveSpeed * Time.deltaTime;
//加速
if (Input.GetKey(KeyCode.LeftShift)) {
moveDirection = (transform.forward * xZ.y + transform.right * xZ.x).normalized * runSpeed * Time.deltaTime;
}
//跳跃逻辑
if (Controller.isGrounded) {
verticalVelocity = -gravity * Time.deltaTime; // 微小重力保证贴地
if (Input.GetKeyDown(KeyCode.Space)) {
isJumping = true; // 开始跳跃
verticalVelocity = jumpForce;
}
}
else {
verticalVelocity -= gravity * Time.deltaTime;
}
Controller.Move(moveDirection + Vector3.up * verticalVelocity * Time.deltaTime);
if (Controller.isGrounded && isJumping) {
JumpShark();
isJumping = false; // 结束跳跃
}
}
private void CameraShake() {
if (xZ.magnitude != 0) {
float shakeOffsetX = Mathf.Sin(Time.time * shakeFrequency) * shakeIntensity;
float shakeOffsetY = Mathf.Cos(Time.time * shakeFrequency * 2f) * shakeIntensity * 0.5f;
HeadCamera.transform.localPosition = originalCameraPos + new Vector3(shakeOffsetX, shakeOffsetY, 0f);
}
else {
HeadCamera.transform.localPosition = Vector3.Lerp(HeadCamera.transform.localPosition, originalCameraPos, Time.deltaTime * 10f);
}
}
private void JumpShark() {
HeadCamera.transform.localPosition = originalCameraPos + new Vector3(0f, -landingSharkFrequency, 0f);
}
}