He estado implementando un motor de física personalizado, y estoy bastante cerca de que funcione como me gustaría. Hay una fuerza gravitacional, colisiones y respuesta de colisión. Desafortunadamente, parece haber cierta inquietud entre los objetos casi estacionarios, muy probablemente debido a las garrapatas físicas que no cambian.
Busqué en línea y probé algunas de las implementaciones que encontré, incluidos algunos de mis propios intentos. Aquí están las soluciones que probé:
- Movimiento de amortiguación cuando la velocidad / momento / energía potencial está por debajo de un umbral.
- Solo aplica la gravedad cuando la velocidad / momento / energía potencial está por encima del umbral.
- Implementando una función de sueño. que comprueba la posición del objeto durante los últimos 60 fotogramas y duerme si no se ha movido fuera de un cuadro de límite del límite.
- Iterando a través de los objetos de arriba a abajo al aplicar pruebas de colisión y resolución.
Aquí está mi código:
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);
}
}
¿Cómo evito el temblor entre los objetos de física casi estacionarios?
physics
vector
collision-resolution
あ ら ま あ
fuente
fuente
Respuestas:
Bueno, resulta que uno de mis controles booleanos estaba causando este problema.
Este código aquí:
Estaba rompiendo todo. Tenía la impresión de que simplemente ignoraría las colisiones consigo mismo, pero por cualquier razón, era evitar que las colisiones ocurrieran en el orden correcto. No estoy seguro de por qué, creo que es un error en el motor del juego que estoy usando. De todos modos, aquí está el código de trabajo, que implementa un estado de suspensión para todas las bolas: cuando el movimiento después de 30 fotogramas se limita a cierta área de delimitación, el objeto se pone en un estado de suspensión, durante el cual no se aplican fuerzas (gravedad en este ejemplo). Se despierta después de que algo se desplaza fuera de esta área delimitador, generalmente un ajuste o colisión de otra bola.
fuente