Файл: Беляев С А - Разработка игр на языке JavaScript - 2016.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Программирование

Добавлен: 25.10.2018

Просмотров: 7592

Скачиваний: 136

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Отображение карты игры

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) {


background image

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, затем


background image

Отображение карты игры

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;


background image

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);


background image

Отображение карты игры

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);