Algoritmo per sparare a un bersaglio in un gioco 3d


11

Per quelli di voi che ricordano Descent Freespace aveva una bella caratteristica che ti aiutava a mirare al nemico quando sparavi missili o laser non-homing: mostrava un mirino di fronte alla nave che hai inseguito dicendoti dove sparare per colpire il movimento bersaglio.

Ho provato a utilizzare la risposta da /programming/4107403/ai-algorithm-to-shoot-at-a-target-in-a-2d-game?lq=1 ma è per il 2D, quindi ho provato adattandolo.

Per prima cosa ho decomposto il calcolo per risolvere il punto di intersezione per il piano XoZ e salvato le coordinate x e z, quindi ho risolto il punto di intersezione per il piano XoY e ho aggiunto la coordinata y a uno xyz finale che ho poi trasformato in spazio clip e ho messo una trama in quelle coordinate. Ma ovviamente non funziona come dovrebbe altrimenti non avrei pubblicato la domanda.

Da quello che noto dopo aver trovato x nel piano XoZ e in XoY la x non è la stessa, quindi qualcosa deve essere sbagliato.

    float a = ENG_Math.sqr(targetVelocity.x) + ENG_Math.sqr(targetVelocity.y) -
            ENG_Math.sqr(projectileSpeed);
    float b = 2.0f * (targetVelocity.x * targetPos.x + 
            targetVelocity.y * targetPos.y);
    float c = ENG_Math.sqr(targetPos.x) + ENG_Math.sqr(targetPos.y);
    ENG_Math.solveQuadraticEquation(a, b, c, collisionTime);

TargetVelocity.y per la prima volta è targetVelocity.z (lo stesso per targetPos) e la seconda volta è targetVelocity.y.

La posizione finale dopo XoZ è

    crossPosition.set(minTime * finalEntityVelocity.x + finalTargetPos4D.x, 0.0f, 
                minTime * finalEntityVelocity.z + finalTargetPos4D.z);

e dopo XoY

    crossPosition.y = minTime * finalEntityVelocity.y + finalTargetPos4D.y;

Il mio approccio è quello di separare in 2 piani e calcolare qualcosa di buono? O per il 3D esiste un approccio completamente diverso?

  • sqr () è quadrato non sqrt - evitando confusione.

1
"Dirigere l'obiettivo" potrebbe essere la frase che stai cercando.
MichaelHouse

Risposte:


12

Non è necessario suddividerlo in 2 funzioni 2D. Quell'equazione quadratica con cui stai lavorando funziona bene anche in 3d. Ecco il codice pseudo per 2d o 3d. Implica che una torre (difesa della torre) sta sparando al proiettile:

Vector totarget =  target.position - tower.position;

float a = Vector.Dot(target.velocity, target.velocity) - (bullet.velocity * bullet.velocity);
float b = 2 * Vector.Dot(target.velocity, totarget);
float c = Vector.Dot(totarget, totarget);

float p = -b / (2 * a);
float q = (float)Math.Sqrt((b * b) - 4 * a * c) / (2 * a);

float t1 = p - q;
float t2 = p + q;
float t;

if (t1 > t2 && t2 > 0)
{
    t = t2;
}
else
{
    t = t1;
}

Vector aimSpot = target.position + target.velocity * t;
Vector bulletPath = aimSpot - tower.position;
float timeToImpact = bulletPath.Length() / bullet.speed;//speed must be in units per second 

'aimSpot' potrebbe essere il vettore di cui stai chiedendo.


Sei un genio e mi hai salvato il culo !! Accidenti ho bisogno di una reputazione di 15 per votare ....
Sebastian Bugiu,

@SebastianBugiu l'ho fatto per te.
AgentFire

@SebastianBugiu Grazie, sono stato contento quando ho imparato questo concetto e sono contento che ti abbia aiutato. Un'altra caratteristica elegante di questo è che non è necessario pasticciare con gli algoritmi di rilevamento delle collisioni. Non è necessario scrivere alcun codice CD. Poiché i percorsi target e proiettili sono prevedibili, l'impatto si verificherà quando il timeToImpactconto alla rovescia è pari a zero.
Steve H,

1

C'è anche un buon post sul blog sullo stesso argomento: http://playtechs.blogspot.kr/2007/04/aiming-at-moving-target.html . Contiene anche campioni più complessi che includono la gravità.

L'autore ha fatto una maggiore semplificazione, che si traduce in un codice più compatto:

double time_of_impact(double px, double py, double vx, double vy, double s)
{
    double a = s * s - (vx * vx + vy * vy);
    double b = px * vx + py * vy;
    double c = px * px + py * py;

    double d = b*b + a*c;

    double t = 0;
    if (d >= 0)
    {
        t = (b - sqrt(d)) / a;
        if (t < 0) 
        {
            t = (b + sqrt(d)) / a;
            if (t < 0)
                t = 0;
        }
    }

    return t;
}

Aggiornamento: l' autore originale ha preso in considerazione solo la radice più grande. Ma nel caso in cui la radice più piccola sia non negativa, si ottiene una soluzione migliore, poiché il tempo di impatto è minore. Ho aggiornato il codice di conseguenza.

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.