C# 轨道天体在南半球上空不断旋转

C# 轨道天体在南半球上空不断旋转,c#,unity3d,rotation,quaternions,C#,Unity3d,Rotation,Quaternions,我试图让我的身体自己在地球上行走,但当身体到达地球的“下”半球时,问题就出现了。 每当身体到达那里,它就会疯狂地旋转,直到身体回到地球的“上”半球才会停止。 吸引子 public class Attractor : MonoBehaviour { [SerializeField] private float _gravity = -10; public void Attract(Body body) { Vector3 targetDir = (body

我试图让我的身体自己在地球上行走,但当身体到达地球的“下”半球时,问题就出现了。
每当身体到达那里,它就会疯狂地旋转,直到身体回到地球的“上”半球才会停止。
吸引子

public class Attractor : MonoBehaviour
{
    [SerializeField] private float _gravity = -10;

    public void Attract(Body body)
    {
        Vector3 targetDir = (body.transform.position - transform.position).normalized;
        Vector3 bodyUp = body.transform.up;

        body.transform.rotation *= Quaternion.FromToRotation(bodyUp, targetDir);
        body.GetComponent<Rigidbody>().AddForce(targetDir * _gravity);
    }
}  
public class Body : MonoBehaviour
{
    [SerializeField] private Attractor _curAttractor;

    private Rigidbody _rb;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _rb.useGravity = false;
        _rb.constraints = RigidbodyConstraints.FreezeRotation;
    }

    private void FixedUpdate()
    {
        _curAttractor.Attract(this);
    }
}  
public class PathFollower : MonoBehaviour
{
    [SerializeField] private float _moveSpeed;
    [SerializeField] private float _reach;
    private Path _curPath;
    private Rigidbody _rb;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
    }

    public void FollowPath(Path p)
    {
        StopAllCoroutines();
        _curPath = p;
        StartCoroutine(FollowCtn());
    }

    private IEnumerator FollowCtn()
    {
        int i = 0;
        Vector3 target;

        while (i < _curPath.Nodes.Length)
        {
            target = PathfindingData.NodeToWorldPosition(_curPath.Nodes[i]);
            Vector3 dir;

            while (Vector3.Distance(transform.position, target) > _reach)
            {
                dir = target - transform.position;
                dir.Normalize();
                _rb.MovePosition(_rb.position + dir * _moveSpeed * Time.deltaTime);
                yield return null;
            }

            i++;
        }

        _rb.velocity = Vector3.zero;
        _curPath = null;
    }
}  
公共类吸引子:单行为
{
[SerializeField]专用浮点数_重力=-10;
公共空间吸引(主体)
{
Vector3 targetDir=(body.transform.position-transform.position).normalized;
Vector3 bodyUp=body.transform.up;
body.transform.rotation*=四元数FromToRotation(bodyUp,targetDir);
body.GetComponent().AddForce(targetDir*_重力);
}
}  
身体

public class Attractor : MonoBehaviour
{
    [SerializeField] private float _gravity = -10;

    public void Attract(Body body)
    {
        Vector3 targetDir = (body.transform.position - transform.position).normalized;
        Vector3 bodyUp = body.transform.up;

        body.transform.rotation *= Quaternion.FromToRotation(bodyUp, targetDir);
        body.GetComponent<Rigidbody>().AddForce(targetDir * _gravity);
    }
}  
public class Body : MonoBehaviour
{
    [SerializeField] private Attractor _curAttractor;

    private Rigidbody _rb;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _rb.useGravity = false;
        _rb.constraints = RigidbodyConstraints.FreezeRotation;
    }

    private void FixedUpdate()
    {
        _curAttractor.Attract(this);
    }
}  
public class PathFollower : MonoBehaviour
{
    [SerializeField] private float _moveSpeed;
    [SerializeField] private float _reach;
    private Path _curPath;
    private Rigidbody _rb;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
    }

    public void FollowPath(Path p)
    {
        StopAllCoroutines();
        _curPath = p;
        StartCoroutine(FollowCtn());
    }

    private IEnumerator FollowCtn()
    {
        int i = 0;
        Vector3 target;

        while (i < _curPath.Nodes.Length)
        {
            target = PathfindingData.NodeToWorldPosition(_curPath.Nodes[i]);
            Vector3 dir;

            while (Vector3.Distance(transform.position, target) > _reach)
            {
                dir = target - transform.position;
                dir.Normalize();
                _rb.MovePosition(_rb.position + dir * _moveSpeed * Time.deltaTime);
                yield return null;
            }

            i++;
        }

        _rb.velocity = Vector3.zero;
        _curPath = null;
    }
}  
公共类主体:单一行为
{
[SerializeField]私有吸引器_curAttractor;
私人刚体;
私人空间
{
_rb=GetComponent();
_rb.useGravity=false;
_rb.constraints=刚体约束.freeze旋转;
}
私有void FixedUpdate()
{
_吸引(这个);
}
}  
PathFollower

