Файл: Беляев С А - Разработка игр на языке JavaScript - 2016.pdf
Добавлен: 25.10.2018
Просмотров: 7596
Скачиваний: 136
Отображение карты игры
41
Функция isVisible содержит единственное условие,
которое проверяет, что два прямоугольника пересекают
ся: параметры первого прямоугольника переданы в функ
цию isVisible в виде x, y, width и height. Параметры вто
рого прямоугольника хранятся в this.view.
Если прямоугольники пересекаются, возвращается
true, иначе — false.
Для запуска полученной программы необходимо под
ключить приведенный JavaScript в HTMLстраницу, со
держащую холст canvas с объявлением переменных canvas
и ctx (по аналогии с примерами из главы 1), затем вызвать
две функции вновь созданного mapManager:
mapManager.loadMap("tilemap.json"); // çàãðóçèòü êàðòó
mapManager.draw(ctx); // íàðèñîâàòü êàðòó
Пример работы программы приведен на рисунке 2.2.
2.3.
ДОПОЛНИТЕЛЬНЫЕ МЕТОДЫ РАБОТЫ
С КАРТОЙ
Рассмотренные методы позволяют создать и отобра
зить карту пользователю, в том числе с учетом того, что в
общем случае карта намного больше, чем размер холста,
на котором она отображается. При разработке менедже
ров управления объектами, взаимодействия пользователя
Рис. 2.2
Пример внешнего вида карты,
загруженной с помощью
mapManager
42
Глава 2
и игры возникнет необходимость в разработке дополни
тельных функций mapManager, которые на этапе отобра
жения карты могут показаться не очевидными.
Это такие функции, как: разбор слоя типа objectgroup,
получение блока по его координатам на холсте, центров
ка карты относительно заданных координат (x, y).
function parseEntities() { // ðàçáîð ñëîÿ òèïà objectgroup
if (!mapManager.imgLoaded || !mapManager.jsonLoaded) {
setTimeout(function () { mapManager.parseEntities(); }, 100);
} else
for (var j = 0; j < this.mapData.layers.length; j++)
// ïðîñìîòð âñåõ ñëîåâ
if(this.mapData.layers[j].type === 'objectgroup') {
var entities = this.mapData.layers[j];
// ñëîé ñ îáúåêòàìè ñëåäóåò "ðàçîáðàòü"
for (var i = 0; i < entities.objects.length; i++) {
var e = entities.objects[i];
try {
var obj = Object.create(gameManager.factory[e.type]);
// â ñîîòâåòñòâèè ñ òèïîì ñîçäàåì ýêçåìïëÿð îáúåêòà
obj.name = e.name;
obj.pos_x = e.x;
obj.pos_y = e.y;
obj.size_x = e.width;
obj.size_y = e.height;
// ïîìåùàåì â ìàññèâ îáúåêòîâ
gameManager.entities.push(obj);
if(obj.name === "player")
// èíèöèàëèçèðóåì ïàðàìåòðû èãðîêà
gameManager.initPlayer(obj);
} catch (ex) {
console.log("Error while creating: [" + e.gid + "] " + e.type +
", " + ex); // ñîîáùåíèå îá îøèáêå
}
} // Êîíåö for äëÿ îáúåêòîâ ñëîÿ objectgroup
} // Êîíåö if ïðîâåðêè òèïà ñëîÿ íà ðàâåíñòâî objectgroup
}
JSON карты может содержать не только слой tilelayer,
но и слой objectgroup, который хранит информацию о том,
какие объекты и где находятся на карте.
Отображение карты игры
43
В первой строчке функции «разбора» слоя объектов
parseEntities выполняется проверка условия, что изобра
жения и описание карты загружены (по аналогии с функ
цией draw).
for (var j = 0; j < this.mapData.layers.length; j++)
Цикл for проверяет все слои, сохраненные в mapData.
layers.
if(this.mapData.layers[j].type === 'objectgroup')
Данное условие if проверяет, что тип слоя (type) явля
ется слоем objectgroup.
var entities = this.mapData.layers[j];
Создается переменная entities для сокращения записи
при обращении к слою.
for (var i = 0; i < entities.objects.length; i++)
Цикл for ходит по массиву objects для слоя objectgroup.
Следует обратить внимание, что два цикла for являются
вложенными друг относительно друга, поэтому перемен
ные для счетчиков цикла выбраны разные (i и j).
var e = entities.objects[i];
Вводится временная переменная для объекта (сущно
сти), полученная из описания слоя objectgroup.
Конструкция try {…} catch(ex) {…} предназначена для
выполнения действий, которые могут привести к ошибоч
ным ситуациям. В случае возникновения ошибки управ
ление передается в блок, ограниченный фигурными скоб
ками после catch.
var obj = Object.create(gameManager.factory[e.type]);
В данной строке создается новый объект, который бу
дет размещаться на карте. Здесь используется новый объ
ект gameManager (см. главу 6). В данном случае поле e.type
хранит строковое название объекта, который необходимо
разместить на карте. Значение поля type в визуальном
интерфейсе вводится дизайнером игры. Конструкция
gameManager.factory[e.type] вернет объект JavaScript,
описанный в главе 3 и дополненный в главе 5. Встроенная
функция Object.create создает новый объект на основании
44
Глава 2
gameManager.factory[e.type]. При этом копируются все
поля и функции из исходного объекта. Ошибка может воз
никнуть, если разработчик не описал объект с типом e.type.
В новом объекте сохраняются его имя (name), коор
динаты в пискелах (pos_x, pos_y), размеры в пикселах
(size_x, size_y).
gameManager.entities.push(obj);
Объект функцией push помещается в массив entities
менеджера игры gameManager (глава 6).
if(obj.name === "player")
Выполняется проверка, что полученный объект соот
ветствует «игроку», которым будет управлять пользова
тель. Поле name — текст, который в визуальном интерфей
се вводится дизайнером игры. В связи с этим разработчик
должен учитывать, что данный текст может быть не введен
или будет найдено несколько объектов с тем же текстом.
gameManager.initPlayer(obj);
Вызывается функция initPlayer менеджера игры
gameManager (глава 6), в качестве параметра задается
объект, соответствующий «игроку», которым будет управ
лять пользователь.
Функция log встроенного объекта console выводит в
консоль разработчика браузера информацию, передавае
мую в качестве параметра. Доступ к консоли разработчи
ка описан в параграфе 1.3.
function getTilesetIdx(x, y){
// ïîëó÷èòü áëîê ïî êîîðäèíàòàì íà êàðòå
var wX = x;
var wY = y;
var idx = Math.floor(wY / this.tSize.y) * this.xCount + Math.floor
(wX / this.tSize.x);
return this.tLayer.data[idx];
}
Функция getTilesetIdx, используя размеры блоков
(tSize.x, tSize.y) и количество блоков по горизонтали
(xCount), вычисляет индекс блока в массиве data (idx).
return this.tLayer.data[idx];
Отображение карты игры
45
Функция возвращает блок из массива data с индексом
idx.
function centerAt(x, y) {
if(x < this.view.w / 2) // Öåíòðèðîâàíèå ïî ãîðèçîíòàëè
this.view.x = 0;
else
if(x > this.mapSize.x - this.view.w / 2)
this.view.x = this.mapSize.x - this.view.w;
else
this.view.x = x - (this.view.w / 2);
if(y < this.view.h / 2) // Öåíòðèðîâàíèå ïî âåðòèêàëè
this.view.y = 0;
else
if(y > this.mapSize.y - this.view.h / 2)
this.view.y = this.mapSize.y - this.view.h;
else
this.view.y = y - (this.view.h / 2);
}
Функция centerAt предназначена для центрирования
области mapManager.view относительно положения игро
ка (x, y). Функция делится на две логические части: цент
рирование по горизонтали и центрирование по вертика
ли. Они абсолютно идентичны за исключением замены x
на y и ширины (view.w) на высоту (view.h).
if(x < this.view.w / 2)
Первой строчкой выполняется проверка, что x мень
ше половины ширины холста, если это верно, то view.x
присваивается значение ноль.
if(x > this.mapSize.x - this.view.w / 2)
Затем проверяется, что x больше ширины карты, умень
шенной на половину ширины холста, если это верно, то
view.x присваивается разность между шириной карты и
шириной холста, иначе view.x присваивается разность
между x и половиной ширины холста.
Идентичные действия выполняются при центрирова
нии по вертикали.