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?
physics
vector
collision-resolution
あ ら ま あ
sumber
sumber
Jawaban:
Ya, ternyata salah satu cek boolean saya yang menyebabkan masalah ini.
Kode ini di sini:
Merusak segalanya. Saya mendapat kesan bahwa itu hanya akan mengabaikan tabrakan dengan dirinya sendiri tetapi untuk alasan apa pun, itu mencegah tabrakan terjadi dalam urutan yang benar. Tidak begitu yakin mengapa, saya pikir itu adalah bug di mesin permainan yang saya gunakan. Bagaimanapun, ini adalah kode kerja, yang menerapkan kondisi tidur untuk semua bola - ketika gerakan setelah 30 frame terbatas pada area pembatas tertentu, objek diletakkan dalam kondisi tidur, selama tidak ada gaya yang diterapkan padanya (gravitasi dalam hal ini). contoh). Itu dibangunkan setelah dipindahkan di luar area pembatas ini oleh sesuatu - biasanya penyesuaian atau tabrakan dengan bola lain.
sumber