Saya telah menerapkan mesin fisika khusus, dan saya cukup dekat untuk membuatnya berfungsi seperti yang saya inginkan. Ada gaya gravitasi, tumbukan dan respons tumbukan. Sayangnya, tampaknya ada beberapa kegelisahan di antara benda-benda yang hampir diam, kemungkinan besar karena kutu fisika rendah yang tidak dapat diubah.
Saya telah melihat online, dan mencoba beberapa implementasi yang saya temukan, termasuk beberapa upaya saya sendiri. Inilah solusi yang saya coba:
- Gerakan redaman ketika kecepatan / momentum / energi potensial di bawah ambang batas.
- Hanya menerapkan gravitasi ketika kecepatan / momentum / energi potensial berada di atas ambang batas.
- Menerapkan fungsi tidur. yang memeriksa posisi objek untuk 60 frame terakhir, dan tidur jika belum bergerak di luar kotak pembatas ambang batas.
- Iterasi melalui objek dari atas ke bawah saat menerapkan pengujian dan resolusi tabrakan.
Ini kode saya:
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);
}
}
Bagaimana cara mencegah jitter di antara benda-benda fisika yang tidak bergerak?