unity 刚体物体收到两倍于它应该收到的力

Unity rigid object receives twice the force it is supposed to receive

我正在制作一款子弹可以围绕玩家旋转的游戏。轨道是圆形的,而不是椭圆形的。子弹的阻力系数为 0。

一开始我只是简单的计算下一个在轨道上的位置,将delta位置除以fixedDeltaTime得到它的新速度

不幸的是,这意味着快速子弹会沿着多边形路径行驶,并且经常会错过目标。

我想通过给它们一个向内的力和一个几乎与轨道相切的速度来提高精度,这样它们就沿着玩家周围的抛物线段而不是直线。

抛物线段由它们的起点和终点及其顶点定义,顶点必须位于轨道弧上,速度等于我之前使用的速度 ((endpos - startpos) / fixedDeltaTime)。

为了计算抛物线,我计算了圆弧和线段上的中点,它们的差值与施加的力成正比。

所以我们使用以下名称

fdt = fixedDeltaTime
t = fdt / 2
f = the force applied during the incoming physics frame
v0 = the velocity at the start of the frame
v1 = the velocity at the middle of the frame (at the vertex of the parabola)

dp1 = the relative position at the middle of the frame (midpos - startpos) and vertex of the parabola
dp2 = the relative position at the end of the frame (endpos - startpos)

力由以下两个方程定义:

// at vertex, only the "lateral" velocity remains
v1 = dp2 / fdt

// the difference between dp2 / 2 and dp1 is what the force can apply over half a frame

dp2 / 2 - dp1  = f * 0.5tt
therefore
(dp2 / 2 - dp1) / (0.5 * t * t) = f
(dp2 / 2 - dp1) / (0.5 * fdt/2 * fdt/2) = f
(dp2 - dp1 * 2) * 4 / (fdt * fdt) = f

//v0 is then easily calculated
v0 = v1 - t * force
v0 = (dp2 / fdt) - force * (fdt / 2)

然后我们得到这个工作代码:

Vector3 startPos = _rigidbody.position;

if (firstFrame == false && Vector3.Distance(predictedNextFramePos, startPos) > 0.01f)
    Debug.Log("WTF");

Vector3 nextPosition;
GetLocalOrbitPos(nextTime, out nextPosition);
nextPosition += _parent.GetPosition();

float fdt = Time.fixedDeltaTime;

float halfTime = (time + nextTime) / 2f;
Vector3 halfPosition;
GetLocalOrbitPos(halfTime, out halfPosition);
halfPosition += _parent.GetPosition();

Vector3 dp2 = nextPosition - startPos;
Vector3 dp1 = halfPosition - startPos;

Vector3 force = (dp2 - 2 * dp1) * 4 / (fdt * fdt);
Vector3 v0 = (dp2 / fdt) - (force * fdt / 2f);

Vector3 deltaPosPredicted = PhysicsTools.GetMovement(v0, force, fdt);
if (Vector3.Distance(deltaPosPredicted, dp2) > 0.001f)
    Debug.Log("position prediction error: " + Vector3.Distance(deltaPosPredicted, dp2));

predictedNextFramePos = deltaPosPredicted + startPos;

Vector3 deltaHPosPredicted = PhysicsTools.GetMovement(v0, force, fdt / 2f);
if (Vector3.Distance(deltaHPosPredicted, dp1) > 0.001f)
    Debug.Log("position prediction error: " + Vector3.Distance(deltaHPosPredicted, dp1));

//drawing the startpos, midpos, endpos triangle
Debug.DrawLine(startPos, startPos + dp2, Color.magenta, Time.fixedDeltaTime * 2);
Debug.DrawLine(startPos, startPos + dp1, Color.red, Time.fixedDeltaTime * 2);
Debug.DrawLine(startPos + dp2, startPos + dp1, Color.red, Time.fixedDeltaTime * 2);
//drawing v0 and force
Debug.DrawLine(startPos, startPos + force, Color.gray, Time.fixedDeltaTime * 2);
Debug.DrawLine(startPos, startPos + v0, Color.blue, Time.fixedDeltaTime * 2);
//drawing the parabola arc
{
    Vector3 pos = startPos;
    Vector3 vel = v0;
    for (int i = 0; i < 10; i++)
    {
        Vector3 offset = PhysicsTools.GetMovementUpdateVelocity(ref vel, force, Time.fixedDeltaTime / 10f);
        Debug.DrawLine(pos, pos + offset, Color.green, Time.fixedDeltaTime * 2);
        pos += offset;
    }
}

// Old version
// Vector3 deltaPosition = nextPosition - _rigidbody.position;
// Vector3 velocity = deltaPosition / t;
// SetPhysicsState(_rigidbody.position, velocity, time);

//Applying results
SetPhysicsState(startPos, v0, time);
_rigidbody.AddForce(force / 2f, ForceMode.Acceleration);

我正在使用我的物理助手class

public static class PhysicsTools
{

    public static Vector3 GetMovement(Vector3 velocity, Vector3 force, float time)
    {
        return (velocity * time) + 0.5f * force * (time * time);
    }

    public static Vector3 GetMovementUpdateVelocity(ref Vector3 velocity, Vector3 force, float time)
    {
        Vector3 ret = (velocity * time) + 0.5f * force * (time * time);
        velocity += force * time;

        return ret;
    }
}

一切正常,但当且仅当我在施加力时将力除以二。我自己使用 PhysicsTools 的模拟不需要这样的篡改。

这是我的一个测试的图片,力因子同时应用于物理引擎和 PhysicsTools 模拟。您可以看到模拟的线条向远处飞去,但实际的射弹却没有,它应该保持在其怪异的五角星形中。

在这里我们可以看到它按预期工作(仍然减少了施加的力)

我的问题是,为什么我需要将那该死的力量一分为二?

伙计们,当你做出假设时会发生什么。

我假设 ForceMode.Continuous 意味着力将通过框架连续施加。事实并非如此。

unity 物理引擎无法进行任何类型的连续加速或抛物线投射。任何物体都沿直线移动,而 AddForce 只是当场修改速度。

事实证明,只需将力除以二就足以将起始速度重置为我之前对该问题的线性解决方案,而物体似乎在多边形之外做出反应的唯一原因是我的子弹对撞机比我想象的要宽得多。

请阅读此post了解更多信息:https://answers.unity.com/questions/696068/difference-between-forcemodeforceaccelerationimpul.html

解决该问题的唯一方法是提高物理帧速率,或者使用您自己的光线投射解决方案,这会带来一系列其他问题。