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

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

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

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

Добавлен: 25.10.2018

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

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

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

Отображение объектов

51

Возвращается созданный и настроенный объект.

var Player = Entity.extend({ lifetime: 100 });

Создается новая переменная Player путем вызова функ

ции extend у объекта Entity, при этом в качестве парамет
ра передается объект, содержащий одно поле lifetime со
значением равным 100.

Способ 3 позволяет не только создавать объекты, рас

ширяя поля и функции, он также позволяет для всех
объектов, созданных на основании Entity, использовать
функцию extend для расширения, т. е. можно построить
целую иерархию объектов, каждый из которых расширя
ет предыдущий, при этом не требуется писать дополни
тельный программный код. Однако нужно иметь в виду,
что в зависимости от реализации функция extend либо
будет перезаписывать поля и функции, либо будет только
добавлять новые.

В данном учебном пособии будет использован способ 3

для создания объектов.

Для выбора способа решения задачи «наследования»

предполагалось, что объект Player содержит только одно
поле lifetime. Рассмотрим, какими дополнительными свой
ствами должен обладать игрок.

У игрока должно быть определено направление движе

ния. Игра двумерная, поэтому должно использоваться две
координаты вектора движения (move_xmove_y). В дан
ном пособии будет рассмотрен случай, когда каждая ко
ордината вектора движения может принимать значения
только –1, 0 или 1, при этом только одна из них может
быть не нулевой. Предложенное решение можно допол
нить, при этом разработчику нужно будет решить следую
щие задачи:

· в предложенном варианте решения при нажатии на

клавишу изменения направления движения будет вы
полнен разворот на 90

° (глава 4), для плавного поворо

та нужно будет определить правила поворота и пере
счет направления вектора движения;

· в предложенном варианте решения вектор движения

всегда нормирован (его длина либо равна 0, либо 1),


background image

52

Глава 3

при плавном повороте угол наклона будет меняться
плавно и нужно будет с учетом правила треугольника
нормировать длину вектора;

· в предложенном варианте решения заранее подготов

лены рисунки движения объектов в четырех направле
ниях (влево, вправо, вверх и вниз), при плавном пово
роте необходимо будет повернуть рисунок на заданный
угол и изменить правила вычисления границ рисунка
(например, для определения попадания ракеты в танк,
если разработчик создает двумерную игру в танки).
Кроме направления движения должна быть задана ско

рость движения (speed). Для отображения объекта нужна
функция отображения (draw), для изменения состояния
на каждом шаге — функция обновления (update), для
уничтожения объекта — функция уничтожения (kill),
если объект умеет стрелять — функция выстрела (fire),
если объект уничтожается касанием с другим объектом —
функция касания (onTouchEntity). В итоге получается
описание:
var Player = Entity.extend({

lifetime: 100,

move_x: 0, move_y: 0, // íàïðàâëåíèå äâèæåíèÿ

speed: 1, // ñêîðîñòü îáúåêòà

draw: function (ctx) { … }, // ïðîðèñîâêà îáúåêòà

update: function () { … }, // îáíîâëåíèå â öèêëå

onTouchEntity: function(obj) { … }, // îáðàáîòêà âñòðå÷è

// ñ ïðåïÿòñòâèåì

kill: function() { … }, // óíè÷òîæåíèå îáúåêòà

fire: function() { … } // âûñòðåë

});

В приведенном фрагменте программного кода много

точием скрыта реализация конкретных функций. Следует
обратить внимание, что функция draw принимает в каче
стве параметра переменную ctx, которая хранит контекст
холста, а функция onTouchEntity принимает в качестве
параметра объект, с которым осуществляется касание, так
как реакция может отличаться в зависимости от того, ка
кого объекта коснулся игрок. Из перечисленных функций


background image

Отображение объектов

53

в данной главе будет приведена реализация только draw,
реализация остальных — в главе 5.

Предположим, что в качестве оппонентов игроку выс

тупают танки, тогда каждый из них может быть реализо
ван объектом:

var Tank = Entity.extend({

lifetime: 100,

move_x: 0, move_y: -1, // íàïðàâëåíèå äâèæåíèÿ

speed: 1, // ñêîðîñòü îáúåêòà

draw: function (ctx) { … }, // ïðîðèñîâêà îáúåêòà

update: function () { … }, // îáíîâëåíèå â öèêëå

onTouchEntity: function(obj) { … }, // îáðàáîòêà âñòðå÷è

// ñ ïðåïÿòñòâèåì

kill: function() { … }, // óíè÷òîæåíèå îáúåêòà

fire: function() { … } // âûñòðåë

});

С учетом особенностей реализации функции extend,

несмотря на очень большую схожесть полей и функций,
для  Tank целесообразно расширять не объект Player, а
объект Entity. Из перечисленных функций в данной главе
будет приведена реализация только draw и fire.

