Algoritma untuk menembak target di game 3d

11

Bagi Anda yang ingat Descent Freespace, ia memiliki fitur yang bagus untuk membantu Anda membidik musuh ketika menembakkan rudal atau laser non-homing: itu menunjukkan crosshair di depan kapal yang Anda kejar memberi tahu Anda di mana harus menembak untuk memukul di mana bergerak target.

Saya mencoba menggunakan jawaban dari /programming/4107403/ai-algorithm-to-shoot-at-a-target-in-a-2d-game?lq=1 tetapi untuk 2D jadi saya mencoba mengadaptasinya.

Saya pertama kali mendekomposisikan perhitungan untuk menyelesaikan titik persimpangan untuk bidang XoZ dan menyimpan koordinat x dan z dan kemudian memecahkan titik persimpangan untuk bidang XoY dan menambahkan koordinat y ke xyz akhir yang kemudian saya ubah ke ruang klip dan menaruh tekstur pada gambar tersebut koordinat. Tapi tentu saja itu tidak berfungsi sebagaimana mestinya atau saya tidak akan memposting pertanyaan.

Dari apa yang saya perhatikan setelah menemukan x di bidang XoZ dan di XoY, x tidak sama sehingga ada sesuatu yang salah.

    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 pertama kali sebenarnya adalah targetVelocity.z (sama untuk targetPos) dan kedua kalinya itu sebenarnya targetVelocity.y.

Posisi akhir setelah XoZ adalah

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

dan setelah XoY

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

Apakah pendekatan saya memisahkan menjadi 2 pesawat dan menghitung manfaat? Atau untuk 3D ada pendekatan yang berbeda?

  • sqr () adalah persegi bukan sqrt - menghindari kebingungan.
Sebastian Bugiu
sumber
1
"Memimpin target" mungkin kalimat yang Anda cari.
MichaelHouse

Jawaban:

12

Tidak perlu memecahnya menjadi fungsi 2 2d. Persamaan kuadrat yang bekerja dengan Anda berfungsi dengan baik di 3d juga. Berikut adalah kode semu untuk 2d atau 3d. Ini menyiratkan sebuah menara (menara pertahanan) menembakkan proyektil:

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' mungkin merupakan vektor yang Anda tanyakan.

Steve H.
sumber
Kau jenius dan menyelamatkanku !! Sial, aku butuh reputasi 15 untuk
mendukung
@SebastianBugiu saya melakukannya untuk Anda.
AgentFire
@SebastianBugiu Terima kasih, saya senang ketika saya mempelajari konsep ini dan senang itu membantu Anda. Fitur elegan lainnya adalah Anda tidak perlu dipusingkan dengan algoritma pendeteksian benturan. Tidak perlu menulis kode CD. Karena jalur target dan proyektil dapat diprediksi, dampaknya AKAN terjadi ketika timeToImpactmenghitung mundur ke nol.
Steve H
1

Ada juga posting blog yang bagus tentang topik yang sama: http://playtechs.blogspot.kr/2007/04/aiming-at-moving-target.html . Ini juga mengandung sampel yang lebih kompleks yang mencakup gravitasi.

Penulis telah melakukan lebih banyak penyederhanaan, yang menghasilkan kode yang lebih ringkas:

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

Pembaruan: Penulis asli hanya memperhitungkan root yang lebih besar. Tetapi jika root yang lebih kecil non-negatif, itu menghasilkan solusi yang lebih baik, karena waktu dampaknya lebih kecil. Saya telah memperbarui kode yang sesuai.

Roman Hwang
sumber