0

私はビリヤード ボール同士が衝突したときの単純な挙動に取り組んでいます。すべて正常に動作しますが、いくつかの簡単なボールに直面すると、カップリング ボールの効果があり、それらが互いにクールであるという問題がありました。これを防ぐ方法を教えてください。

bool MGBilliard::CollisingBall(CCPoint curr_point, CCPoint next_point)
{
    float dx = next_point.x - (curr_point.x + dvdt.x);
    float dy = next_point.y - (curr_point.y - dvdt.y);
    float d = dx*dx+dy*dy;
    return d <= BALL_RADIUS * BALL_RADIUS;
}
double MGBilliard::angleCollisionBalls(Ball* current, Ball* next)
{
    double na;
    double dx = fabs(next->location.x - current->location.x);
    double dy = fabs(next->location.y - current->location.y);
    na = atan(fabs(dy/dx));
    if(atan(fabs(current->location.y/current->location.x)) < atan(fabs(next->location.y/next->location.x)))
        na = current->angle - na;
    else if(atan(fabs(current->location.y/current->location.x)) > atan(fabs(next->location.y/next->location.x)))
        na = current->angle + na;
    return na;
}
for(unsigned int i = 0;i<BALL_COUNT;++i)
    {
        if(vBalls[i]->speed > 0){
            vBalls[i]->speed += vBalls[i]->acceleration;
            float dsdt = vBalls[i]->speed*dt;
            dvdt.x = dsdt*cos(vBalls[i]->angle);
            dvdt.y = dsdt*sin(vBalls[i]->angle);
            vBalls[i]->location.x += dvdt.x;
            vBalls[i]->location.y += dvdt.y;
            for(unsigned int j = 1; j < BALL_COUNT; ++j)
            {
                if(i == j) continue;
                if(CollisingBall(vBalls[i]->spriteBall->getPosition(),vBalls[j]->spriteBall->getPosition()))
                {
                    vBalls[j]->speed = 600;
                    double angle;
                    angle = angleCollisionBalls(vBalls[i],vBalls[j]);
                    vBalls[i]->angle = (float)-angle;
                    vBalls[j]->angle = (float)angle;
                }
            }
        }
    }
4

1 に答える 1

6

あなたのコードをざっと見て、私の注意を引く 2 つの単純なバグがあります。

まず、これ:

vBalls[i]->angle = (float)-angle; 
vBalls[j]->angle = (float)angle; 

対角を計算する正しい方法ではありません。angleたとえば、がゼロ (さらに言えば 180 度) の場合、実行したいことは実行されません。

vBalls次に、配列全体を複数回繰り返し処理します。1回は indexiで、内側のループは index で行いますj。これは、衝突が 2 回計算され、speed両方のボールの が 600 に設定されることを意味します! 内部ループを次のように変更します。

for(unsigned int j = i + 1; j < BALL_COUNT; ++j)

これを防ぐ必要があります。

さらに微妙なバグもあります。衝突検出では時間が考慮されません。各ボールは、ゲーム ループの反復ごとに特定の距離を移動します。これは、衝突が 1 つの「ティック」で発生しない場合、ボールが別のボールをまっすぐ通過し、ボールの向こう側で衝突コードをトリガーする可能性があることを意味します。この状況では単純な半径ベースの衝突テストを行うことはできません。ボールが 1 ステップで (BALL_RADIUS * BALL_RADIUS) を超えて移動すると、システムが異常な動作をしたり、まったく機能しなくなったりするからです。

個人的には、角度や速度ではなくベクトルを使用して各ボールの速度と方向を記述しますが、これを行うためにコードをリファクタリングすることは、この質問の範囲外です。

于 2012-09-07T09:53:33.860 に答える