我正在尝试使用Unity制作一个游戏,该游戏使用在轨的并且可以过渡到不同行星的火箭,但是我需要根据当前火箭分配的速度/方向实时预测火箭的路径就像spaceflight simulator一样。
在将刚体添加重力时,我设法获得了逼真的物理和轨道:
public interface IMyClass
{
bool NeedsMoreWork(Item item, out Part part);
bool DoWork(Item item);
}
public class MyClass : IMyClass
{
private ILogger log;
public MyClass(ILogger log)
{
this.log = log;
}
public bool NeedsMoreWork(Item item, out Part part)
{
log.Debug($"Examining item {item.Id}");
part = null;
if (item.Completed())
{
log.Debug($"Item {item.Id} already completed.");
return false;
}
part = item.GetNextPart();
log.Debug($"Item {item.Id} needs work on part {part.Id}.");
return true;
}
public bool DoWork(Item item)
{
if (!item.NeedsMoreWork(item, out Part part))
return false;
log.Debug($"Starting work on part {part.Id}.");
// Do work on part.
log.Debug($"Work completed on part {part.Id}.");
return true;
}
}
[TestMethod]
public void TestDoWork()
{
// Version with Configure():
var subst1 = Substitute.ForPartsOf<MyClass>(Substitute.For<ILogger>());
subst1.Configure()
.NeedsMoreWork(Arg.Any<Item>(), out Arg.Any<Part>())
.Returns(false);
// Version with WhenForAnyArgs():
var subst2 = Substitute.ForPartsOf<MyClass>(Substitute.For<ILogger>());
subst2.WhenForAnyArgs(x => x.NeedsMoreWork(Arg.Any<Item>(), out Arg.Any<Part>())
.Returns(false);
}
但是我不知道如何预测未来的时间点来确定我的轨道形状。
我尝试使用 var sateliteCords = Satelite.transform.position;
var planetCords = gameObject.transform.position;
var distance = sateliteCords - planetCords;
distanceFromSatelite = Vector3.Distance(Satelite.transform.position, gameObject.transform.position);
F = (Gravity * Mass) / Mathf.Pow(distanceFromSatelite,2);
forces = (distance / Mathf.Sqrt(Mathf.Pow(distance.x, 2)+ Mathf.Pow(distance.y, 2)+ Mathf.Pow(distance.z, 2))) * -F;
Satelite.GetComponent<Rigidbody>().AddForce(forces * Time.deltaTime, ForceMode.Force);
“加快仿真速度”,但速度不够快。
我在某处读到我需要一份通过统一更新独立运行的太阳系的副本,然后从那里计算火箭的轨迹,但我不知道该如何处理。
物理模拟方面我有点菜鸟,所以你们其中的天才可以帮忙吗?
答案 0 :(得分:2)
这是您的代码实际在做什么:
var sateliteCords = Satelite.transform.position;
var planetCords = gameObject.transform.position;
var distance = sateliteCords - planetCords;
distanceFromSatelite = distance.magnitude;
F = (Gravity * Mass) / Mathf.Pow(distanceFromSatelite,2);
forces = distance / distanceFromSatellite * -F;
Satelite.GetComponent<Rigidbody>().AddForce(forces * Time.deltaTime, ForceMode.Force);
您可以通过以下方法进一步减少它:
var distance = sateliteCords - planetCords;
distanceSqrMag = distance.sqrMagnitude;
F = (Gravity * Mass) / distanceSqrMag;
forces = distance.normalized * -F;
Satelite.GetComponent<Rigidbody>().AddForce(forces * Time.deltaTime, ForceMode.Force);
现在代码更简单了,我可以找到一个严重的错误。 ForceMode.Force已经将Force乘以Time.deltaTime。您想要的是切换到ForceMode.Impulse,或删除deltaTime。
F = (Gravity * Mass) / distanceSqrMag;
forces = distance.normalized * -F;
Satelite.GetComponent<Rigidbody>().AddForce(forces, ForceMode.Force);
或更妙的是,假设质量是卫星的质量,并且重力不是一般常数,而仅仅是行星的局部重力。 ForceMode.Force将力除以所施加的刚体的质量。
F = Gravity / distanceSqrMag;
forces = distance.normalized * -F;
Satelite.GetComponent<Rigidbody>().AddForce(forces, ForceMode.Acceleration);
现在就解决了,您可以通过执行类似的操作来做一个非常简单的近似值
var currentPos = _rigidBody.position;
var prevPos = currentPos;
var currentVelocity = _rigidBody.velocity;
var planetCords = gameObject.transform.position;
for (int i = 0; i < stepCount; i++)
{
var distance = planetCords - currentPos;
var forceMag = Gravity / distance.sqrMagnitude;
forces = distance.normalized * forceMag;
currentVelocity += forces * Time.fixedDeltaTime;
currentPos += currentVelocity * Time.fixedDeltaTime;
//Replace by a TrailRenderer you reset each frame
Debug.DrawLine(prevPos, currentPos, Color.Red, Time.deltaTime);
prevPos = currentPos;
}
请注意,此代码未经测试,我可能在这里或那里犯了一个错误,但这就是要点。
不用担心在轨迹上会有所不同,这正是团结预测位置的方法。当您拥有所需的全部计算能力时,就无需花哨的计算。
如果您想要的不仅仅是一个人体重力模拟,那很简单。要么应用所有行星的重力,要么简单地考虑最近的行星的重力。如果您的行星少于十二个,我建议您使用前者。
您不需要圆锥曲线,高级数学或任何形式的数学。您不是路边空间计划。有时蛮力是最好的解决方案。