Unity 3D重力切换玩法下玩家控制器跳跃功能异常修复求助
故障根因
你当前的代码存在4个核心问题导致跳跃表现混乱:
- 物理逻辑放在了
Update()中执行:Update的执行帧率随设备性能波动,而Rigidbody相关的物理操作必须放在FixedUpdate()中才能保证表现一致,直接在Update中修改rb.velocity会出现卡顿、力度忽大忽小的问题。 - 地面检测逻辑错误:
OnCollision系列方法只要碰到任何物体(包括墙面、天花板)都会触发isGrounded = true,会出现贴墙跳、碰顶跳的异常表现,没有校验接触点是否是可站立的地面。 - 跳跃触发没有加地面判定:只要按空格就会赋值跳跃力度,会出现空中无限跳的问题;同时重力计算没有乘时间增量,不同帧率下重力加速度表现不一致。
- 速度赋值逻辑冗余错误:开头的
if (((isShifting && isRunning)||!(isShifting && isRunning)))判断恒为真,没有实际作用;同时直接全量覆盖rb.velocity会冲掉物理引擎产生的碰撞速度,且存在重复乘速度系数的可能,导致力度计算错误。
修复方案
1. 代码结构调整
把输入检测和物理逻辑拆分,输入检测保留在Update()中,所有Rigidbody操作、重力、跳跃逻辑移到FixedUpdate()中,新增jumpRequested变量缓存跳跃请求:
// 新增类变量 private bool jumpRequested = false; void Update() { // 输入检测保留在Update中 isRunning = Input.GetKey(KeyCode.LeftControl); isShifting = IntToBool((int)((BoolToInt(Input.GetKey(KeyCode.LeftAlt)))*BoolToInt(!isShiftable))+(BoolToInt(Input.GetKey(KeyCode.LeftShift))*BoolToInt(isShiftable))); // 删掉冗余的恒真判断 curSpeedX = walkingSpeed * Input.GetAxis("Vertical"); curSpeedY = walkingSpeed * Input.GetAxis("Horizontal"); if (isShifting) { curSpeedX = ShiftSpeed * Input.GetAxis("Vertical"); curSpeedY = ShiftSpeed * Input.GetAxis("Horizontal"); } if (isRunning) { curSpeedX = runningSpeed * Input.GetAxis("Vertical"); curSpeedY = runningSpeed * Input.GetAxis("Horizontal"); } // 跳跃输入检测加地面判定 if (Input.GetKeyDown(KeyCode.Space) && isGrounded) { jumpRequested = true; } } void FixedUpdate() { // 重力计算乘固定时间增量,保证不同设备表现一致 if (!isGrounded) { ypoa -= gravity * Time.fixedDeltaTime; } // 处理跳跃请求 if (jumpRequested) { ypoa = jumpheight; jumpRequested = false; isGrounded = false; } // 计算最终速度并赋值 Vector3 moveDir = (ypoa * transform.up) + (curSpeedX * transform.forward) + (curSpeedY * transform.right); rb.velocity = moveDir * speed; // 若速度数值异常可先去掉*speed,调整walkingSpeed等基础参数到合适值 }
2. 修正地面检测逻辑
修改碰撞检测代码,仅当接触点法线和玩家当前up向量夹角小于30°(可调整)时判定为站在地面:
void OnCollisionStay(Collision collision) { foreach (ContactPoint contact in collision.contacts) { if (Vector3.Angle(contact.normal, transform.up) < 30f) { isGrounded = true; ypoa = 0; jumcount = 0; break; } } } void OnCollisionExit(Collision collision) { isGrounded = false; } // 删掉原有的OnCollisionEnter逻辑,合并到OnCollisionStay中即可
3. Rigidbody组件配置
- 关闭组件的
Use Gravity选项,避免自行计算的重力和引擎自带重力叠加 - 勾选
Freeze Rotation下的X、Y、Z三个选项,避免玩家碰撞后发生旋转,导致transform.up方向异常
优化建议
- 可以额外增加短射线检测辅助地面判定:在玩家位置向
-transform.up方向发射长度为0.1~0.2f的射线,碰到碰撞体时也判定为isGrounded = true,避免碰撞检测延迟导致跳不起来 - 重力切换时直接修改
transform.up为当前重力的反方向,这套逻辑可直接适配全角度地图的重力切换需求
内容的提问来源于stack exchange,提问作者sam oakes
相关产品推荐
相关产品推荐

