Unity中玩家对象AddForce效果被velocity覆盖问题求助
问题:直接修改Velocity导致AddForce效果被覆盖
我在给玩家刚体使用AddForce时遇到问题:通过直接修改velocity实现玩家移动,该操作会持续覆盖玩家速度,导致AddForce的效果被立刻覆盖,问题出在第一个if语句中的两处playerRb.velocity赋值。另有一处rb.AddForce(ForceMode.Impulse)在其他文件中,目标是在接触时推动玩家。请问是否可以计算最终速度,或是应该更换玩家移动的实现方式?
原代码
private void DefaultMoveRigidBody() { Vector3 move = new Vector3(movementInput.x, 0, movementInput.y); Vector3 MoveVector = transform.TransformDirection(move) * movementSpeed; slopeMovementDirection = Vector3.ProjectOnPlane(MoveVector, slopeHit.normal); if (Physics.CheckSphere(FeetTransform.position, 1f, layerMask) && canJump && OnSlope()) { playerRb.velocity = slopeMovementDirection; } else { playerRb.velocity = new Vector3(MoveVector.x, playerRb.velocity.y, MoveVector.z); Debug.Log(playerRb.velocity); } if (jumped && Physics.CheckSphere(FeetTransform.position, 1f, layerMask) && canJump) { canJump = false; jumpTimer = 0.5f; playerRb.velocity = new Vector3(playerRb.velocity.x, 0, playerRb.velocity.z); playerRb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); } if (!canJump) { if (jumpTimer <= 0f) { canJump = true; jumpTimer = 0.5f; } else { jumpTimer -= Time.deltaTime; } } if (move != Vector3.zero) { Quaternion toRotation = Quaternion.LookRotation(-move, Vector3.up); gameObject.transform.GetChild(0).transform.localRotation = Quaternion.RotateTowards(gameObject.transform.GetChild(0).transform.localRotation, toRotation, rotationSpeed * Time.deltaTime); } }
解决方案
核心问题
直接赋值playerRb.velocity会完全覆盖刚体当前的所有速度分量,包括其他AddForce带来的推力速度,这就是外部推动效果被立刻覆盖的原因。解决思路要么是避免直接覆盖速度,要么是改用AddForce实现玩家移动。
方案一:修改现有逻辑,保留Velocity但不覆盖
不要直接给velocity赋值,而是只替换水平方向的目标速度,同时保留原有速度中的外部推力部分:
// 斜坡移动逻辑修改 if (Physics.CheckSphere(FeetTransform.position, 1f, layerMask) && canJump && OnSlope()) { // 只替换水平分量,保留Y轴速度和外部推力带来的增量 playerRb.velocity = new Vector3(slopeMovementDirection.x, playerRb.velocity.y, slopeMovementDirection.z); } else { // 计算水平方向的速度差,用AddForce叠加到现有速度上 Vector3 targetHorizontalVelocity = new Vector3(MoveVector.x, 0, MoveVector.z); Vector3 currentHorizontalVelocity = new Vector3(playerRb.velocity.x, 0, playerRb.velocity.z); Vector3 velocityDelta = targetHorizontalVelocity - currentHorizontalVelocity; // 转换为适合FixedUpdate的力(除以fixedDeltaTime保证速度稳定) playerRb.AddForce(velocityDelta / Time.fixedDeltaTime, ForceMode.Force); }
方案二:完全改用AddForce实现移动(更推荐)
彻底抛弃直接修改velocity的方式,全程用AddForce控制玩家移动,这样所有力(玩家移动、跳跃、外部推动)都会通过物理引擎自然叠加:
private void DefaultMoveRigidBody() { Vector3 move = new Vector3(movementInput.x, 0, movementInput.y); Vector3 moveVector = transform.TransformDirection(move) * movementSpeed; Vector3 targetMoveDirection; // 确定目标移动方向(平地/斜坡) if (Physics.CheckSphere(FeetTransform.position, 1f, layerMask) && canJump && OnSlope()) { targetMoveDirection = Vector3.ProjectOnPlane(moveVector, slopeHit.normal); } else { targetMoveDirection = new Vector3(moveVector.x, 0, moveVector.z); } // 计算需要的水平加速度,用AddForce施加 Vector3 desiredVelocity = targetMoveDirection; Vector3 currentHorizontalVelocity = new Vector3(playerRb.velocity.x, 0, playerRb.velocity.z); Vector3 velocityChange = desiredVelocity - currentHorizontalVelocity; velocityChange /= Time.fixedDeltaTime; // 转换为适合FixedUpdate的加速度 playerRb.AddForce(velocityChange, ForceMode.Force); // 跳跃逻辑保留,可选去掉清零Y速度的操作(如果不需要取消下落惯性) if (jumped && Physics.CheckSphere(FeetTransform.position, 1f, layerMask) && canJump) { canJump = false; jumpTimer = 0.5f; // 若需要取消下落惯性再起跳,保留这行;否则删除 // playerRb.velocity = new Vector3(playerRb.velocity.x, 0, playerRb.velocity.z); playerRb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); } // 跳跃冷却逻辑不变 if (!canJump) { jumpTimer -= Time.deltaTime; if (jumpTimer <= 0f) { canJump = true; jumpTimer = 0.5f; } } // 角色旋转逻辑不变,简化写法 if (move != Vector3.zero) { Quaternion toRotation = Quaternion.LookRotation(-move, Vector3.up); transform.GetChild(0).localRotation = Quaternion.RotateTowards(transform.GetChild(0).localRotation, toRotation, rotationSpeed * Time.deltaTime); } }
外部推动的处理
其他文件中的AddForce(ForceMode.Impulse)不需要额外修改,只要玩家移动逻辑不再直接覆盖velocity,这个推力就会和玩家的移动速度自然叠加,物理引擎会自动处理最终速度的计算。
内容的提问来源于stack exchange,提问作者realsrbic
相关产品推荐
相关产品推荐

