You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:32:03