Bola a bola colisão - Ganhos de velocidade significativa sobre colisão
-
23-08-2019 - |
Pergunta
Eu implementei o código da questão " a bola colisão - Detecção e manipulação " em Objective-C. No entanto, sempre que as bolas colidem segundo um ângulo a sua velocidade aumenta dramaticamente. Toda a matemática vector é feito usando cocos2d-iphone , com o cabeçalho CGPointExtension.h. Qual é a causa desta aceleração indesejada?
O que se segue é um exemplo do aumento da velocidade:
Input:
massa == 12,56637
velocity.x == 1.73199439
velocity.y == -10,5695238
ball.mass == 12,56637
ball.velocity.x == 6.04341078
ball.velocity.y == 14.2686739
Output:
massa == 12,56637
velocity.x == 110.004326
velocity.y == -10,5695238
ball.mass == 12,56637
ball.velocity.x == -102,22892
ball.velocity.y == -72,4030228
#import "CGPointExtension.h"
#define RESTITUTION_CONSTANT (0.75) //elasticity of the system
- (void) resolveCollision:(Ball*) ball
{
// get the mtd (minimum translation distance)
CGPoint delta = ccpSub(position, ball.position);
float d = ccpLength(delta);
// minimum translation distance to push balls apart after intersecting
CGPoint mtd = ccpMult(delta, (((radius + ball.radius)-d)/d));
// resolve intersection --
// inverse mass quantities
float im1 = 1 / [self mass];
float im2 = 1 / [ball mass];
// push-pull them apart based off their mass
position = ccpAdd(position, ccpMult(mtd, (im1 / (im1 + im2))));
ball.position = ccpSub(ball.position, ccpMult(mtd, (im2 / (im1 + im2))));
// impact speed
CGPoint v = ccpSub(velocity, ball.velocity);
float vn = ccpDot(v,ccpNormalize(mtd));
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / ([self mass] + [ball mass]);
CGPoint impulse = ccpMult(mtd, i);
// change in momentum
velocity = ccpAdd(velocity, ccpMult(impulse, im1));
ball.velocity = ccpSub(ball.velocity, ccpMult(impulse, im2));
}
Solução
Eu sou o único que escreveu o código de salto bola original você referenciado. Se você download e experimentar esse código, você pode ver ele funciona bem.
O código a seguir está correto (a maneira que você originalmente tinha):
// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / (im1 + im2);
CGPoint impulse = ccpMult(mtd, i);
Este é um código de física muito comum e você pode vê-lo quase exatamente implementado como esta nos exemplos a seguir:
- Encontrar resposta colisão de dois objetos - GameDev
- 3D Pong Collision Response
- Outra bola a colisão bola escrito em Java
Isso é correto, e ~ não é ~ a criação de um CR acima de 1,0 como já foi sugerido. Este é o cálculo do vector impulso relativa baseado fora em massa e coeficiente de restituição.
Ignorando atrito, um exemplo 1d simples é como se segue:
J = -Vr(1+e) / {1/m1 + 1/m2}
Onde e é o seu CR, Vr é a sua velocidade normalizada e J é um valor escalar da velocidade de impulso.
Se você está pensando em fazer algo mais avançado do que isso, eu sugiro que você use uma das muitas bibliotecas física já lá fora. Quando eu usei o código acima foi bom para algumas bolas, mas quando eu ramped-lo até várias centenas começou a sufocar. Eu usei o motor de física Box2D e seu solver poderia lidar com mais bolas e é muito mais preciso.
De qualquer forma, eu olhei seu código e à primeira vista ele parece estar bom (é uma tradução bastante fiel). É provavelmente um erro pequeno e sutil de um valor errado sendo passado, ou um problema de vector de matemática.
Eu não sei nada sobre o desenvolvimento do iPhone mas gostaria de sugerir a criação de um ponto de interrupção na parte superior do que o método e monitoramento de cada etapas valor resultante e encontrar onde o blow-up é. Certifique-se de que a MTD é calculado corretamente, as velocidades de impacto, etc, etc até ver onde o grande aumento está sendo introduzido.
Relatório de volta com os valores de cada passo nesse método e vamos ver o que temos.
Outras dicas
Tendo examinado o código original e os comentários do autor, o código parece o mesmo, por isso, se o original é uma implementação correta, eu suspeitaria uma biblioteca vector ruim ou algum tipo de variável não inicializada.
Por que você está adicionando 1,0 para o coeficiente de restituição?
De: http://en.wikipedia.org/wiki/Coefficient_of_restitution
O CR é geralmente um número no intervalo [0,1]. Qualitativamente, 1 representa uma colisão perfeitamente elástica, enquanto que 0 representa uma colisão perfeitamente inelástica. A CR maior que um é teoricamente possível, representando uma colisão que gera energia cinética, como minas terrestres que estão sendo jogados juntos e explodindo.
Outro problema é o seguinte:
/ (im1 + im2)
Você está dividindo pela soma dos recíprocos das massas para obter o impulso ao longo do vetor de contato - você provavelmente deve ser dividir pela soma das próprias massas. Este está ampliando o seu impulso ( "isso é o que ela disse").
Nesta linha:
CGPoint impulse = ccpMult(mtd, i);
necessidades mtd ter sido normalizado. O erro aconteceu porque no mtd código original foi normalizado em uma linha anterior, mas não em seu código. Você pode corrigi-lo fazendo algo parecido com isto:
CGPoint impulse = ccpMult(ccpNormalize(mtd), i);