Тело как объект состояния и попадание в цель

Прямая задача — куда упадёт снаряд; обратная — с какой скоростью бросить, чтобы попасть. Обе решает симуляция.

Обратная задача баллистики — нахождение параметров запуска (скорости, угла) по требуемой точке попадания.

Тело как структура данных

До сих пор мы держали $x, y, v_x, v_y$ отдельными переменными. В настоящем движке тело — это структура (словарь, объект или кортеж) с этими полями, а шаг симуляции — функция, принимающая тело и возвращающая обновлённое. Такой подход масштабируется на тысячи объектов: список тел, и в цикле каждое продвигается на шаг. Заодно код становится читаемее: «состояние» и «правило перехода» чётко разделены.

Прямая задача в виде функции

Соберём симуляцию полёта в функцию, которая по начальной скорости и углу возвращает дальность. Тело храним в словаре.

import math
def simulate(v0, ang_deg, dt=0.001):
    ang = math.radians(ang_deg)
    body = {"x": 0.0, "y": 0.0,
            "vx": v0*math.cos(ang), "vy": v0*math.sin(ang)}
    g = 9.8
    while True:
        body["vy"] -= g*dt
        xn = body["x"] + body["vx"]*dt
        yn = body["y"] + body["vy"]*dt
        if yn < 0:
            frac = body["y"] / (body["y"] - yn)
            return body["x"] + frac*(xn - body["x"])
        body["x"], body["y"] = xn, yn

print(f"Дальность при v0=22, 45°: {simulate(22, 45):.2f} м")

Вывод:

Дальность при v0=22, 45°: 49.37 м

Обратная задача: попасть в цель

Теперь зададимся вопросом: какую скорость нужно сообщить снаряду, чтобы при угле $45°$ попасть в цель на расстоянии $50$ м? Для случая без сопротивления есть аналитическое решение из формулы дальности: $v_0 = \sqrt{\frac{R\,g}{\sin 2\alpha}}$. Найдём её и сразу проверим прямой симуляцией.

import math
def simulate(v0, ang_deg, dt=0.001):
    ang = math.radians(ang_deg)
    x = y = 0.0
    vx = v0*math.cos(ang); vy = v0*math.sin(ang)
    g = 9.8
    while True:
        vy -= g*dt
        xn = x + vx*dt; yn = y + vy*dt
        if yn < 0:
            frac = y/(y - yn)
            return x + frac*(xn - x)
        x, y = xn, yn

target, ang, g = 50.0, 45, 9.8
v0 = math.sqrt(target*g / math.sin(2*math.radians(ang)))
print(f"Цель на {target} м, угол {ang}°")
print(f"Нужная скорость v0 = {v0:.3f} м/с")
print(f"Симуляция упала на {simulate(v0, ang):.2f} м")

Вывод:

Цель на 50.0 м, угол 45°
Нужная скорость v0 = 22.136 м/с
Симуляция упала на 49.98 м

Аналитика и симуляция совпали: подобранная скорость $22.136$ м/с приводит снаряд почти ровно в цель ($49.98$ м, расхождение — артефакт дискретного шага). Так устроено прицеливание в играх с честной баллистикой и системы наведения.

Как работает под капотом

Если добавить сопротивление, аналитической формулы для $v_0$ уже нет, и обратную задачу решают численным поиском: симулируют при нескольких скоростях и ищут ту, при которой дальность равна целевой. Поскольку дальность монотонно растёт со скоростью, отлично работает двоичный поиск (бисекция): берём нижнюю и верхнюю границы скорости и сужаем интервал вдвое, пока не попадём в цель с нужной точностью. Это тот же приём, что для решения уравнений: симуляция играет роль функции, корень которой мы ищем. По такому принципу ИИ-противник в шутере подбирает упреждение и силу броска.

Частые ошибки

  • Решать обратную задачу формулой при сопротивлении. С трением нужен численный поиск (бисекция), формула $v_0=\sqrt{Rg/\sin2\alpha}$ не работает.
  • Менять состояние тела частично. Если обновить $v_y$, но забыть применить его к $y$ в том же шаге, симуляция рассинхронизируется.
  • Слишком грубый шаг при поиске. При обратной задаче ошибка дискретизации складывается с ошибкой поиска — берите $\Delta t$ поменьше.

Итог

  • Тело удобно представлять структурой состояния, а шаг — функцией над ней.
  • Прямая задача: по запуску найти точку падения (симуляция).
  • Обратная задача без трения решается формулой $v_0=\sqrt{Rg/\sin2\alpha}$.
  • С трением обратную задачу решает численный поиск (бисекция по скорости).
Проверьте себя
1. Что такое обратная задача баллистики?
AНайти точку падения по запуску
BНайти параметры запуска (скорость/угол) по нужной точке попадания
CНайти массу снаряда
DНайти ускорение свободного падения
2. Как решают обратную задачу при наличии сопротивления воздуха?
AПо формуле v0=√(Rg/sin2α)
BЧисленным поиском: бисекцией по скорости, используя симуляцию как функцию
CНикак, она неразрешима
DУвеличивая угол до 90°
3. Почему удобно представлять тело структурой состояния?
AТак быстрее считает Pyodide
BСостояние и правило перехода разделяются, код масштабируется на тысячи тел
CЭто требование KaTeX
DЧтобы не использовать математику