Um algoritmo de colisão bola-pá mais sofisticado para o Breakout?

7

Eu tenho um jogo de fuga simples no qual estou trabalhando. O código de colisão é sólido; as coisas ricocheteiam como deveriam e não passam por outras coisas ou causam estranheza, mas o reflexo é um pouco simplista. Como resultado, é fácil entrar em um estado em que a bola fique presa em um loop, de modo que os últimos blocos não possam ser atingidos sem morrer para quebrar o loop.

Atualmente, o código de colisão do remo reflete a velocidade Y e reflete a velocidade X, dependendo do lado do remo que ele atinge:

        // 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()));
            }
        }

Existe alguma maneira de eu tornar o algoritmo mais "interessante" e apertar o controle para que a bola não fique presa saltando no mesmo quadrado?


fonte

Respostas:

12

Use uma escala móvel para modificar a velocidade X, dependendo da localização na raquete.

Defina algum tipo de constante para uma alteração máxima da velocidade X. Se a bola bater no lado direito da raquete, adicione essa constante à velocidade X. Se atingir o lado esquerdo da raquete, subtraia essa constante da velocidade X. Se atingir o meio da raquete, não afete a velocidade X.

Em qualquer lugar, use uma escala móvel para determinar a quantidade a ser adicionada ou subtraída à velocidade X.

Erick Robertson
fonte
4

Muitos jogos de abertura introduzirão "spin". Se a raquete estiver em movimento, ela influenciará a direção X da bola na direção em que a raquete está se movendo.

Heneryville
fonte
2

Jonathan,

Eu faria o que Erick sugere, mas tomaria cuidado para garantir que os componentes de velocidade X e Y permaneçam interligados; caso contrário, a velocidade geral da bola mudará simplesmente de uma colisão com a raquete, que é uma física irrealista.

Então, eu primeiro calculava a velocidade geral da bola de .speedX()e .speedY()(usando o teorema de Pitágoras), depois calculava a nova velocidade X a partir da posição da bola em relação à raquete, e então definia a velocidade Y dependente de uma função da nova velocidade X e a velocidade total original, de modo que a bola simplesmente mude de direção (em um número infinito de ângulos possíveis), mas sempre mantenha a mesma velocidade geral.

Para colocar isso de maneira mais concreta, eu faria assim:

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

Nota: Com o passar do tempo, os erros de arredondamento farão com que a velocidade geral se desvie lentamente do valor original. A velocidade geral desejada pode ser algo que você deseja adicionar como dados de membro m_ball(em vez de calculá-lo sempre aqui), ou pode ser algo que você deseja permitir que acelere e desacelere de acordo com outros fatores de jogo.

Todd Lehman
fonte
11
É uma mecânica de jogo comum acelerar a bola lentamente até que alguém perca. Caso contrário, você pode jogar para sempre.
Erick Robertson
Este é um bom ponto!
21415 Todd Lehman