Ein ausgefeilterer Ball-Paddel-Kollisionsalgorithmus für Breakout?

7

Ich habe ein einfaches Breakout-Spiel, an dem ich arbeite. Der Kollisionscode ist solide. Dinge hüpfen wie sie sollten und gehen nicht durch Dinge oder machen andere Funky, aber die Reflexion ist ein bisschen simpel. Infolgedessen ist es leicht, in einen Zustand zu gelangen, in dem der Ball in einer Schleife stecken bleibt, so dass die letzten Blöcke nicht getroffen werden können, ohne zu sterben, um die Schleife zu brechen.

Derzeit spiegelt der Paddelkollisionscode die Y-Geschwindigkeit wider und spiegelt die X-Geschwindigkeit wider, je nachdem, auf welche Seite des Paddels es trifft:

        // Check for paddle collisions
        if ((m_ball.rect()).intersects(m_paddle.rect())) {
            double ballCenter = m_ball.rect().getX() + (m_ball.rect().getWidth()/2);
            double paddleCenter = m_paddle.rect().getX() + (m_paddle.rect().getWidth()/2);

            m_ball.setSpeedY(m_ball.speedY() * -1);

            if (ballCenter > paddleCenter) {
                m_ball.setSpeedX(Math.abs(m_ball.speedX()));
            } else {
                m_ball.setSpeedX(-Math.abs(m_ball.speedX()));
            }
        }

Gibt es eine Möglichkeit, den Algorithmus "interessanter" zu machen und die Kontrolle zu verschärfen, damit der Ball nicht auf dem gleichen Feld hängen bleibt?


quelle

Antworten:

12

Verwenden Sie eine Schiebeskala, um die X-Geschwindigkeit abhängig von der Position auf dem Paddel zu ändern.

Stellen Sie eine Konstante für eine maximale X-Geschwindigkeitsänderung ein. Wenn der Ball ganz rechts auf das Paddel trifft, addieren Sie diese Konstante zur X-Geschwindigkeit. Wenn es ganz links auf das Paddel trifft, subtrahieren Sie diese Konstante von der X-Geschwindigkeit. Wenn es genau in der Mitte des Paddels trifft, hat dies keinen Einfluss auf die X-Geschwindigkeit.

Verwenden Sie irgendwo dazwischen eine gleitende Skala, um den Betrag zu bestimmen, der zur X-Geschwindigkeit addiert oder subtrahiert werden soll.

Erick Robertson
quelle
4

Viele Breakout-Spiele werden "Spin" einführen. Wenn sich das Paddel bewegt, beeinflusst es die X-Richtung des Balls in der Richtung, in die sich das Paddel bewegt.

Henryville
quelle
2

Jonathan,

Ich würde tun, was Erick vorschlägt, aber ich würde darauf achten, dass die X- und Y-Geschwindigkeitskomponenten ineinander greifen, da sich sonst die Gesamtgeschwindigkeit des Balls einfach aufgrund einer Kollision mit dem Paddel ändert, was eine unrealistische Physik ist.

Also würde ich zuerst die Gesamtgeschwindigkeit des Balls aus .speedX()und .speedY()(unter Verwendung des Satzes von Pythagoras) berechnen, dann die neue X-Geschwindigkeit aus der Position des Balls relativ zum Paddel berechnen und dann die Y-Geschwindigkeit abhängig von einer Funktion der neuen X-Geschwindigkeit einstellen und die ursprüngliche Gesamtgeschwindigkeit, so dass der Ball einfach die Richtung ändert (in einer unendlichen Anzahl möglicher Winkel), aber immer die gleiche Gesamtgeschwindigkeit beibehält.

Um das konkreter auszudrücken, würde ich es so machen:

if ((m_ball.rect()).intersects(m_paddle.rect())) {
    double ballWidth = m_ball.rect().getWidth();
    double ballCenterX = m_ball.rect().getX() + ballWidth/2;
    double paddleWidth = m_paddle.rect().getWidth();
    double paddleCenterX = m_paddle.rect().getX() + paddleWidth/2;
    double speedX = m_ball.speedX();
    double speedY = m_ball.speedY();

    // Applying the Pythagorean theorem, calculate the ball's overall
    // speed from its X and Y components.  This will always be a
    // positive value.
    double speedXY = Math.sqrt(speedX*speedX + speedY*speedY);

    // Calculate the position of the ball relative to the center of
    // the paddle, and express this as a number between -1 and +1.
    // (Note: collisions at the ends of the paddle may exceed this
    // range, but that is fine.)
    double posX = (ballCenterX - paddleCenterX) / (paddleWidth/2);

    // Define an empirical value (tweak as needed) for controlling
    // the amount of influence the ball's position against the paddle
    // has on the X speed.  This number must be between 0 and 1.
    final double influenceX = 0.75;

    // Let the new X speed be proportional to the ball position on
    // the paddle.  Also make it relative to the original speed and
    // limit it by the influence factor defined above.
    speedX = speedXY * posX * influenceX;
    m_ball.setSpeedX(speedX);

    // Finally, based on the new X speed, calculate the new Y speed
    // such that the new overall speed is the same as the old.  This
    // is another application of the Pythagorean theorem.  The new
    // Y speed will always be nonzero as long as the X speed is less
    // than the original overall speed.
    speedY = Math.sqrt(speedXY*speedXY - speedX*speedX) *
             (speedY > 0? -1 : 1);
    m_ball.setSpeedY(speedY);
}

Hinweis: Rundungsfehler führen im Laufe der Zeit dazu, dass die Gesamtgeschwindigkeit langsam von ihrem ursprünglichen Wert abweicht. Die gewünschte Gesamtgeschwindigkeit möchten Sie möglicherweise als Mitgliedsdaten hinzufügen m_ball(anstatt sie hier jedes Mal zu berechnen), oder Sie möchten zulassen, dass sie gemäß anderen Spielfaktoren beschleunigt und verlangsamt werden.

Todd Lehman
quelle
1
Es ist eine übliche Spielmechanik, den Ball langsam zu beschleunigen, bis jemand verliert. Sonst könntest du für immer spielen.
Erick Robertson
Das ist ein guter Punkt!
Todd Lehman