public class Attractor : MonoBehaviour
{
    [SerializeField] private float _gravity = -10;

    public void Attract(Body body)
    {
        Vector3 targetDir = (body.transform.position - transform.position).normalized;
        Vector3 bodyUp = body.transform.up;

        body.transform.rotation *= Quaternion.FromToRotation(bodyUp, targetDir);
        body.GetComponent<Rigidbody>().AddForce(targetDir * _gravity);
    }
}  
public class Body : MonoBehaviour
{
    [SerializeField] private Attractor _curAttractor;

    private Rigidbody _rb;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
        _rb.useGravity = false;
        _rb.constraints = RigidbodyConstraints.FreezeRotation;
    }

    private void FixedUpdate()
    {
        _curAttractor.Attract(this);
    }
}  
public class PathFollower : MonoBehaviour
{
    [SerializeField] private float _moveSpeed;
    [SerializeField] private float _reach;
    private Path _curPath;
    private Rigidbody _rb;

    private void Awake()
    {
        _rb = GetComponent<Rigidbody>();
    }

    public void FollowPath(Path p)
    {
        StopAllCoroutines();
        _curPath = p;
        StartCoroutine(FollowCtn());
    }

    private IEnumerator FollowCtn()
    {
        int i = 0;
        Vector3 target;

        while (i < _curPath.Nodes.Length)
        {
            target = PathfindingData.NodeToWorldPosition(_curPath.Nodes[i]);
            Vector3 dir;

            while (Vector3.Distance(transform.position, target) > _reach)
            {
                dir = target - transform.position;
                dir.Normalize();
                _rb.MovePosition(_rb.position + dir * _moveSpeed * Time.deltaTime);
                yield return null;
            }

            i++;
        }

        _rb.velocity = Vector3.zero;
        _curPath = null;
    }
}  
公共类路径跟随者:单行为
{
[SerializeField]专用浮点运算速度;
[SerializeField]专用浮动范围;
专用路径_curPath;
私人刚体;
私人空间
{
_rb=GetComponent();
}
公共无效跟随路径(路径p)
{
StopAllCoroutines();
_curPath=p;
startcroutin(FollowCtn());
}
私有IEnumerator FollowCtn()
{
int i=0;
矢量3靶;
while(i<\u curPath.Nodes.Length)
{
target=PathfindingData.NodeToWorldPosition(_curPath.Nodes[i]);
向量3-dir;
while(矢量3.距离(变换.位置,目标)>\u到达)
{
dir=目标-变换位置;
dir.Normalize();
_rb.MovePosition(_rb.position+dir*_moveSpeed*Time.deltaTime);
收益返回空;
}
i++;
}
_rb.速度=矢量3.0;
_curPath=null;
}
}  
你知道是什么导致了这种奇怪的行为吗

以下是我所说的疯狂旋转的意思:

当您只关心一个轴指向的位置时,从旋转开始
是最好的选择,因为它将以任何方式改变其他轴的方向,从而使两个旋转之间的角度最小化。换句话说,
FromToRotation
将改变对象的偏航,如果这样做可以减少俯仰或滚动所需的变化

因为您关心变换的
向上
(始终指向远离吸引子的方向)和
向前
(在
固定更新
调用之间尽可能少地更改),所以最好使用另一种路由

使用和将
targetDir
方向指定为向上,并尽可能保持主体的
transform.forward
不变(如果它们是共线的,则使用
forward
的任意方向):

vector3targetdir=(body.transform.position-transform.position);
Vector3 bodyForward=body.transform.forward;
向量3.正交规范化(ref targetDir,ref bodyForward);
body.transform.rotation=四元数.LookRotation(bodyForward,targetDir);
body.GetComponent().AddForce(targetDir*_重力);