最终效果
文章目录
- 最终效果
- 前言
- 一、前期准备
- 1、创建项目
- 2、选择在进入播放模式时启动哪些重新加载选项
- 3、搭建基本场景原型
- 4、拖入3D角色模型
- 二、真实开始
- 1、输入控制
- 2、使用Character Controller实现人物移动
- 3、添加虚拟相机Cinemachine跟随
- 4、人物跟随相机旋转
- 5、导入动画
- 6、添加BlendTree混合动画
- 1. 配置参数方式一
- 2. 配置参数方式二
- 7、添加Animator控制代码
- 8、添加动画过渡
- 1 方法一 使用`Vector3.Lerp`进行平滑插值
- 2 方法二 使用animator.SetFloat进行平滑插值
- 3 效果
- 9、使用Root Motion实现动画和位移同步
- 10、添加下蹲移动
- 11、添加重力和跳跃
- 12、播放跳跃下落动画
- 13、修复原地跳跃问题
- 14、原地转向
- 15、角色在下斜坡时,短暂浮空
- 16、冲刺时跳跃,落地速度就会立即恢复到最高的跑步速度
- 17、在墙壁边缘走上走下或者跳跃,会出现抖动卡顿
- 18、我们跳上超斜的斜面,会被卡住
- 19、限制人物下落速度
- 20、物体会挡住相机视野和相机穿模
- 21、相机上下楼梯,跳跃有点抖动
- 待续
- 专栏推荐
- 完结
前言
本文我将带大家从零手搓一个带动画的第一人称和第三人称unity人物控制器,不借助任何外在的第三方插件。主要使用到了新输入系统InputSystem
+虚拟相机Cinemachine
+Animator
。
其实第一人称和第三人称unity人物控制器我之前做过不少,但是都没有带动画效果。
注意本文不是新手向的,如果你还不了解如何使用unity可以参考【unity游戏开发入门到精通——通用篇】,可以等有一定基础了再来看本篇文章。
一、前期准备
1、创建项目
如果你不知道如何下载unity6可以参考:【unity小技巧】国内Unity6下载安装和一些Unity6新功能使用介绍
这里我直接使用最新的Unity6版本,当然,如果你想使用其他版本也是可以的。
2、选择在进入播放模式时启动哪些重新加载选项
为了更快地进入播放模式,节约我们的时间,我们可以禁用 scene 或域重新加载。这里我在项目设置里将进入播放模式设置
设置成Reload Scene Only (仅重新加载场景)
。
域重新加载是指编辑器在开始播放模式之前重置脚本状态。场景重新加载是指编辑器在播放模式开始之前销毁所有场景 GameObjects
并从磁盘重新加载场景。具体介绍可以参考官方文档说明:禁用域和场景重新加载的详细信息
3、搭建基本场景原型
如果你还不知道如何使用ProBuilder,可以参考:【推荐100个unity插件之28】在unity中建模,使用Unity制作基础模型,搭建场景原型——ProBuilder的使用
这里我使用unity自带的ProBuilder插件搭建基本场景原型,效果就大家自由发挥。当然你也可以自己使用其他方式,比如使用不同的3D模型进行拼接。
4、拖入3D角色模型
这里随便找个3D人物模型即可,我这里导入的是:そふぃーら
如果你不知道vrm模型如何在unity中使用,可以参考:【推荐100个unity插件之25】在unity中直接使用VRM模型——URPUniVrm插件的使用
这个模型其实不算特别好,衣服头发经常穿模,VRM插件也经常爆警告,看着很难受。所以到后面开发我更换成了模型:【善良米塔/瘋狂米塔 vroid版本/vrm】,如果中途发现我的突然换了隔模型,千万不用惊讶。
这里推荐另一种方式使用VRM模型,也就是将VRM模型转成FBX模型再到unity中使用,可以参考:【blender小技巧】使用Blender将VRM或者其他模型转化为FBX模型,并在unity使用,导出带贴图的FBX模型,贴图材质问题修复
二、真实开始
1、输入控制
对InputSystem还不熟悉的小伙伴可以先看:【unity游戏开发——InputSystem】
using UnityEngine;
using UnityEngine.InputSystem;public class InputController : MonoBehaviour {PlayerInput playerInput;public Vector2 moveVector2;public bool isSprint;public bool isCrouch;public bool isJump;void Awake(){playerInput = GetComponent<PlayerInput>();}private void OnEnable() {// 输入触发事件,任何输入都会触发该事件playerInput.onActionTriggered += OnActionTrigger;}void OnDisable() {playerInput.onActionTriggered -= OnActionTrigger;}private void OnActionTrigger(InputAction.CallbackContext context){switch (context.action.name){case "Move":// 获取输入的方向值(Vector2类型)moveVector2 = context.ReadValue<Vector2>();// Debug.Log("Move: " + moveVector2);//打印break;case "Sprint"://按下返回true,松开返回falseisSprint = context.action.IsPressed();break;case "Crouch":isCrouch = !isCrouch;break;case "Jump":isJump = context.action.IsPressed();break;}}
}
挂载脚本
结果,键盘wasd输入打印值
2、使用Character Controller实现人物移动
这里我们使用Character Controller实现第三人称控制,如果你还不知道具体如何使用CharacterController,可以参考:
- 【零基础入门unity游戏开发——unity3D篇】3D角色控制器CharacterController的使用、实现俯视角、第三人称角色控制
给角色添加Character Controller,并配置合适的参数
新增PlayerController脚本,控制角色移动
using UnityEngine;[RequireComponent(typeof(Animator), typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{CharacterController characterController;[Header("输入")]InputController inputController;Vector3 direction;//输入创建移动方向向量[Header("移动")]public float speed = 5f; // 玩家移动的速度Vector3 moveDirection;//角色的移动方向void Awake(){characterController = GetComponent<CharacterController>();inputController = GetComponent<InputController>();}void Update(){SetPlayerMove();}//处理角色移动void SetPlayerMove(){// 根据输入创建移动方向向量direction = new Vector3(inputController.moveVector2.x, 0, inputController.moveVector2.y);//将该向量从局部坐标系转换为世界坐标系,得到最终的移动方向moveDirection = transform.TransformDirection(direction);characterController.Move(moveDirection.normalized * speed * Time.deltaTime);}
}
挂载脚本
效果
3、添加虚拟相机Cinemachine跟随
如果你还不知道如何使用Cinemachine,可以参考:【推荐100个unity插件之10】Unity最全的最详细的Cinemachine(虚拟相机系统)介绍,详细案例讲解,快速上手
新增虚拟相机
配置参数
效果
4、人物跟随相机旋转
因为我们要做的是FPS第三人称视角,所以我们需要实现人物一直面向相机
代码如下
// 处理角色旋转
void SetPlayerRotation()
{// 获取相机的旋转(只考虑 Y 轴的旋转)float yRotation = mainCamera.transform.eulerAngles.y;// 计算角色的目标旋转Quaternion targetRotation = Quaternion.Euler(0, yRotation, 0);//进行平滑过渡到目标旋转(如果需要平滑效果)transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
}
效果
5、导入动画
这里所有的动画,都可以在mixamo网站免费获取,如果你还不懂如何使用它,可以参考:【游戏资源】获取免费开源的人物模型,为obj fbx人物模型绑定人形骨骼和人形动画,并导入到unity中使用——mixamo的使用介绍
这里为了节省时间,我就不去mixamo网站一个个下载了,这里我直接使用之前unity免费的动画包:Basic Motions FREE
6、添加BlendTree混合动画
如果你还了解
Blend Tree
动画混合树的知识,可以先去查看:【unity游戏开发入门到精通——动画篇】动画混合(Blend Tree)
添加行为树,配置动画和参数。当然,在这里配置参数的做法有很多种。
1. 配置参数方式一
我们可以把移动阈值设置成1,奔跑设置成2。注意这里斜着走我们要设置成0.707,因为我们会发现斜着输入最大值就是-0.70到0.707,这涉及三角函数的计算,斜边长为1的等腰直角三角形的两边长度就是1/√2≈0.707
。
2. 配置参数方式二
点击xy按动画的xz方向上的速度自动分配阈值
然后我们可以参考Unity官方在标准资源包里的做法。
- 我们把待机动画阈值设置成0。
- 把前后运动的动画x方向阈值设置成0,左右运动的动画y轴阈值设置0,另一个方向的阈值设置成和向前行走一样。
- 斜方向阈值都设置成向前行走的阈值*0.707,也就是
+-1.066*0.707=0.753662
,为什么是0.707前面已经解释了
- 奔跑动画同理
注意
:这里如果你对动画要求比较高,其实我们还可以进行更加精细的调整,比如修改缩放,让所有的行走奔跑动画移动速度都保持在一个值。这里我就不做调整了,具体的方式我在RootMotion
动画混合树的知识的文章里有提到:【unity实战】OnAnimatorMove+Root Motion+BlendTree+CharacterController解决Animator动画和位移不同步问题,完美实现移动动画动作匹配
7、添加Animator控制代码
修改PlayerController
[Header("移动")]
public float currentSpeed = 0f;//当前速度
[SerializeField] private float walkSpeedValue = 1.066f;//行走速度
[SerializeField] private float runSpeedValue = 4.067f;//奔跑速度
Vector3 moveDirection;//角色的移动方向//处理角色移动
void SetPlayerMove(){if(inputController.moveVector2.magnitude > 0.1f){if(inputController.isSprint){currentSpeed = runSpeedValue;}else{currentSpeed = walkSpeedValue; }}else{currentSpeed = 0f;}// 根据输入创建移动方向向量direction = new Vector3(inputController.moveVector2.x, 0, inputController.moveVector2.y);//将该向量从局部坐标系转换为世界坐标系,得到最终的移动方向moveDirection = transform.TransformDirection(direction);characterController.Move(moveDirection.normalized * currentSpeed * Time.deltaTime);
}
新增AnimatorController 代码,控制动画切换
using UnityEngine;public class AnimatorController : MonoBehaviour {InputController inputController;Animator animator;PlayerController playerController;private static int inputX = Animator.StringToHash("inputX");private static int inputY = Animator.StringToHash("inputY");void Awake(){inputController = GetComponent<InputController>();animator = GetComponent<Animator>();playerController = GetComponent<PlayerController>();}void Update(){UpdateAnimatorState();}private void UpdateAnimatorState(){animator.SetFloat(inputX, inputController.moveVector2.x * playerController.currentSpeed);animator.SetFloat(inputY, inputController.moveVector2.y * playerController.currentSpeed); }
}
使用Animator.StringToHash哈希处理字符串
:
使用哈希的主要原因是提高效率。状态机中的标签和参数通常用字符串表示,但字符串比较在性能上可能较慢。通过使用哈希值,可以将字符串转换为唯一的整数值,进行更快速的比较操作。这避免了每帧都进行昂贵的字符串比较操作,从而提升了状态机查询的性能。
效果
8、添加动画过渡
虽然现在看到一切正常,但是其实混合树实际上并没有进行混合,它只是在不同的动画之间即时切换,这是因为你可以看到输入x和输入y参数立即被设置为新值,我们需要做的是缓慢地增加它们。
1 方法一 使用Vector3.Lerp
进行平滑插值
我们可以在设置输入值前,使用Vector3.Lerp
进行平滑插值,修改AnimatorController代码
[SerializeField] private float smoothTime = 4f;//平滑插值速度
Vector2 currentBlendInput = Vector3.zero;//当前移动输入private void UpdateAnimatorState(){//平滑插值currentBlendInput = Vector2.Lerp(currentBlendInput, inputController.moveVector2, smoothTime * Time.deltaTime);animator.SetFloat(inputX, currentBlendInput.x);animator.SetFloat(inputY, currentBlendInput.y);
}
2 方法二 使用animator.SetFloat进行平滑插值
animator.SetFloat方法其实自带了平滑插值方法,我们只需要新增两个参数即可。
[SerializeField] private float smoothTime = 0.1f;//平滑插值速度private void UpdateAnimatorState(){animator.SetFloat(inputX, inputController.moveVector2.x * playerController.currentSpeed, smoothTime, Time.deltaTime);animator.SetFloat(inputY, inputController.moveVector2.y * playerController.currentSpeed, smoothTime, Time.deltaTime);
}
3 效果
9、使用Root Motion实现动画和位移同步
现在我们的动画切换虽然进行混合了,但是很明显我们人物移动出现了滑步
的想象或者说很容易出现滑步
现象。因为我们还没有对人物的速度进行限制。当然,你可以选择同样对速度进行平滑,然后解决这个滑步问题。
但是我这里打算使用Root Motion,要完全解决人物移动的滑步问题,使用Root Motion一定是最好的方式。
如果你还了解
Root Motion
动画混合树的知识,可以先去查看:【unity实战】OnAnimatorMove+Root Motion+Blend Tree+CharacterController解决Animator动画和位移不同步问题,完美实现移动动画动作匹配
修改,取消之前的SetPlayerMove方法,新增OnAnimatorMove方法代替
private void OnAnimatorMove()
{if(inputController.moveVector2.magnitude > 0.1f){if(inputController.isSprint){currentSpeed = runSpeedValue;}else{currentSpeed = walkSpeedValue; }}else{currentSpeed = 0f;}Vector3 deltaPosition = animator.deltaPosition;//当前帧相对于上一帧的位移增量// 移动 CharacterControllercharacterController.Move(deltaPosition);
}
开启animator动画物理
效果,现在使用动画根位移控制角色移动,实现了角色动画和位移绝对同步
10、添加下蹲移动
实现下蹲移动其实和前面的操作基本一样,新增一个下蹲bleedTree,再做切换即可,这里不浪费时间再介绍一次了
直接看看最终效果
11、添加重力和跳跃
修改PlayerController
[Header("跳跃")]
public float jumpHeight = 2f;//跳跃高度
[SerializeField] private bool isGround;//地面检测
[SerializeField] private float Gravity = -39.8f;//重力
private Vector3 verticalVelocity; // 垂直方向上的速度void Update()
{SetPlayerRotation();SetPlayerGravity();SetPlayerJump();
}// 处理角色重力
void SetPlayerGravity()
{// 应用重力characterController.Move(verticalVelocity * Time.deltaTime);//地面检测isGround = characterController.isGrounded;if (isGround){// 当isGrounded为true时,将Y轴方向的速度设为了一个较小的负值,这是为了确保能稳定触碰地面,避免isGrounded误判为falseverticalVelocity = new Vector3(0, -2f, 0);}else{// 更新重力影响的速度verticalVelocity.y += Gravity * Time.deltaTime;}
}// 处理角色跳跃
void SetPlayerJump()
{// 跳跃处理if (isGround && inputController.isJump){verticalVelocity.y = Mathf.Sqrt(jumpHeight * -2 * Gravity);}
}
效果
12、播放跳跃下落动画
我们添加一个跳跃下落的子状态机,并配置参数
跳跃下落的子状态机参数如下。(注意:可以看到这里默认有条黄线,不用管他,好像是unity6的显示bug)
修改AnimatorController,进行跳跃动画切换
private static int jumpSpeed = Animator.StringToHash("jumpSpeed");
private static int isJump = Animator.StringToHash("isJump");
private static int isGround = Animator.StringToHash("isGround");animator.SetFloat(jumpSpeed, playerController.verticalVelocity.y);
animator.SetBool(isJump, inputController.isJump);
animator.SetBool(isGround, playerController.isGround);
效果
13、修复原地跳跃问题
应用跳跃动画之后,我们可以看到目前我们都只能在原地跳跃了,水平方向的速度一直都是0,其实是因为前面我们使用了OnAnimatorMove来控制人物移动,而我们的跳跃动画是没有水平方向位移的。
想解决这一问题,我们可以不在地面时手动设置一个水平方向的速度,修改PlayerController
private Vector3 horizontalVelocity; // 水平方向速度//设置水平速度
void SetHorizontalVelocity()
{//不在地面时更新水平速度if (!isGround){//将该向量从局部坐标系转换为世界坐标系,得到最终的移动方向horizontalVelocity = transform.TransformDirection(new Vector3(inputController.moveVector2.x, 0, inputController.moveVector2.y)) * currentSpeed; }else{horizontalVelocity = Vector3.zero;}characterController.Move(horizontalVelocity * Time.deltaTime);
}
效果
14、原地转向
业余游戏开发者在做人物控制系统时,经常忽略的一个内容就是原地转身,如果你想用3D玩家控制器制作可发布的游戏,这确实是一个你必须拥有的机制。
老实说,这也是比较难做好的机制之一。这里我打算复刻一下类似PUBG吃鸡这样的原地转身机制。及人物面向方向与相机的水平正方向的夹角如果在45度范围内,角色不发生转身。如果超出这个范围,则等待3秒后角色平滑旋转,与相机的水平正方向对齐。
我们新增一个子状态机叫转身动作
。
配置子状态机内部连线,因为我这里只有左右转的动画,所以只配置了旋转角度大于小于0播放不同动画。如果你有更多动画问题,比如旋转45、90、180度动画,可以进行更加精细的配置,效果将会更好。
修改PlayerController代码,我们要修改覆盖掉原来我们角色转身的代码。这里代码我都加了很详细的中文注释,方便大家理解,就不多做解释了。
[Header("相机跟随设置")]
[SerializeField] private float angleThreshold = 45f; // 角度阈值
[SerializeField] private float rotationSpeed = 8f; // 转向速度[HideInInspector] public float _currentAngle; // 当前角度差
public float turnDelay = 3f; // 转身动画延迟发生时间
private float lastTurnTime;//上次转身时间
public float turnTime = 0.6f;//转身需要的时间
[HideInInspector] public bool _isTurning = false; // 是否正在转身
private float _turnStartTime; // 转身开始时间
private Quaternion _startRotation; // 转身开始时的旋转
private Quaternion _targetRotation; // 转身目标旋转
private bool isIdle;//是否在原地
private Vector3 cameraForward;//获取相机水平方向//...记得在update中调用下面这些函数// 计算人物和相机的夹角
void CalculateCameraAngle()
{// 获取相机在水平面(XZ平面)的正前方向cameraForward = mainCamera.transform.forward;cameraForward.y = 0;cameraForward.Normalize();// 获取角色在水平面的正前方向Vector3 playerForward = transform.forward;playerForward.y = 0;playerForward.Normalize();// 通过点乘计算两个向量的夹角_currentAngle = Vector3.Angle(playerForward, cameraForward);// 计算两个向量的叉乘,确定角度方向(正负值)float crossY = Vector3.Cross(playerForward, cameraForward).y;//y小于0 证明相机在人物左侧if (crossY < 0) _currentAngle *= -1;
}//处理旋转逻辑
private void HandleRotationLogic()
{isIdle = inputController.moveVector2.magnitude < 0.1f; // 如果移动向量长度小于0.1,则认为处于静止状态// 如果没有移动,且角度大于阈值,且当前没有正在转身,且上次转身时间超过延迟时间,且在地面上,且没有下蹲if (isIdle && Mathf.Abs(_currentAngle) > angleThreshold && !_isTurning && Time.time - lastTurnTime > turnDelay && isGround && !inputController.isCrouch){_isTurning = true;_turnStartTime = Time.time;_startRotation = transform.rotation;_targetRotation = Quaternion.LookRotation(cameraForward);}// 如果转身动画结束或者移动,重置状态if ((_isTurning && Time.time - _turnStartTime >= turnTime) || !isIdle){_isTurning = false;lastTurnTime = Time.time;}
}// 处理角色旋转
private void SetPlayerRotation()
{if (_isTurning){// 计算转身进度float turnProgress = (Time.time - _turnStartTime) / turnTime;// 确保进度在0到1之间turnProgress = Mathf.Clamp01(turnProgress);// 使用插值平滑旋转transform.rotation = Quaternion.Slerp(_startRotation, _targetRotation, turnProgress);}else if (!isIdle)//非待机状态角色才跟随相机旋转{lastTurnTime = Time.time;// 普通情况下的相机跟随旋转Vector3 cameraForward = mainCamera.transform.forward;cameraForward.y = 0;Quaternion targetRotation = Quaternion.LookRotation(cameraForward);transform.rotation = Quaternion.Slerp(transform.rotation,targetRotation,rotationSpeed * Time.deltaTime);}
}
效果
15、角色在下斜坡时,短暂浮空
角色在下斜坡时,会短暂浮空,特别是速度比较快的时候。
我们可以给角色一个向下的压力,我们可以将它配置化成参数,方便在面板调整。
[Header("斜坡处理")]
[SerializeField] private Vector3 downForceVector = new Vector3(0, -10, 0); //下压力void Update()
{SetDownForce();//记得一定要在isGround检测之前调用//。。。
}//加下压力
void SetDownForce(){if (!isGround) return;characterController.Move(downForceVector * Time.deltaTime);
}
效果
16、冲刺时跳跃,落地速度就会立即恢复到最高的跑步速度
我们可以先在PlayerController获取跳跃状态
public bool isJumping;//是否在跳跃// 处理角色跳跃
void SetPlayerJump()
{// 跳跃处理if (isGround){isJumping = false;if(inputController.isJump){isJumping = true;verticalVelocity.y = Mathf.Sqrt(jumpHeight * -2 * Gravity);}}
}
在AnimatorController里判断,如果正在跳跃,则inputX和inputY归零
if (playerController.isJumping)
{animator.SetFloat(inputX, 0f);animator.SetFloat(inputY, 0f);
}
else
{animator.SetFloat(inputX, inputController.moveVector2.x * playerController.currentSpeed, smoothTime, Time.deltaTime);animator.SetFloat(inputY, inputController.moveVector2.y * playerController.currentSpeed, smoothTime, Time.deltaTime);
}
效果
17、在墙壁边缘走上走下或者跳跃,会出现抖动卡顿
其实这是一个非常细微的问题,比如我把玩家的跳跃高度设置成1.7米,无论如何他都不能跳上2米的墙壁才对。但是事实并非如此。
这主要其实就是收到Character Controller的每步偏移量的影响。跳跃2米的墙,还差0.3米时他会把他当作是楼梯,然后顿一下走上前。
我的解决方案是我们在跳跃或下落(也就是空中)时,我们将步长偏移设置为零,在任何其他状态下,再将他设置回默认值。
[Header("楼梯处理")]
float stepOffset; //默认步长偏移void Awake()
{//。。。stepOffset = characterController.stepOffset;
}void SetPlayerGravity()
{//。。。if(isGround){//。。。characterController.stepOffset = stepOffset;}else{//。。。characterController.stepOffset = 0f;}
}
效果
18、我们跳上超斜的斜面,会被卡住
我们可以在玩家脚下使用射线检测,检测斜面的法线向量,然后计算出斜坡的角度。
RaycastHit hit; //射线检测结果
float slopeAngle; //斜率角度
Vector3 normal;//获取法线向量
public LayerMask layerMask; //射线检测的层
public float distance = 0.5f; //射线检测距离// 处理角色重力
void SetPlayerGravity()
{if (isGround){verticalVelocity = new Vector3(0, -2f, 0);characterController.stepOffset = stepOffset;}else{// 累加重力verticalVelocity.y += Gravity * Time.deltaTime;characterController.stepOffset = 0f;}
}// 处理角色跳跃
void SetPlayerJump()
{// 跳跃处理if (isGround){isJumping = false;if(inputController.isJump){isJumping = true;verticalVelocity.y = Mathf.Sqrt(jumpHeight * -2 * Gravity);}}verticalVelocity = SetSlopeVelocity(verticalVelocity);// 应用y轴速度characterController.Move(verticalVelocity * Time.deltaTime);//地面检测,注意地面检测一定要在Move之后,否则可能会检测不到isGround = characterController.isGrounded;
}//斜坡检测
void CheckIsSlope()
{// 射线检测if (Physics.Raycast(transform.position, Vector3.down,out hit, distance, layerMask)){normal = hit.normal;// 计算斜面角度slopeAngle = Vector3.Angle(normal, Vector3.up);}
}
//斜坡速度处理
private Vector3 SetSlopeVelocity(Vector3 velocity)
{//角色在大斜坡上下落if (slopeAngle > characterController.slopeLimit && verticalVelocity.y < 0f){// 则将速度投射到斜坡上velocity = Vector3.ProjectOnPlane(velocity, normal);}//返回处理后的速度向量return velocity;
}
我们可以使用OnDrawGizmos辅助函数,在场景显示射线,方便调试查看
private void OnDrawGizmos()
{Gizmos.color = Color.red;Gizmos.DrawLine(transform.position, transform.position + Vector3.down * distance;);
}
可以在场景视图看到射线检测的距离
记得修改玩家图层和检测图层
效果
不过如果你人物在边角的时候,检测还是会有问题。
如果你有更加精确的要求的话,可以使用多条射线检测,或者使用Physics.SphereCast
球形检测、Physics.BoxCast
方形检测、Physics.CapsuleCast
胶囊体检测,效果会更好,这里就不演示了
if(Physics.SphereCast(transform.position, characterController.radius, Vector3.down, out hit, distance, layerMask)){Debug.Log(2222);
};
19、限制人物下落速度
如果我们开始下落,我们不想他无限加速,我希望限制这个值。我不希望玩家从很高的地方跌落,速度太快。
public float maxVelocityY = 50f;//最大垂直速度//将y轴速度限制在+-maxVelocityY之间
verticalVelocity.y = Mathf.Clamp(verticalVelocity.y, -maxVelocityY, maxVelocityY);
20、物体会挡住相机视野和相机穿模
我们可以添加虚拟相机Cinemachine Deoccluder
反遮挡器,具体可以参考:https://docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineDeoccluder.html
效果
21、相机上下楼梯,跳跃有点抖动
我们可以适当增大相机的阻尼
效果
待续
暂时先实现这么多,如果后续想到加其他功能再来添加。
专栏推荐
地址 |
---|
【unity游戏开发入门到精通——C#篇】 |
【unity游戏开发入门到精通——unity通用篇】 |
【unity游戏开发入门到精通——unity3D篇】 |
【unity游戏开发入门到精通——unity2D篇】 |
【unity实战】 |
【制作100个Unity游戏】 |
【推荐100个unity插件】 |
【实现100个unity特效】 |
【unity框架/工具集开发】 |
【unity游戏开发——模型篇】 |
【unity游戏开发——InputSystem】 |
【unity游戏开发——Animator动画】 |
【unity游戏开发——UGUI】 |
【unity游戏开发——联网篇】 |
【unity游戏开发——优化篇】 |
【unity游戏开发——shader篇】 |
完结
好了,我是向宇
,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!