环绕 body 在南半球上空不断旋转
Orbiting body constantly spinning while over southern hemisphere
我试图让我的身体自己在地球上行走,但是当 body 到达地球的 "lower" 半球时出现问题。
每当 body 到达那里,它就会疯狂地旋转,直到 body 回到地球的 "upper" 半球才会停止。
吸引子
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);
}
}
Body
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;
}
}
关于可能导致这种奇怪行为的原因有什么想法吗?
这就是我所说的疯狂旋转的意思:
FromToRotation
当您关心只有一个轴指向的位置时最好,因为它会以任何方式改变其他轴的方向,从而最小化两个旋转之间的角度。换句话说,FromToRotation
将改变您的 object 的偏航,如果这样做减少了俯仰或滚动所需的变化。
因为您关心变换的 up
(始终指向远离吸引子的方向)和 forward
(在 FixedUpdate
调用之间尽可能少地改变),所以另一条路线更可取.
用Vector3.OrthoNormalize
and Quaternion.LookRotation
指定targetDir
方向向上,body的transform.forward
尽可能保持不变(如果共线,任意使用 forward
的方向):
Vector3 targetDir = (body.transform.position - transform.position).normalized;
Vector3 bodyForward = body.transform.forward;
Vector3.OrthoNormalize(ref targetDir, ref bodyForward);
body.transform.rotation = Quaternion.LookRotation(bodyForward, targetDir);
body.GetComponent<Rigidbody>().AddForce(targetDir * _gravity);
我试图让我的身体自己在地球上行走,但是当 body 到达地球的 "lower" 半球时出现问题。
每当 body 到达那里,它就会疯狂地旋转,直到 body 回到地球的 "upper" 半球才会停止。
吸引子
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);
}
}
Body
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;
}
}
关于可能导致这种奇怪行为的原因有什么想法吗?
这就是我所说的疯狂旋转的意思:
FromToRotation
当您关心只有一个轴指向的位置时最好,因为它会以任何方式改变其他轴的方向,从而最小化两个旋转之间的角度。换句话说,FromToRotation
将改变您的 object 的偏航,如果这样做减少了俯仰或滚动所需的变化。
因为您关心变换的 up
(始终指向远离吸引子的方向)和 forward
(在 FixedUpdate
调用之间尽可能少地改变),所以另一条路线更可取.
用Vector3.OrthoNormalize
and Quaternion.LookRotation
指定targetDir
方向向上,body的transform.forward
尽可能保持不变(如果共线,任意使用 forward
的方向):
Vector3 targetDir = (body.transform.position - transform.position).normalized;
Vector3 bodyForward = body.transform.forward;
Vector3.OrthoNormalize(ref targetDir, ref bodyForward);
body.transform.rotation = Quaternion.LookRotation(bodyForward, targetDir);
body.GetComponent<Rigidbody>().AddForce(targetDir * _gravity);