Файл: Беляев С А - Разработка игр на языке JavaScript - 2016.pdf
Добавлен: 25.10.2018
Просмотров: 7595
Скачиваний: 136
Реализация логики поведения объектов
91
Данное условие не отличается от примера «Свободное
падение».
if(Math.abs(pos.imp) > 0.01)
Условие проверяет абсолютное значение (Math.abs)
импульса (pos.imp), если импульс по модулю достаточно
велик, то выполняются следующие шаги. В данном при
мере выбрано значение 0.01. Это значение разработчик
подбирает эмпирическим путем с учетом видимой скоро
сти затухания падения.
pos.imp = pos.dy = pos.imp / 2;
Уменьшение импульса. В данном примере импульс
уменьшается в 2 раза. Степень уменьшения импульса оп
ределяется разработчиком, чем сильнее уменьшается им
пульс, тем менее упругое столкновение. Результат умень
шения импульса сохраняется в pos.dy в качестве нового
ускорения.
pos.y += pos.dy;
Чтобы объект «отскочил» необходимо сразу изменить
значение координаты по вертикали (pos.y) с учетом новой
скорости (pos.dy).
Если импульс оказался достаточно мал, то демонстра
ция начинается сначала. Предлагаемый код по своей сути
не отличается от программы «Изменение двух координат
с учетом свободного падения», но записан в сокращенном
виде.
pos = {x:20, y:320, dx:4, dy:-15, imp:-15};
Объекту pos присваиваются те же значения, что и при
инициализации.
В зависимости от особенностей реализуемых законов
физики разработчик может выбрать тот или иной вари
ант реализации функций update.
5.2.
МЕНЕДЖЕР ФИЗИКИ ОБЪЕКТОВ
При создании объектов у каждого из них могут быть
свои особенности отображения, изменения состояния,
влияния на другие объекты, но законы движения с боль
шой вероятностью будут общие [13], [14]. В связи с этим
92
Глава 5
целесообразно общую логику по обновлению вынести в
специальный объект — менеджер физики объектов (physic
Manager).
var physicManager = {
update: function (obj){
if(obj.move_x === 0 && obj.move_y === 0)
return "stop"; // ñêîðîñòè äâèæåíèÿ íóëåâûå
var newX = obj.pos_x + Math.floor(obj.move_x * obj.speed);
var newY = obj.pos_y + Math.floor(obj.move_y * obj.speed);
// àíàëèç ïðîñòðàíñòâà íà êàðòå ïî íàïðàâëåíèþ äâèæåíèÿ
var ts = mapManager.getTilesetIdx(newX + obj.size_x / 2,
newY + obj.size_y / 2);
var e = this.entityAtXY(obj, newX, newY); // îáúåêò íà ïóòè
if(e !== null && obj.onTouchEntity) // åñëè åñòü êîíôëèêò
obj.onTouchEntity(e); // ðàçáîð êîíôëèêòà âíóòðè îáúåêòà
if(ts !== 7 && obj.onTouchMap) // åñòü ïðåïÿòñòâèå
obj.onTouchMap(ts); // ðàçáîð êîíôëèêòà ñ ïðåïÿòñòâèåì
// âíóòðè îáúåêòà
if(ts === 7 && e === null) { // ïåðåìåùàåì îáúåêò íà ñâîáîäíîå
// ìåñòî
obj.pos_x = newX;
obj.pos_y = newY;
} else
return "break"; // äàëüøå äâèãàòüñÿ íåëüçÿ
return "move"; // äâèãàåìñÿ
},
entityAtXY: function(obj, x, y) { // ïîèñê îáúåêòà ïî êîîðäèíàòàì
for(var i = 0; i < gameManager.entities.length; i++) {
var e = gameManager.entities[i]; // âñå îáúåêòû êàðòû
if(e.name !== obj.name) { // èìÿ íå ñîâïàäàåò (èìåíà
// óíèêàëüíû)
if (x + obj.size_x < e.pos_x || // íå ïåðåñåêàþòñÿ
y + obj.size_y < e.pos_y ||
x > e.pos_x + e.size_x ||
y > e.pos_y + e.size_y)
continue;
Реализация логики поведения объектов
93
return e; // íàéäåí îáúåêò
}
} // êîíåö öèêëà for
return null; // îáúåêò íå íàéäåí
}
};
Менеджер физики объектов содержит две функции:
основную (update) для обновления состояния объекта и
вспомогательную (entityAtXY) для определения столкно
вения с объектом по заданным координатам.
При реализации функции update используются сле
дующие особенности объекта: уникальное имя объекта
(name), его координаты (pos_x, pos_y), размеры (size_x,
size_y), направление движения по координатам (move_x,
move_y), скорость движения (speed). Объект может содер
жать функции встречи с другим объектом (onTouchEntity)
и встречи с границей карты (onTouchMap) или не содер
жать их. Если проанализировать метод parseEntities ме
неджера карты, то можно обнаружить, что в нем инициа
лизируются имя, координаты и размеры объекта. Если
проанализировать описания объектов, то в них задаются
скорость и направления движения.
Предполагается, что массив объектов хранится в ме
неджере игры gameManager.entities, обращение к этому
полю выполняется в функции entityAtXY при поиске
объектов, находящихся по заданным координатам.
Для определения касания карты используется код бло
ка, обозначающего пустое пространство: в приведенном
фрагменте кода — это число 7.
Функция update изменяет состояние объекта и возвра
щает информацию о внесенных или не внесенных измене
ниях (коды: stop, break, move).
if(obj.move_x === 0 && obj.move_y === 0) return "stop";
Условие проверяет, что скорости движения нулевые,
в таком случае выполнение функции прекращается и воз
вращается код «stop» (объект стоит).
var newX = obj.pos_x + Math.floor(obj.move_x * obj.speed);
var newY = obj.pos_y + Math.floor(obj.move_y * obj.speed);
94
Глава 5
Создаются две переменные для хранения новых коор
динат объекта (newX, newY). Новые координаты вычис
ляются как сумма предыдущих координат и направления
движения, умноженного на скорость. Для вычисления
используется функция floor, обеспечивающая округление
до меньшего целого числа встроенного объекта Math.
var ts = mapManager.getTilesetIdx(newX + obj.size_x / 2, newY +
obj.size_y / 2);
Создается новая переменная ts, в которую сохраняют
ся результаты вызова функции getTilesetIdx менеджера
карты, в качестве координат используется середина объек
та. Функция getTilesetIdx возвращает индекс блока кар
ты, который находится на пути объекта.
var e = this.entityAtXY(obj, newX, newY);
Создается переменная e, в которую сохраняются ре
зультаты вызова функции entityAtXY и которая сообща
ет с кем произойдет столкновение, если объект будет на
ходиться в координатах (newX, newY).
if(e !== null && obj.onTouchEntity) obj.onTouchEntity(e);
Если переменная e содержит значение и в объекте есть
функция обработки встречи с другим объектом (onTouch
Entity), то эта функция вызывается, а в качестве парамет
ра передается переменная e.
if(ts !== 7 && obj.onTouchMap) obj.onTouchMap(ts);
Если значение переменной ts не равно 7 (в данном при
мере число 7 — индекс блока, по которому может двигать
ся объект) и объект содержит функцию встречи с грани
цей карты (onTouchMap), то эта функция вызывается, а в
качестве параметра передается значение переменной ts.
if(ts === 7 && e === null)
Если не произошло столкновения с границей карты
и другим объектом, то сохраняются новые координаты:
obj.pos_x = newX; obj.pos_y = newY. Иначе возвращается
код «break» (дальнейшее движение невозможно).
return "move";
Реализация логики поведения объектов
95
Возвращается код «move» (продолжаем движение).
При наличии отличий в отображении объекта при движе
нии влево, вправо, вверх или вниз целесообразно в этой
функции вычислить реальное направление движение и
вместо кода «move» вернуть код с направлением движе
ния, например, «move_left» (двигаемся налево).
Функция entityAtXY принимает три параметра: объ
ект и его новые координаты (x, y).
for(var i = 0; i < gameManager.entities.length; i++)
Цикл for обеспечивает проход по всем объектам карты.
Предполагается, что объекты хранятся в массиве game
Manager.entities.
var e = gameManager.entities[i];
Создается новая переменная e, в которую сохраняется
текущий анализируемый объект карты.
if(e.name !== obj.name)
Проверяем, что имя анализируемого объекта не совпа
дает с именем объекта, передаваемого в качестве парамет
ра функции. Именно здесь используется свойство уникаль
ности имени объекта.
if (x + obj.size_x < e.pos_x || y + obj.size_y < e.pos_y ||
x > e.pos_x + e.size_x || y > e.pos_y + e.size_y) continue;
Если анализируемый объект и передаваемый в каче
стве параметра не пересекаются, то с использованием клю
чевого слова continue осуществляется переход к очеред
ной итерации цикла for для анализа следующего объекта:
return e;
Возвращается найденный объект.
return null;
Возвращается пустой объект (столкновение с другими
объектами не обнаружено).
Простейшее применение функции update менеджера
физики объектов позволяет упростить функции update
объекта.