Математика игр. Часть 1.
Для наглядности будем делать игру Dragon Master и познавать насколько полезно учить математику в школе.
Плавное изменение свойств
Например, у наc есть класс Дракончика, который летает за своим хозяином. Код выглядит следующим образом:
public function followMaster(target:DisplayObject):void{ this.target = target; addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event):void{ x = target.x; y = target.y; }
Но не хватает динамики. Дракончик моментально перемещается за своим хозяином. Преобразуем немного выражение следующим образом:
Где (target.x - x) и (target.y - y) расстояния по осям от текущей точки до желаемой. Мы будем прибавлять не всё это расстояние, а, например, только четверть:
Или короче:
Таким образом Дракончик будет приближаться к желаемой точке на 1/n расстояния каждый кадр. Такая техника используется мной довольно часто для придания динамики в играх. Например, плавное изменение свойств может понадобиться в классе камеры, которая двигает карту, следя за игроком, чтобы тот не находился всегда в центре экрана и т.д.
Радианы и градусы
Очень полезно помнить, как преобразовать радианы в градусы и наоборот. Поворот визуальных объектов - rotation - задаётся в градусах, в то время как тригонометрические функции возвращают значения в радианах. Вот тут они нам и понадобятся:
function radToDeg(rad:Number):Number{ return rad/Math.PI*180; } function degToRad(deg:Number):Number{ return deg/180*Math.PI; }
Наш дракончик должен поворачиваться мордочкой по направлению движения. Для этого нужно определить угол между дракончиком и игроком. Для этого нужно вспомнить, что такое тангенс угла. Тангенс угла - это отношение катетов. Арктангенс - это обратная функция, результатом которой будет угол в радианах. Катетами треугольника - будут наши расстояния по осям: (target.x - x) и (target.y - y). В ActionScript 3 есть стандартная функция, которая считает арктангенс по длинам катетов:
Обратите внимание, что первым аргументом идёт расстояние по оси y, а не по x.
Поворачиваться Дракончик будет плавно (да дракончик умеет сдавать спиной. Даже в Dota персонажи так делают), это мы уже умеем:
Есть одно но. Функция atan2 возвращает значение от -PI до PI. То есть для значения PI+0.000001 функция вернёт -PI+0.000001 и вместо того, чтобы повернуться на 1 миллионную радиана, Дракончик сделает почти полный оборот. Для это будем считать наименьший направленный угол поворота:
function rotationAngle(a1:Number, a2:Number):void{ //Приводим значения к одному кругу a1 %= 360; a2 %= 360; //Нормализуем углы, чтобы их значения были в интервале от 0 до 360; if (a1 < 0) a1 += 360; if (a2 < 0) a2 += 360; //Угол поворота между углами var a:Number = a2 - a1; //Он не может быть больше 180 градусов if (a > 180) return a-360; if (a < -180) return a+360; return a; }
Синусы и косинусы
Сам персонаж будет у нас ходить с постоянной скоростью, перемещаясь к позиции клика на карте. У нас есть функция:
function move(endX:Number, endY:Number):void { start = new Point(x, y); end = new Point(endX, endY); }
И угол:
Также объявим переменную скорости и пройденного расстояния.
Теперь наш персонаж каждый кадр должен проходить расстояние равное скорости:
Вспомним какие значения возвращают синус и косинус угла. Для этого возьмём круг единичного диаметра:
На картинке видно, что координата X точки A равна косинусу угла, а по Y - синуса. Домножим эти величины на пройдённое расстояние и сместим центр на точку начала движения:
Это и будет положением Мастера в любой момент времени. Можно конечно было обойтись и без тригонометрических функций (они взяты для наглядности):
x = start.x + progress/distance * (end.x-start.x); y = start.y + progress/distance * (end.y-start.y);
Вот, что в итоге должно получиться:
Архив с исходным кодом: DragonMaster.rar
В следующей части мы сделаем гексагональный лабиринт и прикрутим к нему поиск пути. Stay tuned.
Всего комментариев 20
Комментарии
![]() ![]() |
|
Классно!
|
![]() ![]() |
|
Спасибо, нужная статья)
|
![]() ![]() |
|
Спасибо, вроде начало начал, а оказывается сколько упустил материала
![]() |
![]() ![]() |
|
Спасибо за замечания - поправил текст. Про Math.PI*180 - это для наглядности.
|
![]() ![]() |
|
Цитата:
Это уже в учебниках?
|
![]() ![]() |
|
![]() ![]() |
|
![]() ![]() |
|
Почему "велосипедил"?
|
![]() ![]() |
|
Цитата:
Например, игровые физические движки — насколько я могу предполагать, все, по крайней мере, популярные — тоже работают пошагово
|
![]() ![]() |
|
Цитата:
Идеализация там привела бы к очень неправильным результатам.
|
![]() ![]() |
|
Цитата:
Если бы ты знал, что "step" переводится как "шаг", то не стал бы спорить с очевидным
|
|
Обновил(-а) iNils 14.08.2014 в 15:27
|
![]() ![]() |
|
![]() ![]() |
|
Цитата:
Ещё на такое:
|
Последние записи от Rzer
- Радиальный прогресс бар для Starling 2 (01.07.2016)
- Приложения для изучающих AS3 (21.12.2014)
- Математика игр. Часть 1. (10.07.2014)
- Подключаем SWC как внешнюю библиотеку. (07.07.2014)
- Обновился набор классов simplify as3 (20.11.2012)