J'ai implémenté un moteur physique personnalisé et je suis presque sur le point de le faire fonctionner comme je le voudrais. Il y a une force gravitationnelle, des collisions et une réponse aux collisions. Malheureusement, il semble y avoir une certaine gigue parmi les objets quasi stationnaires, probablement en raison de tics inchangeables à faible physique.
J'ai regardé en ligne et essayé certaines des implémentations que j'ai trouvées, y compris certaines de mes propres tentatives. Voici les solutions que j'ai essayées:
- Mouvement d'amortissement lorsque la vitesse / l'élan / l'énergie potentielle est inférieure à un seuil.
- Appliquer la gravité uniquement lorsque la vitesse / l'élan / l'énergie potentielle est supérieure au seuil.
- Implémentation d'une fonction sommeil. qui vérifie la position de l'objet pour les 60 dernières images et s'endort s'il ne s'est pas déplacé en dehors d'une zone de délimitation de seuil.
- Itération à travers les objets de haut en bas lors de l'application des tests de collision et de la résolution.
Voici mon 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);
}
}
Comment éviter la gigue parmi les objets physiques quasi stationnaires?
physics
vector
collision-resolution
あ ら ま あ
la source
la source
Réponses:
Eh bien, il s'avère que l'un de mes contrôles booléens était à l'origine de ce problème.
Ce code ici:
Brisait tout. J'avais l'impression qu'il ignorerait simplement les collisions avec lui-même, mais pour une raison quelconque, cela empêcherait les collisions de se produire dans le bon ordre. Je ne sais pas exactement pourquoi, je pense que c'est un bug dans le moteur de jeu que j'utilise. Quoi qu'il en soit, voici le code de travail, qui implémente un état de sommeil pour toutes les boules - lorsque le mouvement après 30 images est limité à une certaine zone de délimitation, l'objet est mis dans un état de sommeil, pendant lequel aucune force ne lui est appliquée (la gravité dans ce exemple). Il est réveillé après avoir été déplacé à l'extérieur de cette zone de délimitation par quelque chose - généralement un ajustement ou une collision avec une autre balle.
la source