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

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

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

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

Добавлен: 25.10.2018

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

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

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

36

Глава 2

Встроенная функция setTimeout принимает два пара

метра: первый — функция, которая будет вызвана после
заданной задержки, второй — задержка в миллисекундах.
В данном примере через 100 мс будет повторно вызвана
функция draw с тем же параметром.

if(this.tLayer === null)

При создании объекта tLayer присвоено значение null,

при первом обращении к draw данное условие будет верно.

for (var id = 0; id < this.mapData.layers.length; id++)

Цикл по массиву слоев в mapData.

var layer = this.mapData.layers[id];

Для сокращения записи создаем дополнительную пе

ременную layer.

if (layer.type === "tilelayer")

Если тип layer соответствует слою блоков карты, то

сохраняем его в tLayer и с использованием ключевого сло
ва break прерываем выполнение цикла.

for (var i = 0; i < this.tLayer.data.length; i++)

Цикл for по всем данным, предназначенным для ото

бражения на карте.

Если this.tLayer.data[i] равен нулю, то ничего делать

не нужно.

var tile = this.getTile(this.tLayer.data[i]);

С помощью функции getTile, которая будет описана

ниже, по номеру блока получаем из массива tilesets объект
блока и сохраняем его в переменной tile.

Следующие две строки позволяют вычислить pX  и

pY — координаты блока в пикселах. Символ «%» обозна
чает вычисление остатка от деления двух чисел. Индекс i
проходит последовательно по всем элементам массива data
(в п. 2.1 был описан принцип хранения информации в этом
массиве). Значение pX вычисляется как остаток от деле
ния индекса i на количество элементов в строке (xCount),
для перевода в пикселы выполняется умножение на ши


background image

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

37

рину в пикселах (tSize.x). Значение pY вычисляется как
наименьшее целое (Math.floor) от деления i на количество
элементов в строке (xCount), для перевода в пикселы вы
полняется умножение на высоту в пикселах (tSize.y).
ctx.drawImage(tile.img, tile.px, tile.py, this.tSize.x, this.tSize.y, pX, pY,

this.tSize.x, this.tSize.y);

Для контекста вызывается функция drawImage с рас

ширенным количеством параметров: tile.img — изображе
ние, tile.px и tile.py — координаты блока в изображении,
this.tSize.x и this.tSize.y — ширина и высота блока в изоб
ражении, pX и pY — координаты, где необходимо отобра
зить блок, this.tSize.x и this.tSize.y — размеры отобража
емого блока. Размеры отображаемого блока необходимо
указывать, так как данная функция поддерживает изме
нение масштаба.

Для корректной работы функции draw должна быть

определена функция getTile, обеспечивающая получение
блока по ее индексу из tilesets.

function getTile (tileIndex) { // èíäåêñ áëîêà

var tile = { // îäèí áëîê

img: null, // èçîáðàæåíèå tileset

px: 0, py: 0 // êîîðäèíàòû áëîêà â tileset

};

var tileset = this.getTileset(tileIndex);

tile.img = tileset.image; // èçîáðàæåíèå èñêîìîãî tileset

var id = tileIndex - tileset.firstgid; // èíäåêñ áëîêà â tileset

// áëîê ïðÿìîóãîëüíûé, îñòàòîê îò äåëåíèÿ íà xCount äàåò x

// â tileset

var x = id % tileset.xCount;

// îêðóãëåíèå îò äåëåíèÿ íà xCount äàåò y â tileset

var y = Math.floor(id / tileset.xCount);

// ñ ó÷åòîì ðàçìåðà ìîæíî ïîñ÷èòàòü êîîðäèíàòû áëîêà

// â ïèêñåëàõ

tile.px = x * mapManager.tSize.x;

tile.py = y * mapManager.tSize.y;

return tile; // âîçâðàùàåì áëîê äëÿ îòîáðàæåíèÿ

}

Для отображения блока необходимы изображение, его

координаты в пикселах и размеры. Размеры блоков хра


background image

38

Глава 2

нятся в mapManager, поэтому достаточно создать объект
(tile), который будет хранить три поля: изображение (img)
и координаты блока в изображении в пикселах (px,  py).
var tileset = this.getTileset(tileIndex);

Для получения tileset по индексу (tileIndex) восполь

зуемся функцией getTileset, которая будет описана ниже
в данной главе. Код данной функции не сложен, его мож
но было бы разместить непосредственно в getTile, но он
потребуется для повторного использования, поэтому це
лесообразно его иметь в виде отдельной функции.
tile.img = tileset.image;

Выполняет копирование ссылки на изображение в но

вый объект tile.
var id = tileIndex - tileset.firstgid;

Переменная tileIndex хранит номер блока в общем мас

сиве data, при этом tileset.firstgid хранит номер первого
блока в отображаемом изображении. Вычитание выполня
ется для получения индекса блока в отображаемом tileset.

