Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Rzer

Рейтинг: 3.00. Голосов: 3.

Математика игр. Часть 1.

Запись от Rzer размещена 10.07.2014 в 20:59
Обновил(-а) Rzer 11.07.2014 в 20:09

Для наглядности будем делать игру Dragon Master и познавать насколько полезно учить математику в школе.

Плавное изменение свойств

Например, у наc есть класс Дракончика, который летает за своим хозяином. Код выглядит следующим образом:

Код AS3:
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;
}

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

Код AS3:
x = x + (target.x - x);
y = y + (target.y - y);
Где (target.x - x) и (target.y - y) расстояния по осям от текущей точки до желаемой. Мы будем прибавлять не всё это расстояние, а, например, только четверть:

Код AS3:
x = x + (target.x - x)/4;
y = y + (target.y - y)/4;
Или короче:

Код AS3:
x += (target.x - x)/4;
y += (target.y - y)/4;

Таким образом Дракончик будет приближаться к желаемой точке на 1/n расстояния каждый кадр. Такая техника используется мной довольно часто для придания динамики в играх. Например, плавное изменение свойств может понадобиться в классе камеры, которая двигает карту, следя за игроком, чтобы тот не находился всегда в центре экрана и т.д.

Радианы и градусы

Очень полезно помнить, как преобразовать радианы в градусы и наоборот. Поворот визуальных объектов - rotation - задаётся в градусах, в то время как тригонометрические функции возвращают значения в радианах. Вот тут они нам и понадобятся:

Код AS3:
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 есть стандартная функция, которая считает арктангенс по длинам катетов:

Код AS3:
var rad:Number = Math.atan2(target.y - y, target.x - x);
rotation = radToDeg(rad);
Обратите внимание, что первым аргументом идёт расстояние по оси y, а не по x.

Поворачиваться Дракончик будет плавно (да дракончик умеет сдавать спиной. Даже в Dota персонажи так делают), это мы уже умеем:

Код AS3:
rotation += (radToDeg(rad) - rotation)/4;
Есть одно но. Функция atan2 возвращает значение от -PI до PI. То есть для значения PI+0.000001 функция вернёт -PI+0.000001 и вместо того, чтобы повернуться на 1 миллионную радиана, Дракончик сделает почти полный оборот. Для это будем считать наименьший направленный угол поворота:

Код AS3:
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;	
}
Теперь для плавного изменения угла поворота делаем следующее:

Код AS3:
rotation += rotationAngle(rotation, radToDeg(rad))/4;
Синусы и косинусы

Сам персонаж будет у нас ходить с постоянной скоростью, перемещаясь к позиции клика на карте. У нас есть функция:

Код AS3:
function move(endX:Number, endY:Number):void {
 
	start = new Point(x, y);
	end = new Point(endX, endY);
 
}
Для начала посчитаем расстояние между точками по всем известной школьной формуле:
Название: 8class-1117.jpg
Просмотров: 2810

Размер: 8.9 Кб

Код AS3:
distance = Math.sqrt(Math.pow(end.x-start.x,2) + Math.pow(end.y-start.y,2));
И угол:

Код AS3:
angle = Math.atan2(end.y - start.y, end.x -start.x);
Также объявим переменную скорости и пройденного расстояния.

Код AS3:
speed = 5;
progress = 0;
Теперь наш персонаж каждый кадр должен проходить расстояние равное скорости:

Код AS3:
progress += speed;
Вспомним какие значения возвращают синус и косинус угла. Для этого возьмём круг единичного диаметра:
Нажмите на изображение для увеличения
Название: pi1.png
Просмотров: 150
Размер:	19.7 Кб
ID:	439


На картинке видно, что координата X точки A равна косинусу угла, а по Y - синуса. Домножим эти величины на пройдённое расстояние и сместим центр на точку начала движения:

Код AS3:
x = start.x +  progress * Math.cos(angle);
y = start.y + progress * Math.sin(angle);
Это и будет положением Мастера в любой момент времени. Можно конечно было обойтись и без тригонометрических функций (они взяты для наглядности):

Код AS3:
x = start.x +  progress/distance * (end.x-start.x);
y = start.y + progress/distance * (end.y-start.y);
Что и закономерно, так как синус или косинус угла равен отношению соответствующего катета к гипотенузе.

Вот, что в итоге должно получиться:
DragonMaster.swf   (25.5 Кб)


Архив с исходным кодом: DragonMaster.rar
В следующей части мы сделаем гексагональный лабиринт и прикрутим к нему поиск пути. Stay tuned.
Вложения
Тип файла: swf DragonMaster.swf (25.5 Кб, 537 просмотров)
Всего комментариев 20

Комментарии

Старый 10.07.2014 22:02 samana вне форума
samana
 
Аватар для samana
Классно!
Старый 11.07.2014 11:56 gyfak вне форума
gyfak
Спасибо, нужная статья)
Старый 11.07.2014 15:14 GrafMine вне форума
GrafMine
 
Аватар для GrafMine
Спасибо, вроде начало начал, а оказывается сколько упустил материала
Старый 11.07.2014 15:30 alexcon314 вне форума
alexcon314
Цитата:
Угол между двумя точками
Это уже в учебниках?
Цитата:
Заплавление движения ... Sin и косинусы .. точка A по оси X лежит на расстоянии косинуса угла
Что ж так .... топорно-то..
Цитата:
Math.PI*180
Полезно заранее высчитать один раз и использовать готовенькое. Или компилятор уже научили оптимизациям?

