Movimento nemico in linea retta verso il giocatore nel gioco di inseguimento


10

Sto creando un gioco in cui i nemici si generano casualmente su una mappa per poi spostarsi verso il giocatore ogni fotogramma a una velocità casuale. La mappa non ha ostacoli, quindi i nemici devono sempre muoversi in linea retta. Ho scritto la funzione di movimento un paio di volte, ma indipendentemente da ciò che i nemici colpivano sempre 0, 45, 90, 135, 180, 225, 270, 315 angoli ma mai una linea retta. Ecco un esempio del codice:

    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;

Questo è il mio primo tentativo di programmazione del gioco. Immagino che dovrebbe usare un algoritmo come Bresenham's Line ( http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm ) ma i miei tentativi di implementazione hanno lo stesso problema. Come faccio a far muovere i nemici in linea retta?

Risposte:


17

L'algoritmo di linea di Bresenham è stato sviluppato per linee di disegno veloci senza utilizzare operazioni in virgola mobile (le operazioni di numero intero sono più veloci). È storicamente molto interessante ma non un'ottima soluzione per un gioco (soprattutto perché non è possibile specificare la velocità).

Quando fai un movimento 2D usa sempre i vettori. Questo farà tutto per te. A volte l'algebra è semplicemente meravigliosa.

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

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

Ci sarà sicuramente una classe vector2D per la tua lingua di destinazione.


Funzionava perfettamente. Normalizzare era la funzione di cui avevo bisogno. Grazie.
user4761

9

Stai calcolando ogni frame? Il codice imposta x_speed o y_speed su un numero casuale e l'altro su zero (o il valore predefinito). Diciamo che il nemico è a 0, 0 e il giocatore è a 20, 10. Questo sembra che imposterà x_speed su un numero casuale ogni frame e sposterà il nemico a destra fino a quando non sarà a 10, 0. Quindi il nemico si sposterà x o y per ogni fotogramma, quindi sembrerà che si muova con un angolo di 45 gradi fino a 10, 10.

La spiegazione vettoriale di Notabene è corretta ma ecco come funziona. Vec2d avrà un componente xey. Nell'esempio sopra, playerPos - nemiciPos ti darà un vettore di (20, 10). normalize () cambia il vettore in modo che la lunghezza sia 1. Attualmente la lunghezza è sqrt (20 * 20 + 10 * 10). Sono circa 22.36068. normalize divide sia X che Y per questo numero, dandoti circa (0,89443, 0,44721) per la direzione, che è un vettore che punta dal nemico al giocatore per una lunghezza di 1. Moltiplicandolo per la tua velocità casuale fa quello che vuoi.

Tuttavia, non calcolerei una nuova velocità casuale per ogni fotogramma. Probabilmente vuoi semplicemente impostare la velocità casuale una volta o avere una velocità iniziale e una velocità target che ti avvicini a ciascun fotogramma. Non ha senso che il nemico vada inizialmente a 100 mph, quindi a 50 mph per un fotogramma e 200 mph per il successivo.

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;

Belle spiegazioni e aggiunte Jason, grazie. Mi piace la tua funzione di accelerazione
Notabene,

random () in quell'ambito era un refuso. La tua spiegazione e il codice con ciò che Notabene ha scritto mi aiutano a far funzionare il gioco. Grazie.
user4761
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.