奇怪的对象旋转,即使旋转约束被冻结(Unity 引擎)

Weird object rotation even with rotation constraints frozen (Unity Engine)

我有一个 3D 世界的游戏space。游戏是二维的。因此,玩家的位置在 1 个轴上冻结,旋转在 2 个轴上冻结。位置冻结工作正常。然而,一些玩家在游戏过程中遇到了不想要的对象旋转,即使有冻结约束(我在 BETA 测试期间从未遇到过这样的问题)

我自己测试时的限制:

我的代码(玩家移动脚本)

public class Movement : MonoBehaviour
{
    public Rigidbody rb;
    public int clickForce = 500;
    private Plane plane = new Plane(Vector3.up, Vector3.zero);
    public float speed;
    public Slider staminaBar;

    private void Start()
    {
        Rigidbody rb = GetComponent<Rigidbody>();
        rb.centerOfMass = Vector3.zero;
        rb.inertiaTensorRotation = Quaternion.identity;
    }

    void FixedUpdate()
    {
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Confined;

        if (Input.GetMouseButton(0))
        {
            if (staminaBar.value > 0.25)
            {
                var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

                float enter;

                if (plane.Raycast(ray, out enter))
                {
                    var hitPoint = ray.GetPoint(enter);
                    var mouseDir = hitPoint - gameObject.transform.position;
                    mouseDir = mouseDir.normalized;
                    rb.AddForce(mouseDir * clickForce);
                }

                Plane playerPlane = new Plane(Vector3.up, transform.position);
                Ray rayy = Camera.main.ScreenPointToRay(Input.mousePosition);
                float hitdist = 0.0f;

                if (playerPlane.Raycast(rayy, out hitdist))
                {
                Vector3 targetPoint = rayy.GetPoint(hitdist);
                Quaternion targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
                transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
                }
            }
        }
    }
}

提前致谢!

如@Iggy 所示,分配给变换会忽略并覆盖刚体约束。要解决此问题,您可以使用一些矢量数学和 Quaternion.LookRotation 的第二个参数将局部向上轴限制在其当前方向。评论中的解释:

if (playerPlane.Raycast(rayy, out hitdist))
{
    Vector3 targetPoint = rayy.GetPoint(hitdist);
    Vector3 targetDir = targetPoint - transform.position;
    // Find direction orthogonal to both targetDir and current local up.
    // this will become local right.
    Vector3 newLocalRight = Vector3.Cross(transform.up, targetDir);
    
    // If local up and target dir are colinear, do something sensible
    // like not changing the rotation
    if (newLocalRight == Vector3.zero) 
    { 
        /* something sensible */
        /* doing nothing may be the sensible choice */ 
    }
    else 
    {
        // If they are not colinear, determine the direction perpendicular to local up 
        // and local right. This will be the fixed forward direction.
        Vector3 newLocalForward = Vector3.Cross(newLocalRight, transform.up);

        // Assign a rotation using the fixed forward direction, and the current local up
        Quaternion targetRotation = Quaternion.LookRotation(newLocalForward, 
                transform.up);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 
                speed * Time.deltaTime);
    }
 
}