D:\sideБлогМатематика GameMaker - введение

Совсем недавно я разбирал парочку занятных вопросов о том, как в GM применяется математика. И столкнулся с занятной проблемой - в том возрасте, когда школьники (без всякого подтекста - просто учащиеся) начинают увлекаться GameMaker, они часто сталкиваются с областями математики, в которую школа их ещё не посвятила. Самообразование - конечно, хорошо, но ему необходимо дать некое направление.

Этот пост внезапно задерживает ближайший урок по языковым конструкциям, потому что язык бесполезен без понимания того, какими данными можно управлять с помощью него. Речь пойдёт, преимущественно, о координатах. А значит, будет некий базовый материал о векторах и немного физики о том, как с их помощью моделировать движение. Зачем всё это надо? Потому что именно таким образом движение смоделировано в GameMaker. И если вы хотите знать, как разместить каждый ваш объект в точности там, где надо, и заставить двигаться, куда надо (при условии, что вы сами этого ещё не знаете) - то вам сюда.

Предварительные требования - выполнение первых двух моих уроков по GML (вот первый, вот второй), а также понимание того, как в школе изучается геометрия.

Принципиальных подходов к геометрии я за свою жизнь повидал два. Условно я их называю «классический» и «аналитический».

Классический - это то, с чего в школах начинают изучать геометрию: что такое точка, прямая, отрезок, треугольник, многоугольник, окружность, круг, разные свойства, виды взаимного расположения; доказательство теорем и решение задач при помощи их применения.

Аналитический - это представление почти всех геометрических понятий и фактов с помощью уравнений и выражений, преобразованиями которых можно многого добиться.

Предполагается, что с азами классического подхода вы уже знакомы, потому что рассказывать я о нём не буду. Почитайте любой учебник по геометрии, если вам так интересно. Я мало встречал учебников, которые могут непонятно объяснять школьную геометрию. Но когда в 10 классе нас начали учить аналитической геометрии, я освоился, проникся и теперь пытаюсь использовать её почаще.

В чём мы работаем

В «классическом» подходе мы, как правило, используем некое непонятное пространство, которое может содержать геометрические фигуры. Оно может быть плоским (плоское пространство - может звучать, как нонсенс), может быть объёмным. Об этом пространстве мы знаем сравнительно немного. Недостаточно, чтобы смоделировать его в компьютерной программе - нам многое придётся придумывать из ниоткуда.

В аналитической геометрии всё чуть веселее и понятнее. Там мы работаем в некотором «линейном пространстве» (ещё называют «векторным»), элементами которого является то, что мы «в классическим подходе» называем точками. Каждая комната GameMaker - это некое линейное пространство, и любая точка этого пространства - его элемент. У него есть свойства, но пока мы не договоримся, как различать разные элементы пространства, далеко мы не уедем.

Чтобы не блуждать бесцельно и без ориентиров по нашему линейному пространству, придумали системы координат. Это некий элемент линейного пространства, который мы называем нулём, а также набор осей. Поскольку говорить мы собираемся о плоскости, таких осей у нас будет две. Чтобы завести подобную штуку, скажем, у вас в комнате, вам понадобится уже три оси. Ось - это всего лишь известное направление и единица измерения расстояния на ней. Мы здесь будем говорить о комнатах в GameMaker, поэтому сразу «привяжу вас» к тому, что ноль в комнате - это её левый верхний угол, а оси - это направления «вправо» и «вниз», измеряемые в пикселях.

Вектор

В школах, для простоты понимания, дают определение вектору, как «направленный отрезок». Раскопаем это определение чуть глубже. Отрезок можно однозначно определить при помощи двух точек - другой отрезок на этих же двух точках невозможен. А его направленность означает только то, что мы можем однозначно сказать об этих двух точках, какая из них первая (начало), а какая вторая (конец).

