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));

}
Foi útil?

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:

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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top