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?
physics
vector
collision-resolution
あ ら ま あ
quelle
quelle
Antworten:
Nun, es stellt sich heraus, dass eine meiner booleschen Prüfungen dieses Problem verursacht hat.
Dieser Code hier:
Brach alles. Ich hatte den Eindruck, dass es Kollisionen mit sich selbst einfach ignorieren würde, aber aus irgendeinem Grund wurde verhindert, dass Kollisionen in der richtigen Reihenfolge auftreten. Ich weiß nicht genau warum, ich denke, es ist ein Fehler in der Spiel-Engine, die ich benutze. Wie auch immer, hier ist der Arbeitscode, der einen Schlafzustand für alle Bälle implementiert - wenn die Bewegung nach 30 Bildern auf einen bestimmten Begrenzungsbereich beschränkt ist, wird das Objekt in einen Schlafzustand versetzt, in dem keine Kräfte auf es ausgeübt werden (Schwerkraft in diesem Fall) Beispiel). Es wird geweckt, nachdem es durch etwas außerhalb dieses Begrenzungsbereichs verschoben wurde - normalerweise durch eine Anpassung oder Kollision durch einen anderen Ball.
quelle