— Ну что мои дорогие ученики, теперь вы понимаете, как вычисляется синус и косинус угла?
— Учитель, а где это пригодится в жизни?
— А что уже звонок прозвенел? Все свободны!
Я хочу поделиться собственной функцией перевода координат из полярной системы в декартову систему. Вернее не самой функцией, а то каким способом я изобретал велосипед, не будучи в состоянии воспользоваться уже готовыми решениями.
Вы, наверное, спросите – «А в чем собственно полезность данной статьи?».
Если вы задали такой вопросом, то дальше ничего интересного для вас не будет, а вот для людей, которые подобно мне не являются программистами – вполне себе пособие, как выбраться из затруднительного положения.
Так уж сошлись звезды на небе, что мне пришлось столкнуться с внутренним скриптовым языком одной компании. Никаких громких названий этот язык не имеет и по синтаксису отдаленно напоминает C-подобные. С помощью него создаются заклинания для онлайн RPG – игры. Но так же с помощью него реализуются визуальные эффекты к этим самых заклинаниям.
Для нормальной работы заклинаний необходимо использовать относительные координаты. Проще говоря, мы манипулируем точками и областями, которые привязаны к какому-либо центру (в нашем случае центром чаще всего выступает персонаж или монстр). Еще проще говоря, если целью заклинания является игровой персонаж, то мы можем создать визуальный эффект не для самого персонажа, а в точке с отступом от персонажа на расстояние «y» = 5 (вперед) и «x» = -3 (влево) игровых метров. Собственно, весь функционал по манипуляции точек и ограничивался смещением по иксу и игрику.
Не знаю, будет ли для вас откровением, но самые шикарные (на мой взгляд) визуальные эффекты, которые можно создавать с помощью математических функций, реализуются в полярной системе координат (см. рисунки). Но вот проблема, функции в этой системе координат задаются не с помощью «x» и «y», а величиной радиуса и значением угла.
Не будем задаваться вопросами «откуда знаешь» и «с чего ты взял», но точку, заданную с помощью радиуса и угла, можно перевести в точку с координатами «x» и «y»:
- x = r * Cos(угол)
- y = r * Sin(угол)
Вроде бы, все просто! Но мир IT полон множеством «Но», и, само собой разумеется, в данном языке нет встроенных инструментов для вычисления тригонометрических функций (Cos и Sin).
Моя специальность в университет к счастью имела такое же отношение к высшей математике, как утконос к проектированию орбитальных станций, поэтому за помощью по поиску алгоритма вычисления Синуса я обратился к товарищу гуглу.
В кусках кода, которые мне выдавали некоторые результаты поиска, я разобраться не смог, следовательно, пришлось изучать математику.
Первое, с чем я познакомился, так это с рядами Тейлора. Но их проблема в том, что они требуют серьезных вычислительных мощностей (возведения в степень), и понимания основ:
- Ряды используют значение угла, указанного в радианах (в конце дня я смог понять, почему у меня вместо синуса вычисляется последнее число Мерсенна).
- Ряды корректно вычисляют только те значения угла, которые заданы в пределах от 0 до 2*pi (осознание того, почему ответ получается равен числу Грехема, пришло только спустя час).
В общем, ряды – это не наш «пассажир». Алгоритмы с мнимое единицей «i» для вычисления синуса, как бы даже не «житель» нашей планеты.
И чуть не забыл поделиться еще одной уникальной особенностью данного скриптового языка – у него отсутствуют массивы. Это, к слову, что касается всех других возможных «пассажиров».
Время шло, а проблема не решалась, поэтому в действие пошел план-банан, который никогда не подводит. Настало время вытащить свой собственный велосипед, пускай и без колес – «Анализ графика функции Sin и интерполяция».
Результаты чирканья волнистых линий на листке привели к следующим выводам (которые пригодятся лишь в моей следующей статье):
- Алгоритм волны синусоиды уникален только на дистанции от 0 до 90 градусов (в идеале от 0 до 45, но здесь много ненужных проблем).
- Синусоида содержит два типа отрезков: один, из которых вначале быстро возрастает, а под конец сильно замедляется, второй же все в точности наоборот.
Колеса к велосипеду я приделал следующим образом:
На калькуляторе получил синусы для углов 10, 20, 30, …, 80, 90 градусов. А дальше для вычисления угла использовал интерполяцию. Например, нам нужно посчитать синус угла 24-х градусов:
- Sin(20) = 0.3420 и Sin(30) = 0.5
- Если расстояние между 20 до 30 = 100%, то 24 – это 40% всего расстояния
- 0.5 — 0.3420 = 0.1580 (это и есть наше расстояние в 100%)
- 0.1580 * 40% = 0.0632 (примерно на это значение Sin(24) превосходит Sin(20))
- Sin(24) = Sin(20) + 0.0632 = 0.3420 + 0.0632 = 0.4032
А раз мы вычислили синус, то узнать значение косинуса не составит труда. Как там нас учили в школе? Sin^2 + Cos^2 = 1.
Значит, Cos = (1 – Sin^2)^0.5 (а если быть точнее, то Cos = z * (1 – Sin^2)^0.5).
И о чудо… Отдавая для функции операторы «radius» и «angle» мы обратно получаем «x» и «y» (не совсем точные значения, но вполне себе реальные).
Кусочек кода, который рисует нам спиральку из спецэффектов с id = 57 (polar_offset – это и есть наша функция для перевода координат из одной системы в другую):
i = 0
while (i < 36 * 3){
angle = i * 10
radius = i / 10
x = target.polar_offset(angle, radius, 0)
y = target.polar_offset(angle, radius, 1)
visual_effect (57, x, y)
i = i + 1
wait (0.05)
}
Предсказываю удивленные глаза и кучу похожих замечаний – «Но ведь угол можно задавать любым числом, а не только от 0 до 90». Но это уже совсем другая история, которую я расскажу в следующей статье.
Автор: Fensfire
Классно. Вы интересно пишете. Пишите про геймдев, не забрасывайте это дело. Вас интересно читать!