Ich habe eine benutzerdefinierte Physik-Engine implementiert und bin ziemlich nahe daran, dass sie so funktioniert, wie ich es gerne hätte. Es gibt eine Gravitationskraft, Kollisionen und Kollisionsreaktionen. Leider scheint es bei nahezu stationären Objekten einen gewissen Jitter zu geben, was höchstwahrscheinlich auf unveränderlich niedrige physikalische Zecken zurückzuführen ist.
Ich habe online gesucht und einige der gefundenen Implementierungen ausprobiert, einschließlich einiger meiner eigenen Versuche. Hier sind die Lösungen, die ich ausprobiert habe:
- Dämpfungsbewegung, wenn Geschwindigkeit / Impuls / potentielle Energie unter einem Schwellenwert liegen.
- Anwendung der Schwerkraft nur, wenn Geschwindigkeit / Impuls / potentielle Energie über dem Schwellenwert liegen.
- Implementieren einer Schlaffunktion. Das überprüft die Position des Objekts für die letzten 60 Frames und schläft, wenn es sich nicht außerhalb eines Schwellenwert-Begrenzungsrahmens bewegt hat.
- Durchlaufen der Objekte von oben nach unten, wenn Kollisionstests und Auflösungen angewendet werden.
Hier ist mein Code:
for each (auto ball in m_Balls)
{
ball->Update(t);
ball->Accelerate(m_Gravity);
}
// This disgusting hack sorts the balls by height. In a more complete physics
// implementation, I guess I could change the sorting based on the direction of
// gravitational force. This hack is necessary to prevent balls being pulled downwards
// into other balls by gravity; by calculating from the bottom of the pile of
// objects, we avoid issues that occur when adjustments push the object towards gravity.
m_Balls.sort([](const CSprite* a, const CSprite* b)
{return a->m_pos.m_y < b->m_pos.m_y; });
static float cor = 0.8f;
for each (auto ball in m_Balls)
{
for each (auto collider in m_Walls)
{
if (collider->HitTest(ball, 1))
{
float offset = 0;
auto n = Helper::GetNormal(ball, collider, offset);
ball->SetPosition(ball->GetPosition() + (n * offset));
auto r = ball->GetVelocity() - ((1 + cor) * Dot(ball->GetVelocity(), n) * n);
ball->SetVelocity(r);
ball->SetPosition(ball->GetPosition() + ball->GetVelocity() * DeltaTime());
}
}
CVector adjustment;
for each (auto collider in m_Balls)
{
if (ball == collider)
{
break;
}
auto diff = collider->GetPosition() - ball->GetPosition();
float distance = diff.Length();
if (distance <= (ball->GetWidth() / 2) + (collider->GetWidth() / 2))
{
auto midPoint = (ball->GetPosition() + collider->GetPosition()) * 0.5f;
adjustment = diff.Normalise() * (ball->GetWidth() / 2
- Distance(ball->GetPosition(), midPoint));
ball->SetPosition(ball->GetPosition() - adjustment);
diff = collider->GetPosition() - ball->GetPosition();
if (Dot(ball->GetVelocity() - collider->GetVelocity(), diff) > 0)
{
auto n = diff.Normalise();
auto u = Dot(cor * ball->GetVelocity() - collider->GetVelocity(), n) * n;
ball->Accelerate(-u);
collider->Accelerate(u);
}
}
}
if (ball->GetSpeed() > MAX_SPEED)
{
ball->SetSpeed(MAX_SPEED);
}
}
Wie verhindere ich Jitter zwischen nahezu stationären Physikobjekten?