Стрельба по танку

Данная практическая реализует мини-игру стрельбы по танку, движущемуся по криволинейной траектории.
Траектория танка генерируется при помощи $\beta$-сплайна, который строится по четырём случайным точкам.

Описание алгоритма построения траектории:
На начальном этапе генерируется 4 случайных точки экрана - $(x_0, y_0), (x_1, y_1), (x_2, y_2), (x_3, y_3)$. По ним строится $\beta$-сплайн. В момент, когда объект доходит до точки $(x_3, y_3)$, сплайн перестраивается следующим образом:

  1. Генерируется новая точка $(x_4, y_4);$
  2. Ключевые точки сплайна меняются на $(x_1, y_1), (x_2, y_2), (x_3, y_3), (x_4, y_4)$ (нулевая точка удаляется из начала, а вместо неё в конец добавляется новая точка);
  3. Сплайн перестраивается по новым точкам и объект оказывается в начале нового сплайна;

Описание алгоритма движения:
Движение объекта выполняется матрицами перемещения - $T(\Delta x, \Delta y)$ - и поворота - $R(\theta)$.
Перемещение точки на вектор $[\Delta x, \Delta y]^T$ вычисляется по следующей формуле:
$$
\begin{bmatrix}
x' \\
y' \\
1
\end{bmatrix}
=
T(\Delta x, \Delta y) \vec{x} =
\begin{bmatrix}
1 & 0 & \Delta x \\
0 & 1 & \Delta y \\
0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
1
\end{bmatrix}
$$
Поворот точки $(x, y)$ вокруг точки $(x_p, y_p)$ на угол $\theta$ вычисляется по формуле:
$$
\begin{bmatrix}
x' \\
y' \\
1
\end{bmatrix}
=
T(x_p, y_p)R(\theta)T(-x_p, -y_p) \vec{x} =
\begin{bmatrix}
1 & 0 & x_p \\
0 & 1 & y_p \\
0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
\cos\theta & -\sin\theta & 0 \\
\sin\theta & \cos\theta & 0 \\
0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
1 & 0 & -x_p \\
0 & 1 & -y_p \\
0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
1
\end{bmatrix}
$$
Для трансформации всего объекта, трансформация применяется к каждой его точке по отдельности.

Для анимации движения, строится линейное приближение сплайна: высчитываются точки сплайна при значениях параметра $t_i = \frac{i}{n}, i=\overline{0,n}$, где $n$ (точность приближения) задаётся произвольно.
Объект двигается линейно от $i$-ой до $(i+1)$-ой точки, каждый кадр перемещая объект на вектор $\Delta \vec{x} = s \vec{v_i}$, где $\vec{v_i}$ - вектор, соединяющий $i$-ую и $(i+1)$-ую точки, $s$ - скорость движения объекта.
Достигая $(i+1)$-ой точки, объект поворачивается на угол $\theta$, который равен углу между векторами $\vec{v_i}$ и $\vec{v_{i+1}}$, где $\vec{v_i}$ - вектор, соединяющий $i$-ую и $(i+1)$-ую точки, $\vec{v_{i+1}}$ - вектор, соединяющий $(i+1)$-ую и $(i+2)$-ую точки.
Угол $\theta$ вычисляется по следующей формуле:
$$
\theta = sign(\vec{v_i} \times \vec{v_{i+1}})\arccos(\vec{v_i} \cdot \vec{v_{i+1}})
$$
где $sign(x)$ - функция, равная $1$, при $x > 0$, равная $0$ при $x = 0$ и $-1$ иначе. $\vec{v_i} \times \vec{v_{i+1}}$ - векторное произведение, $\vec{v_i} \cdot \vec{v_{i+1}}$ - скалярное произведение векторов.

Описание алгоритма детекции выстрела:
Объект представлен в виде набора кругов и выпуклых многоугольников. Выстрел в точку $(x, y)$ экрана является попаданием по объекту тогда и только тогда, когда точка $(x, y)$ лежит внутри хотя бы одного из этих кругов или многоугольников.

Принадлежность точки $(x, y)$ кругу с центром в $(x_0, y_0)$ и радусом $R$ проверяется условием:
$$
(x - x_0)^2 + (y - y_0)^2 \leq R^2
$$
Принадлежность точки $(x, y)$ выпуклому многоугольнику с вершинами $(x_0, y_0), (x_1, y_1), ... (x_n, y_n)$ проверяется следующим алгоритмом:
Пусть $\vec{a_i}$ - вектор, соединяющий точку $(x, y)$ с точкой ${(x_i, y_i)}$.
Вычислим значения $p_i = \vec{a_i} \times \vec{a_{i+1}}, i = \overline{0,n}$, где в качестве $\vec{a_{n+1}}$ будем брать $\vec{a_0}$.
Точка $(x, y)$ лежит внутри заданного выпуклого многоугольника, если все ненулевые $p_i$ имеют одинаковый знак.