Алгоритм стріляти по мішені в 3d-грі


11

Для тих, хто пам'ятає Descen Freespace, він мав приємну функцію, щоб допомогти вам націлитись на противника під час стрільби ракетами чи лазерами, які не навіюються: він показав перехрестя перед кораблем, за яким ви гналися, повідомляючи, куди стріляти, щоб потрапити на рух цільовий.

Я спробував використати відповідь з /programming/4107403/ai-algorithm-to-shoot-at-a-target-in-a-2d-game?lq=1, але це для 2D, тому я спробував адаптуючи його.

Спочатку я розклав обчислення, щоб вирішити точку перетину для площини XoZ, і зберег координати x і z, а потім вирішив точку перетину для площини XoY і додав координату y до кінцевого xyz, який потім перетворив у кліпспространство і поставив текстуру на ті координати. Але, звичайно, це не працює як слід, інакше я б не розміщував питання.

З того, що я помічаю після знаходження x у площині XoZ, а в XoY, x не є тим самим, тому щось повинно бути не так.

    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 - це фактично targetVelocity.z (те саме для targetPos), а другий раз - це фактично targetVelocity.y.

Кінцева позиція після XoZ - це

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

і після XoY

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

Чи є мій підхід до поділу на 2 площини та обчислення будь-якого блага? Або для 3D існує зовсім інший підхід?

  • sqr () - це квадрат не sqrt - уникаючи плутанини.

1
"Провідна ціль" може бути фразою, яку ви шукаєте.
MichaelHouse

Відповіді:


12

Немає необхідності розбивати його на 2 2d функції. Це квадратичне рівняння, з яким ви працюєте, чудово працює і в 3d. Ось псевдокод для 2d або 3d. Це означає, що вежа (оборона вежі) стріляє снарядом:

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' може бути вектором, про який ви запитуєте.


Ти геній і врятував мою попу !! Блін, мені потрібно 15 репутації, щоб підняти ....
Себастьян Бугіу

@SebastianBugiu я зробив це для вас.
AgentFire

@SebastianBugiu Спасибі, я був радий, коли дізнався цю концепцію і радий, що вона допомогла тобі. Ще одна елегантна його особливість полягає в тому, що вам не потрібно возитися з алгоритмами виявлення зіткнень. Код CD не потрібно писати. Оскільки шляхи цілі та снаряда передбачувані, вплив буде виникати при timeToImpactвідліку до нуля.
Стів H

1

Також є хороша публікація в блозі з тієї ж теми: http://playtechs.blogspot.kr/2007/04/aiming-at-moving-target.html . Він також містить більш складні зразки, які включають гравітацію.

Автор зробив більше спрощення, що призводить до отримання більш компактного коду:

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

Оновлення: Оригінальний автор врахував лише більший корінь. Але якщо менший корінь є негативним, це призводить до кращого вирішення, оскільки час впливу менший. Я відповідно оновив код.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.