В некотором смысле, вектором называется лишь то, что находится между двумя точками. Вектор не находится в некотором конкретном месте пространства - это нечто, имеющее известную длину и направление, и всё. Чтобы не париться с тем, что он нигде не находится, считают, что любой вектор можно представить, как находящийся первой точкой в нуле. Вторая точка, в этом случае, однозначно определяет вектор. Что это за точка? Неизвестно, она может быть совершенно любой точкой пространства. Известно то, что если два вектора таким образом попадают в одну и ту же точку - то это (оказывается!) один и тот же вектор. Вторая точка может даже совпадать с первой. В этом случае при размещении первой в нуле, вторая тоже окажется в нуле. Для такого вектора отведено особое понятие «нулевой вектор», «векторный ноль» или просто «ноль» (стоит обратить внимание, что это не число \(0\), а вот такой \(\vec{0}\)). И раз уж я заговорил об обозначениях - векторы в математике обозначают разнообразными буквами со стрелочкой наверху. Вот так: \(\vec{a}\), \(\vec{b}\), \(\vec{\omega}\) (в общем-то, неважно, из какого алфавита буква, эта из греческого).

Операции

Сначала научимся складывать векторы. Мы умеем (условно) двигать векторы, не изменяя их (даже не поворачивая - направление также является его характеристикой). Используя это, опишем сложение следующим образом: возьмём один вектор, разместим его первой точкой в нуле. Возьмём второй вектор, и разместим его первой точкой во второй точке первого вектора - тогда его вторая точка попадёт в некую другую точку пространства. Вот вектор, её представляющий, называется суммой наших двух векторов. Нарисовать это можно двумя способами, оба они изображены на картинке рядышком.

Плюс для векторов по свойствам не сильно отличается от своего собрата для чисел. У него следующие свойства:

Теперь минус. Тут всего пара слов. У любого вектора есть обратный ему вектор. Определяется очень легко: при сложении со своим обратным любой вектор даст ноль. И это не «особенность», а определение — мы утверждаем, что это за объект и как его получить.

\(\vec{a}+(-\vec{a})=\vec{0}\)

Поразмыслив над правилом суммирования, несложно догадаться, что получить его можно из любого вектора, просто взяв представляющие его точки в обратном порядке.

Имея это в виду, определим вычитание векторов следующим образом:

\(\vec{a}-\vec{b}=\vec{a}+(-\vec{b})\)

Графически - мы уводим первый вектор началом (первой точкой) в ноль, затем сдвигаем второй вектор, чтобы концы (вторые точки) обоих векторов совпали. Тогда вектор разности (результат вычитания) будет представлен началом в нуле, а концом - в начале второго вектора. Нарисуйте это на бумаге, как это нарисовано на картинке выше - пусть это будет упражнением.

Теперь кое-что поинтереснее - вектор можно умножить на число. Простая операция, которую можно описать тремя случаями:

Координаты

Оси мы уже завели, ноль находится в известном месте. Пора вводить координаты, потому что совсем скоро они нам понадобятся.

Что мы понимаем под осью координат? Выше я уже говорил, что это направление и единица измерения. Отметим, что характеристиками вектора являются его длина и направление. Прямо напрашивается вывод, что каждую ось можно представить вектором. Так и есть - возьмём вектор длиной с одну единицу измерения оси, направленный по ней. Теоретическая справка: набор векторов, представляющих оси координат, называется базисом. Запоминать это вам сейчас не нужно.

Базис, который мы будем использовать в GameMaker: это вектор \(\vec{i}\) длиной в 1 пиксель, направленный вправо; и вектор \(\vec{j}\) длиной в 1 пиксель, направленный вниз. Казалось бы - как может стрелочка быть длиной в 1 пиксель? А мы просто не будем понимать её, как стрелочку, это «единица измерения» нашего пространства.

Обратите внимание - в учебном процессе обычно используются графики с вертикальной осью, направленной вверх. Но мы занимаемся больше не теорией, а практикой. У нас оси направлены именно так, и с этим ничего не сделать.

Зачем нам вообще эти векторы? А вот зачем - мы можем получить с их помощью любую точку на экране. Представьте, что нам нужно получить точку на 50 пикселей правее и на 100 пикселей ниже левого верхнего угла комнаты. Какой вектор представит эта точка? Вот такой: ( \vec{i} \cdot 50 + \vec{j} \cdot 100 ) Числа ( 50 ) и ( 100 ) - и есть координаты. Для удобства, я записываю вектор из координат вот так: ( (50; 100) ) …или даже так, если не хочется путать векторы с точками: ( \overrightarrow{(50; 100)} ) Так повелось, что первой осью считают горизонтальную, а второй - вертикальную. Не будем отступать от этой традиции. GameMaker не отступает, например. Взять, к примеру, функцию draw_sprite:

