Файл: Беляев С А - Разработка игр на языке JavaScript - 2016.pdf
Добавлен: 25.10.2018
Просмотров: 7592
Скачиваний: 136
Отображение карты игры
31
Второй параметр path хранит URL запроса. Третий
параметр может принимать значения true или false. В слу
чае true запрос будет отправлен асинхронно, в случае false
исполнение JavaScript будет приостановлено до получе
ния ответа от сервера.
request.send();
В последней строке функции loadMap, собственно, вы
полняется отправка запроса на сервер для получения JSON
карты.
Важно обратить внимание, что вызов функции обра
ботки parseMap осуществляется с указанием объекта
mapManager. Для обращения к полям и функциям теку
щего объекта принято использовать указатель this, заре
зервированное ключевое слово (пример использования:
this.mapData). В данном случае функция принадлежит объ
екту mapManager, но использовать указатель this нельзя,
так как функция onreadystatechange будет вызвана не
в контексте mapManager и this будет указывать не на
mapManager, а на глобальный объект window. Это одна из
особенностей, отличающих JavaScript от других объект
ноориентированных языков программирования.
function parseMap(tilesJSON) {
this.mapData = JSON.parse(tilesJSON); // ðàçîáðàòü JSON
this.xCount = this.mapData.width; // ñîõðàíåíèå øèðèíû
this.yCount = this.mapData.height; // ñîõðàíåíèå âûñîòû
this.tSize.x = this.mapData.tilewidth; // ñîõðàíåíèå ðàçìåðà áëîêà
this.tSize.y = this.mapData.tileheight; // ñîõðàíåíèå ðàçìåðà áëîêà
this.mapSize.x = this.xCount * this.tSize.x; // âû÷èñëåíèå ðàçìåðà
// êàðòû
this.mapSize.y = this.yCount * this.tSize.y; // âû÷èñëåíèå ðàçìåðà
// êàðòû
for (var i = 0; i < this.mapData.tilesets.length; i++) {
var img = new Image(); // ñîçäàåì ïåðåìåííóþ äëÿ õðàíåíèÿ
// èçîáðàæåíèé
img.onload = function () { // ïðè çàãðóçêå èçîáðàæåíèÿ
mapManager.imgLoadCount++; // óâåëè÷èâàåì ñ÷åò÷èê
if (mapManager.imgLoadCount ===
mapManager.mapData.tilesets.length) {
32
Глава 2
mapManager.imgLoaded = true; // çàãðóæåíû âñå
// èçîáðàæåíèÿ
}
}; // êîíåö îïèñàíèÿ ôóíêöèè onload
img.src = this.mapData.tilesets[i].image; // Çàäàíèå ïóòè ê
// èçîáðàæåíèþ
var t = this.mapData.tilesets[i]; // çàáèðàåì tileset èç êàðòû
var ts = { // ñîçäàåì ñâîé îáúåêò tileset
firstgid: t.firstgid, // firstgid - ñ íåãî íà÷èíàåòñÿ íóìåðàöèÿ â
// data
image: img, // îáúåêò ðèñóíêà
name: t.name, // èìÿ ýëåìåíòà ðèñóíêà
xCount: Math.floor(t.imagewidth / mapManager.tSize.x),
// ãîðèçîíòàëü
yCount: Math.floor(t.imageheight / mapManager.tSize.y)
// âåðòèêàëü
}; // êîíåö îáúÿâëåíèÿ îáúåêòà ts
this.tilesets.push(ts); // ñîõðàíÿåì tileset â ìàññèâ
} // îêîí÷àíèå öèêëà for
this.jsonLoaded = true; // true, êîãäà ðàçîáðàëè âåñü json
}
Функция parseMap должна быть объявлена в рамках
mapManager. Она принимает один параметр tilesJSON,
при написании функции loadMap был приведен пример
вызова tilesJSON.
this.mapData = JSON.parse(tilesJSON);
В JavaScript есть встроенный объект JSON, в програм
ме использована функция parse, которая превращает стро
ку (tilesJSON), прочитанную из файла, в объект JavaScript.
Полученный объект сохраняется в поле mapData теку
щего объекта (this). Следует отметить, что в данной строч
ке указание this является обязательным, так как иначе
JavaScript будет интерпретировать обращение к перемен
ной как к локальной переменной функции, а не как обра
щение к полю объекта. Соответственно, при необходимо
сти обращения к полю объекта следует либо указать клю
чевое слово this, либо имя объекта.
Следующие две строчки инициализируют xCount и
yCount из полей mapData.width и mapData.height, затем
Отображение карты игры
33
инициализируются ширина и высота блока в поле tSize на
основании полей tilewidth и tileheight объекта mapData.
Размер карты mapSize, ширина и высота, вычисляют
ся простыми арифметическими операциями.
Затем описан цикл for по всем объектам tilesets. С каж
дым набором блоков связано изображение, поэтому созда
ется переменная для хранения изображения:
var img = new Image();
Изображения могут быть большими, их может быть
много, поэтому необходимо считать, сколько изображе
ний загружено, чтобы не было попытки отобразить карту
до загрузки всех изображений. Кроме того, необходимо
контролировать, что описание JSON для карты уже за
гружено и проанализировано. Для дальнейшей работы рас
ширяем описание объекта mapManager, созданного в па
раграфе 2.1. В объект mapManager добавляются следую
щие поля:
var mapManager = {
,
imgLoadCount: 0, // êîëè÷åñòâî çàãðóæåííûõ èçîáðàæåíèé
imgLoaded: false, // âñå èçîáðàæåíèÿ çàãðóæåíû (ñíà÷àëà - false)
jsonLoaded: false // json îïèñàíèå çàãðóæåíî (ñíà÷àëà - false)
}
На месте многоточия в mapManager находятся все пре
дыдущие поля.
В функции onload изображения увеличиваем счетчик
количества загруженных изображений на единицу:
mapManager.imgLoadCount++;
Затем проверяем все ли изображения загружены:
if (mapManager.imgLoadCount ===
mapManager.mapData.tilesets.length)
Здесь следует обратить внимание на три знака «=». Это
не опечатка, в JavaScript тройное равенство означает срав
нение с учетом типа объекта. Если равенство верно, то все
изображения загружены:
mapManager.imgLoaded = true;
34
Глава 2
Затем в поле src сохраняем путь до изображения:
img.src = this.mapData.tilesets[i].image;
Здесь tilesets[i] — обращение к iму элементу массива.
Затем создаем временную переменную для хранения tileset:
var t = this.mapData.tilesets[i];
В общем случае эта переменная нужна исключитель
но для сокращения записи и упрощения читаемости кода.
В частности, если создать ее до записи в src пути до изоб
ражения, то путь можно было бы сохранить, обратившись
к полю t.image.
Затем создается новый объект ts, в котором сохра
няются номер, с которого начинается нумерация в data
(firstid), рисунок (image), имя рисунка (name), вычисля
ется количество блоков по горизонтали (xCount) и вертика
ли (yCount). Для вычисления количества блоков использо
ван встроенный объект Math, который предоставляет мно
жество математических функций. В частности, Math.floor()
обеспечивает округление аргумента до меньшего целого
числа.
this.tilesets.push(ts);
Созданный объект ts командой push помещается в ко
нец массива описаний блоков карты mapManager. Затем
осуществляется переход к следующему элементу массива
в цикле for.
По окончании цикла for выполняется команда:
this.jsonLoaded = true;
В переменной jsonLoaded сохраняется информация,
что JSON из файла успешно загружен.
Следующая задача — отображение на холсте загружен
ной карты.
function draw(ctx) { // íàðèñîâàòü êàðòó â êîíòåêñòå
// åñëè êàðòà íå çàãðóæåíà, òî ïîâòîðèòü ïðîðèñîâêó ÷åðåç 100
// ìñåê
if (!mapManager.imgLoaded || !mapManager.jsonLoaded) {
setTimeout(function () { mapManager.draw(ctx); }, 100);
Отображение карты игры
35
} else {
if(this.tLayer === null) // ïðîâåðèòü, ÷òî tLayer íàñòðîåí
for (var id = 0; id < this.mapData.layers.length; id++) {
// ïðîõîäèì ïî âñåì layer êàðòû
var layer = this.mapData.layers[id];
if (layer.type === "tilelayer") { // åñëè íå tilelayer -
// ïðîïóñêàåì
this.tLayer = layer;
break;
}
} // Îêîí÷àíèå öèêëà for
for (var i = 0; i < this.tLayer.data.length; i++) { // ïðîéòè ïî âñåé
// êàðòå
if (this.tLayer.data[i] !== 0) { // åñëè íåò äàííûõ - ïðîïóñêàåì
var tile = this.getTile(this.tLayer.data[i]); // ïîëó÷åíèå áëîêà
// ïî èíäåêñó
// i ïðîõîäèò ëèíåéíî ïî ìàññèâó, xCount - äëèíà ïî õ
var pX = (i % this.xCount) * this.tSize.x; // âû÷èñëÿåì õ â
// ïèêñåëàõ
var pY = Math.floor(i / this.xCount) * this.tSize.y;
// âû÷èñëÿåì ó
// ðèñóåì â êîíòåêñò
ctx.drawImage(tile.img, tile.px, tile.py, this.tSize.x,
this.tSize.y, pX, pY, this.tSize.x, this.tSize.y);
}
} // Îêîí÷àíèå öèêëà for
} // Îêîí÷àíèå if-else
}
Функция draw предназначена для отображения кар
ты на холсте, контекст (ctx) ей передается в качестве па
раметра.
if (!mapManager.imgLoaded || !mapManager.jsonLoaded)
В первом условии (if) функции draw проверяется, что
изображения и JSON загружены. Восклицательный знак
в данном случае означает отрицание, а двойная вертикаль
ная черта — логическое «ИЛИ». Соответственно, если ус
пешно загружены и изображения и JSON, то осуществля
ется переход к else.
setTimeout(function () { mapManager.draw(ctx); }, 100);