Предположим, что в качестве оружия будут использо

ваться ракеты, тогда их можно реализовать с применени
ем такого объекта:

var Rocket = Entity.extend({

move_x: 0, move_y: 0, // íàïðàâëåíèå äâèæåíèÿ

speed: 4, // ñêîðîñòü îáúåêòà

draw: function (ctx) { … }, // ïðîðèñîâêà îáúåêòà

update: function () { … }, // îáíîâëåíèå â öèêëå

onTouchEntity: function(obj) { … }, // îáðàáîòêà âñòðå÷è

// ñ ïðåïÿòñòâèåì

onTouchMap: function(idx) { … }, // îáðàáîòêà âñòðå÷è ñî ñòåíîé

kill: function() { … } // óíè÷òîæåíèå îáúåêòà

});

Рассмотрим отличия Rocket от Player и Tank. Кроме

того, что скорость ее движения (speed) в 4 раза больше,
появился дополнительный метод onTouchMap, который


background image

54

Глава 3

должен уничтожить ракету, если она попала в препят
ствие. В качестве параметра она принимает индекс блока
карты, которого она коснулась.

Естественно, если мы можем с помощью какогото

объекта уменьшить здоровье у нашего игрока, значит для
баланса должна быть возможность какимто образом его
восполнить. Для этого можно создать объект:
var Bonus = Entity.extend({

draw: function (ctx) { … }, // ïðîðèñîâêà îáúåêòà

kill: function() { … } // óíè÷òîæåíèå îáúåêòà

});

Особенность данного объекта в том, что он умеет ото

бражаться (draw) и умеет уничтожаться (kill), а вся логи
ка по восполнению жизненных сил (lifetime) возлагается
на метод onTouchEntity игрока.

Рассмотрим вариант реализации функции fire объек

та Player.
function fire() {

var r = Object.create(Rocket);

r.size_x = 32; // íåîáõîäèìî çàäàòü ðàçìåðû ñîçäàâàåìîìó

// îáúåêòó

r.size_y = 32;

r.name = "rocket" + (++gameManager.fireNum); // èñïîëüçóåòñÿ

// ñ÷åò÷èê âûñòðåëîâ

r.move_x = this.move_x;

r.move_y = this.move_y;

switch (this.move_x + 2 * this.move_y) {

case -1: // âûñòðåë âëåâî

r.pos_x = this.pos_x - r.size_x; // ïîÿâèòüñÿ ñëåâà îò èãðîêà

r.pos_y = this.pos_y;

break;

case 1: // âûñòðåë âïðàâî

r.pos_x = this.pos_x + this.size_x; // ïîÿâèòüñÿ ñïðàâà

// îò èãðîêà

r.pos_y = this.pos_y;

break;

case -2: // âûñòðåë ââåðõ

r.pos_x = this.pos_x;

r.pos_y = this.pos_y - r.size_y; // ïîÿâèòüñÿ ñâåðõó îò èãðîêà

break;


background image

Отображение объектов

55

case 2: // âûñòðåë âíèç

r.pos_x = this.pos_x;

r.pos_y = this.pos_y + this.size_y; // ïîÿâèòüñÿ ñíèçó îò èãðîêà

break;

default: return;

}

gameManager.entities.push(r);

}

Предлагаемая реализация функции fire может вызы

ваться произвольное число раз и не имеет задержки меж
ду выстрелами, при этом предполагается использование
массива entities менеджера игры (gameManager), который
будет описан в 6 главе, и счетчика выстрелов fireNum,
который нужен только для того, чтобы создавать уникаль
ные идентификаторы для объектов.

var r = Object.create(Rocket);

Создается переменная r, в которую сохраняется новый

экземпляр объекта Rocket. Следующие две строчки зада
ют размеры объекту 32

´32.

r.name = "rocket" + (++gameManager.fireNum);

Объекту  name присваивается имя «rocket», за кото

рым будет следовать уникальный идентификатор благо
даря счетчику fireNum менеджера игры. Сочетание «++»
обеспечивает увеличение счетчика перед каждым обраще
нием к нему.

Данные две строки присваивают объекту r то же на

правление, что у игрока: r.move_x = this.move_x; r.move_y
= this.move_y.

Переключатель switch обеспечивает вычисление зна

чения, передаваемого ему в качестве параметра, а затем
вызов соответствующего варианта case. Каждый case за
канчивается командой break, обеспечивающей выход из
switch. В данном случае всего четыре варианта: влево (–1),
вправо (1), вверх (–2), вниз (2). Если ни один из вариантов
не выполняется, то switch перейдет к значению по умол
чанию (default), который обеспечит выход из метода без
сохранения созданного объекта r. При этом следует иметь