draw_sprite(спрайт, кадр_спрайта, положение_по_x, положение_по_y);

Договорились. С этого момента вектор \( (a; b) \) - то же, что и \( \vec{i} \cdot a + \vec{j} \cdot b \). При этом \(a\) и \(b\) - просто ничем не примечательные числа. Достаточно очевидно, что длину вектора по координатам можно вычислить такой формулой: \( l = \sqrt{a^2 + b^2} \) Формула опирается на теорему Пифагора и тот факт, что \( \vec{i} \) и \( \vec{j} \) направлены под прямым углом (\(90^\circ\)). Формально длину можно определить и иначе, но этих вопросов мы не будем касаться.

Ещё операции

Теперь, когда мы ввели координаты, пришло время обсудить скалярное произведение. Строгого определения этой операции я давать не буду - отмечу лишь, что это операция, делающая из двух векторов некое число. Применять мы будем, как правило, такую:

\( \vec{a} \cdot \vec{b} = \vec{a} \cdot \vec{b} \cdot \cos{\widehat{(\vec{a}\vec{b})}} \)
\( \vec{a} \) - длина вектора \(\vec{a}\), а к косинусу мы ещё вернёмся позже. Это определение скалярного произведения называют геометрическим. Однако есть ещё один способ его вычислить, более весёлый и полезный.

\( \overrightarrow{(x_1; y_1)} \cdot \overrightarrow{(x_2; y_2)} = x_1 \cdot x_2 + y_1 \cdot y_2 \)

Можете проверить - это работает для любых векторов, и выдаёт точно те же самые значения. Обратите лишь внимание на то, что косинусу нужен угол, измеренный в радианах (\( 180^\circ = \pi \) радиан).

Поскольку эти определения равнозначны - это быстрый способ узнать угол между векторами. Угол может быть лишь от \( 0^\circ \) до \( 180^\circ \), значит, его можно однозначно вычислить при помощи арккосинуса. К работе с углами мы вернёмся позже, поэтому пока на это можно не обращать внимания.

Сложение векторов, представленных координатами (согласно свойствам сложения) выполняется просто путём сложения соответствующих координат. Вот так просто.

\( \overrightarrow{(x_1; y_1)} + \overrightarrow{(x_2; y_2)} = \overrightarrow{(x_1 + x_2; y_1 + y_2)} \)

Умножение вектора на число не сложнее - просто умножить координаты на соответствующее число:

\( \alpha \cdot \overrightarrow{(x; y)} = \overrightarrow{( \alpha \cdot x; \alpha \cdot y)} \)

Вычитание, таким образом, вытекает из двух правил выше.

Координаты в GameMaker повсюду. Надо понимать, как их использовать.

Эксперимент I

Задание, по большей части, творческое. Побито на этапы:

  1. Используя тот факт, что вид (view) №0 находится в комнате со смещением, указанным в векторе: \(()view_xview[0](;)view_yview[0]()\), перемещайте любой объект так, чтобы он всегда был на 50 пикселей правее и на 100 пикселей ниже левого верхнего угла вида №0.
  2. Вооружитесь вектором: \((\)lengthdir_x(расстояние, угол)\(;\)lengthdir_y(расстояние, угол)\()\), чтобы сделать у курсора мыши стрелочку, всегда указывающую на ( (0; 0) ) (помните о point_direction!), и отстоящую от курсора на 100 пикселей в том направлении, куда указывает.
  3. Добавьте вторую стрелочку, указывающую в том же направлении, что и первая, но отстоящую на 100 пикселей против того направления, в котором указывает. В чём подвох? Не пользоваться функциями lengthdir_x, lengthdir_y, а также sin и cos — только те значения, что были вычислены на предыдущем этапе, их можно.

Скалярное произведение и умножение вектора на число на этот раз трогать не будем. В следующем уроке узнаем несколько забавных фактов о том, для чего вообще может быть надо умножать вектор на число, и как так выходит, что при взятии среднего арифметического координат двух точек мы попадаем ровно между ними.