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

Unity 3D:简易胶囊角色自稳定器开发问题求助

胶囊角色不倒翁自扶正解决方案

现有代码问题分析

  • 第一段代码:仅处理Z轴旋转,未覆盖胶囊倾斜的主要方向(X轴);在OnCollisionStay中持续施加扭矩易引发过冲翻滚;未结合物理帧时间增量计算扭矩,力的控制不稳定。
  • 第二段代码:错误将扭矩施加到Y轴(Y轴为角色转向轴,不应参与扶正逻辑);Quaternion.Angle返回无方向的正角度,用Mathf.Sign(angle)无法正确判断旋转方向,导致扶正力方向完全错误。

有效实现代码

使用FixedUpdate处理物理逻辑,通过计算当前旋转与目标直立旋转的差值施加扭矩,同时加入角速度阻尼避免过冲:

using UnityEngine;

public class SelfRighting : MonoBehaviour
{
    [SerializeField] private Rigidbody _rb;
    [SerializeField] private float _rightingTorque = 20f;
    [SerializeField] private float _maxAngle = 60f;
    [SerializeField] private float _angularDamping = 0.5f;

    private void FixedUpdate()
    {
        if (IsGrounded())
        {
            // 目标旋转:保留当前Y轴转向,X、Z轴回正
            Quaternion targetRot = Quaternion.Euler(0f, transform.rotation.eulerAngles.y, 0f);
            // 计算当前旋转与目标旋转的差值
            Quaternion deltaRot = targetRot * Quaternion.Inverse(transform.rotation);
            Vector3 deltaEuler = deltaRot.eulerAngles;

            // 修正欧拉角360度循环问题,转换为-180~180范围
            deltaEuler.x = Mathf.DeltaAngle(0f, deltaEuler.x);
            deltaEuler.z = Mathf.DeltaAngle(0f, deltaEuler.z);

            // 限制最大倾斜角度,避免过度施力
            float clampedX = Mathf.Clamp(deltaEuler.x, -_maxAngle, _maxAngle);
            float clampedZ = Mathf.Clamp(deltaEuler.z, -_maxAngle, _maxAngle);

            // 计算与倾斜角度成正比的扶正扭矩
            Vector3 torque = new Vector3(clampedX, 0f, clampedZ) * _rightingTorque * Time.fixedDeltaTime;
            torque = transform.TransformDirection(torque);

            _rb.AddTorque(torque);

            // 角速度阻尼,减少过冲摇晃
            Vector3 angularVelocity = _rb.angularVelocity;
            angularVelocity.x *= (1 - _angularDamping * Time.fixedDeltaTime);
            angularVelocity.z *= (1 - _angularDamping * Time.fixedDeltaTime);
            _rb.angularVelocity = angularVelocity;
        }
    }

    // 射线检测判断是否接触地面(可根据场景调整)
    private bool IsGrounded()
    {
        float rayLength = 0.1f;
        Vector3 rayStart = transform.position - new Vector3(0f, transform.localScale.y / 2f, 0f);
        return Physics.Raycast(rayStart, Vector3.down, rayLength, LayerMask.GetMask("Ground"));
    }
}

使用说明

  1. 将脚本挂载到胶囊角色上,拖入对应Rigidbody组件。
  2. 调整参数适配场景:
    • _rightingTorque:扶正力度,数值越大扶正速度越快。
    • _maxAngle:最大倾斜角度限制,超出后不再施加额外力度。
    • _angularDamping:角速度阻尼,数值越大越不容易出现过冲摇晃。
  3. 确保地面Layer设置为Ground,或修改IsGrounded中的LayerMask匹配你的场景配置。

关键改进点

  • 用FixedUpdate处理物理逻辑:贴合Unity物理更新时机,避免力的帧间不稳定。
  • 精准计算倾斜方向:正确识别X、Z轴的倾斜角度,确保扭矩方向始终指向直立状态。
  • 加入角速度阻尼:解决过冲翻滚问题,实现平滑的扶正效果。
  • 射线检测替代OnCollisionStay:避免持续触发导致的力叠加异常。

内容的提问来源于stack exchange,提问作者desl8

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:43:11