Movimento inimigo em linha reta para o jogador no jogo de perseguição

10

Estou criando um jogo no qual os inimigos aparecem aleatoriamente em um mapa e depois se movem em direção ao jogador a cada quadro a uma velocidade aleatória. O mapa não tem obstáculos, portanto os inimigos devem sempre se mover em linha reta. Escrevi a função de movimento algumas vezes, mas não importa o que os inimigos sempre batam em 0, 45, 90, 135, 180, 225, 270, 315 ângulos, mas nunca em uma linha reta. Aqui está um exemplo do código:

    base_speed = random();

    diff_x = abs(enemy_y_pos - player_x_pos);
    diff_y = abs(enemy_x_pos - player_y_pos);
     if (diff_x > diff_y) {
      y_speed = base_speed;
     } else if (diff_y > diff_x) {
      x_speed = base_speed;
     }

     if (enemy_x_pos < player_x_pos) {
      velocity.x = x_speed;
     } else if (enemy_x_pos > player_x_pos) {
      velocity.x = -x_speed;
     } else {
      velocity.x = 0;
     }

     if (enemy_y_pos < player_y_pos) {
      velocity.y = y_speed;
     } else if (enemy_y_pos > player_y_pos) {
      velocity.y = -y_speed;
     } else {
            velocity.y = 0;
    }

    enemy_x_pos = enemy_x_pos + velocity.x;
    enemy_y_pos = enemy_y_pos + velocity.y;

Esta é minha primeira tentativa de programação de jogos. Eu acho que deve usar algoritmos como o da Bresenham's Line ( http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm ), mas minhas tentativas de implementar têm o mesmo problema. Como faço para que os inimigos se movam em linha reta?

user4761
fonte

Respostas:

17

O algoritmo de linha de Bresenham foi desenvolvido para desenhar linhas rapidamente sem usar operações de ponto flutuante (operações inteiras são mais rápidas). É uma solução histórica muito interessante, mas não muito boa para um jogo (principalmente porque você não pode especificar a velocidade).

Ao fazer um movimento 2D, use sempre vetores. Isso fará tudo para você. Às vezes a álgebra é simplesmente maravilhosa.

Vec2d playerPos;
Vec2d direction; // always normalized
float velocity;

update()
{
   direction = normalize(playerPos - enemyPos);
   playerPos = playerPos + direction * velocity;
}

Haverá alguma classe vector2D para o seu idioma de destino, com certeza.

Notabene
fonte
Isso funcionou perfeitamente. Normalizar era a função que eu precisava. Obrigado.
user4761
9

Você está calculando cada quadro? Seu código define x_speed ou y_speed como um número aleatório e o outro como zero (ou o padrão). Digamos que o inimigo esteja em 0, 0 e o jogador em 20, 10. Parece que ele definirá x_speed para um número aleatório a cada quadro e moverá o inimigo para a direita até que ele esteja em 10, 0. Então o inimigo se moverá x ou y cada quadro, então parece que ele se move em um ângulo de 45 graus até 10, 10.

A explicação vetorial de Notabene está certa, mas eis como funciona. O Vec2d terá um componente x e y. No exemplo acima, playerPos - enemyPos fornecerá um vetor de (20, 10). normalize () altera o vetor para que o comprimento seja 1. Atualmente, o comprimento é sqrt (20 * 20 + 10 * 10). Isso é cerca de 22.36068. normalize divide X e Y por esse número, fornecendo a você cerca de (0,89443, 0,44721) para a direção, que é um vetor apontando do inimigo para o jogador com um comprimento de 1. Multiplicar isso pela sua velocidade aleatória faz o que você deseja.

No entanto, eu não calcularia uma nova velocidade aleatória a cada quadro. Você provavelmente só deseja definir a velocidade aleatória uma vez ou ter uma velocidade inicial e uma velocidade alvo que se aproximem de cada quadro. Não faz sentido para o seu inimigo percorrer 100 mph inicialmente, depois 50 mph para um quadro e 200 mph para o próximo.

float targetSpeed = random(); // do this only rarely, or each frame if you don't mind slowing down and speeding up constantly

float acceleration = max(abs(targetSpeed - speed), 0.5) * sgn(targetSpeed - speed); // cap accel/decel at 0.5 per frame
speed = speed + acceleration;
Jason Goemaat
fonte
Boas explicações e adições Jason, obrigado. Eu gosto da sua função de aceleração
Notabene
random () nesse escopo foi um erro de digitação. Sua explicação e código com o que notabene escreveu me ajudam a fazer o jogo funcionar. Obrigado.
user4761