即使旋转约束冻结Unity引擎

问题描述

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

Object wierd rotation.

我自己测试时的限制:

enter image description here

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

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);
    }
 
}