Для получения координат x и y выполняются уже из

вестные операции по вычислению на основании индекса
блока в изображении. Для получения координат (tile.px,
tile.py) выполняется умножение на размеры блока.
return tile;

В результате возвращается сформированный блок (tile).
Для корректной работы функции getTile необходима

функция getTileset.
function getTileset(tileIndex) { // ïîëó÷åíèå áëîêà ïî èíäåêñó

for (var i = mapManager.tilesets.length - 1; i >= 0; i--)

// â êàæäîì tilesets[i].firstgid çàïèñàíî ÷èñëî,

// ñ êîòîðîãî íà÷èíàåòñÿ íóìåðàöèÿ áëîêîâ

if (mapManager.tilesets[i].firstgid <= tileIndex) {

// åñëè èíäåêñ ïåðâîãî áëîêà ìåíüøå ëèáî ðàâåí èñêîìîìó,

// çíà÷èò ýòîò tileset è íóæåí

return mapManager.tilesets[i];

}

return null; // Âîçâðàùàåòñÿ íàéäåííûé tileset

}


background image

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

39

Создается цикл поиска:

for (var i = mapManager.tilesets.length - 1; i >= 0; i--)

В отличие от предыдущих описанных циклов for в дан

ном цикле поиск осуществляется не по возрастанию ин
декса, а по его убыванию (означает уменьшение значе
ния переменной i на каждом шаге цикла). Поиск нужен
именно в обратном порядке, так как в tilesets[i].firstgid
хранится индекс, с которого начинается нумерация бло
ков, а сами наборы блоков упорядочены по возрастанию
этого индекса. Соответственно, если искомый индекс мень
ше максимального индекса в текущем наборе блоков, то
он в одном из предыдущих наборов блоков.
if (mapManager.tilesets[i].firstgid <= tileIndex)

Если искомый индекс больше начального номера бло

ков в tilesets[i], то именно этот набор блоков нужен, он
возвращается return tileset.
return null;

По окончании, если ничего не найдено, возвращается

null.

Приведенного кода достаточно для создания карты,

которая помещается на холсте. В случае, если карта на
холсте не помещается, необходимо внести дополнитель
ные изменения в код. В частности, потребуется дополни
тельное поле в mapManager, которое будет хранить пара
метры видимой области карты:
var mapManager = {

…,

// âèäèìàÿ îáëàñòü ñ êîîðäèíàòàìè ëåâîãî âåðõíåãî óãëà

view: {x: 0, y: 0, w: 800, h: 600}

}

Поле  view хранит координаты левого верхнего угла

видимой области (xy) и размеры холста (wh), ширину и
высоту. Недостаточно знать только размеры видимой об
ласти, полезно принимать во внимание эту информацию
при отображении, в частности сдвигать отображаемые объ
екты с учетом координат левого верхнего угла и учитывать
размеры холста при отображении. Нет смысла выводить


background image

40

Глава 2

информацию за пределами холста, пользователь все рав
но этого не увидит, а ресурсы компьютера на это будут
расходоваться.

В функцию  draw перед вызовом ctx.crawImage необ

ходимо добавить несколько строк кода:
// íå ðèñóåì çà ïðåäåëàìè âèäèìîé çîíû

if(!this.isVisible(pX, pY, this.tSize.x, this.tSize.y))

continue;

// ñäâèãàåì âèäèìóþ çîíó

pX -= this.view.x;

pY -= this.view.y;

В первой строке вызывается функция isVisible. Она

описана в виде функции, так как потребуется для повтор
ного использования, ее код будет приведен ниже в данной
главе. Функция isVisible принимает в качестве парамет
ров координаты (pXpY) и размеры отображаемого блока
(this.tSize.xthis.tSize.y).

Если isVisible возвращает false, то используется клю

чевое слово continue для перехода к следующему шагу
цикла. В отличие от ключевого слова break, которое пре
рывает выполнение цикла, continue сообщает, что следу
ет проигнорировать весь код до конца цикла, изменить
счетчик цикла и начать выполнение цикла с начала.

Последующие две строчки уменьшают pX и pY с уче

том координат левого верхнего угла. Знак «=» предлагает
уменьшить значение переменной, стоящей слева от него,
на значение выражения, стоящего справа от него. Соот
ветственно, они могут быть переписаны таким образом:
pX = pX - this.view.x;

pY = pY - this.view.y;

Обе записи идентичны. Для корректной работы усо

вершенствованной функции draw необходима isVisible.
function isVisible(x, y, width, height) { // íå ðèñóåì çà ïðåäåëàìè âèäèìîé

// çîíû

if (x + width < this.view.x || y + height < this.view.y ||

x > this.view.x + this.view.w || y > this.view.y + this.view.h)

return false;

return true;

}