Но вцелом начинание полезное, построже изложение только, математика как никак.
Старый 11.07.2014 19:58 Rzer вне форума
Rzer
 
Аватар для Rzer
Спасибо за замечания - поправил текст. Про Math.PI*180 - это для наглядности.
Старый 11.07.2014 20:12 GBee вне форума
GBee
 
Аватар для GBee
Цитата:
Это уже в учебниках?
Кстати, я уже встречал такую формулировку. Это вроде про вектора из одной точки.
Старый 11.07.2014 23:39 Astraport вне форума
Astraport
 
Аватар для Astraport
Старый 22.07.2014 04:41 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Код AS3:
//Приводим значения к одному кругу
a1 %= 360;
a2 %= 360;
 
//Нормализуем углы, чтобы их значения были в интервале от 0 до 360;
if (a1 < 0) a1 += 360;
if (a2 < 0) a2 += 360;
Можно заменить на такое:
Код AS3:
a1 = (a1 % 360 + 360) % 360;
a2 = (a2 % 360 + 360) % 360;
Точно так же справляется с совершенно любыми углами, в том числе отрицательными, только в одну строчку.
Старый 06.08.2014 16:39 nubideus вне форума
nubideus
Код AS3:
x += (target.x - x)/4;
я помню, как велосипедил это в первые полгода погромирования
Старый 06.08.2014 23:16 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Почему "велосипедил"?
Старый 12.08.2014 19:56 toFL вне форума
toFL
Цитата:
Таким образом Дракончик будет приближаться к желаемой точке на 1/n расстояния каждый кадр
Не совсем правильно. В идеале анимации должны быть привязаны к времени:
1) Легко изменить FPS
2) При просадках CPU не будет рассинхрона
Старый 13.08.2014 22:41 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Не совсем корректно.
Например, игровые физические движки — насколько я могу предполагать, все, по крайней мере, популярные — тоже работают пошагово. Идеализация там привела бы к очень неправильным результатам.

P.S.
Уж и не говорю о том, что не каждому идеалисту так уж и по плечу корректно заменить обсуждаемую формулу на функциональную зависимость от t.
Старый 14.08.2014 11:34 toFL вне форума
toFL
Цитата:
Например, игровые физические движки — насколько я могу предполагать, все, по крайней мере, популярные — тоже работают пошагово
Предположение не верно.
Код AS3:
// Box2D
Box2D.Dynamics.b2World.Step(dt:Number, velocityIterations:int, positionIterations:int):void//Take a time step.
 
// Nape
nape.space.Space.step(dt:Number);//Take a time step.
Старый 14.08.2014 11:34 toFL вне форума
toFL
Цитата:
Идеализация там привела бы к очень неправильным результатам.
Опять же, предположение не верно - они только на ней и держатся.
Старый 14.08.2014 11:57 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Ну, предположением я это назвал исключительно для красного словца.
Если бы ты знал, что "step" переводится как "шаг", то не стал бы спорить с очевидным. А если немного разбираться в сути работы физических движков, то можно понять, что это за dt такой передается в качестве аргумента и зачем более аккуратному Box2D нужны эти velocityIterations и positionIterations.

Насчет "они только на ней и держатся" — еще одно высказывание, не соответствующее действительности. В 9 случаях из 10 все держится на приближении и имитации.
Старый 14.08.2014 12:33 toFL вне форума
toFL
Цитата:
Если бы ты знал, что "step" переводится как "шаг", то не стал бы спорить с очевидным
О чем ты говоришь? AS3 весь выполняется пошагово. ABC код попадает в стэк каждый n кадров в секунду. Это не означает что расчеты нельзя привязать к времени.
Обновил(-а) iNils 14.08.2014 в 15:27
Старый 14.08.2014 12:35 toFL вне форума
toFL
Цитата:
А если немного разбираться в сути работы физических движков, то можно понять, что это за dt такой передается в качестве аргумента и зачем более аккуратному Box2D нужны эти velocityIterations и positionIterations.
Цитата:
В 9 случаях из 10 все держится на приближении и имитации.
Куча воды, ноль доказательств.
Старый 14.08.2014 12:51 Zebestov вне форума
Zebestov
 
Аватар для Zebestov
Ты вроде даже не программист? Познания в математике у тебя, очевидно, тоже невелеки. Зачем бы я стал доказывать вещи, которые становятся очевидными при малейшем погружении в материал!

Тебе всего лишь указали на то, что "правильно/неправильно" — это не то утверждение, которое авторитетно может заявить каждый прохожий. Более того, тебе указали на неоспоримый факт, что "неправильно" (на твой взгляд) делают повсеместно.

Каюсь, привел неподъемный для твоего понимания пример.
Старый 19.08.2014 16:10 tsarapkabel вне форума
tsarapkabel
 
Аватар для tsarapkabel
Цитата:
Можно заменить на такое:
Код AS3:
a1 = (a1 % 360 + 360) % 360;
a2 = (a2 % 360 + 360) % 360;
Точно так же справляется с совершенно любыми углами, в том числе отрицательными, только в одну строчку.
Ещё на такое:
Код AS3:
a1 = (a1 + 360) % 360;
a2 = (a2 + 360) % 360;
Старый 19.08.2014 20:49 Rzer вне форума
Rzer
 
Аватар для Rzer
Цитата:
Ещё на такое:
Нельзя. Для проверки: -361
 

 


Часовой пояс GMT +4, время: 06:54.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2018, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.