Мы используем DOM браузера для графики, и читаем ввод пользователя, обслуживая события клавиатуры.
Код, относящийся к экрану и клавиатуре – небольшая часть работы, которую нам над проделать для создания игры. Так как всё состоит из цветных квадратиков, рисовать это просто: мы создаём элементы DOM и используем стили, чтобы задать им цвет фона, размер и расположение.
Мы представляем фон как таблицу, поскольку это – неизменная решётка из квадратов. Свободно двигающиеся элементы можно накладывать сверху, используя абсолютное позиционирование.
В играх и других интерактивных программах с графической анимацией, которые должны реагировать на действия пользователя без задержки, очень важна эффективность. Хотя DOM не был задуман для вывода высокоскоростной графики, он справляется с этим лучше, чем можно ожидать. В главе 13 вы видели немножко анимации. На современном компьютере такая простая игра идёт неплохо, даже если не сильно мучиться с оптимизацией.
В следующей главе мы изучим другую технологию браузера, тег
, который предоставляет более традиционный способ для рисования, и работает с формами и пикселями вместо элементов DOM.
В главе 7 мы использовали массивы строк для описания двумерной решётки. Мы можем сделать то же и здесь. Это позволит нам разрабатывать уровни без того, чтобы сначала писать редактор уровней.
Простой уровень может выглядеть так:
var simpleLevelPlan = [
" ",
" ",
" x = x ",
" x o o x ",
" x @ xxxxx x ",
" xxxxx x ",
" x!!!!!!!!!!!!x ",
" xxxxxxxxxxxxxx ",
" "
];
Фиксированная решётка и движущиеся элементы включены. Символы x
обозначают стены, пробелы – пустое место, а восклицательные знаки – фиксированная лава.
@
отмечает место, где игрок начинает. o
– монетки, знак равенства =
означает блок движущейся лавы, который двигается по горизонтали туда и сюда. Заметьте, что решётка на этих позициях будет содержать пустое пространство, и для отслеживания позиции этих подвижных элементов используется ещё одна структура данных.
Мы будем поддерживать ещё два вида лавы: вертикальная черта |
— для кусочков, двигающихся по вертикали, и v
для капающей лавы. Она будет двигаться вниз, но не отскакивать обратно, а просто перепрыгивать на начальную позицию по достижению пола.
Игра состоит из нескольких уровней, которые надо закончить. Уровень закончен, когда собраны все монетки. Если игрок касается лавы, текущий уровень возвращается к исходному состоянию, и игрок начинает заново.
Следующий конструктор создаёт объект уровня. Аргументом должен быть массив строк, задающих уровень.
function Level(plan) {
this.width = plan[0].length;
this.height = plan.length;
this.grid = [];
this.actors = [];
for (var y = 0; y < this.height; y++) {
var line = plan[y], gridLine = [];
for (var x = 0; x < this.width; x++) {
var ch = line[x], fieldType = null;
var Actor = actorChars[ch];
if (Actor)
this.actors.push(new Actor(new Vector(x, y), ch));
else if (ch == "x")
fieldType = "wall";
else if (ch == "!")
fieldType = "lava";
gridLine.push(fieldType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(function(actor) {
return actor.type == "player";
})[0];
this.status = this.finishDelay = null;
}
Для краткости код не проверяет входящие данные. Он предполагает, что план уровня допустимый, что там есть стартовая позиция игрока и другие необходимые вещи.
Уровень сохраняет свои ширину и высоту и ещё два массива – один для решётки, и один для движущихся частей. Решётку представляет массив массивов, где каждый вложенный массив представляет горизонтальную линию, а каждый квадрат содержит либо null
для пустых квадратов, либо строку, отражающую тип квадрата – “wall”
или “lava”
.
Массив actors
содержит объекты, отслеживающие положения и состояния динамических элементов. У каждого из них должно быть свойство pos
, содержащее позицию (координаты верхнего левого угла), свойство size
с размером, и свойство type
со строчкой, описывающей его тип ( "lava"
, "coin"
или "player"
).
После построения решётки мы используем метод filter
, чтобы найти объект игрока, хранящийся в свойстве уровня. Свойство status
отслеживает, выиграл игрок или проиграл. Когда это случается, используется finishDelay
, которое держит уровень активным некоторое время для показа простой анимации. (Просто сразу восстанавливать состояние уровня или начинать следующий – это выглядит некрасиво). Этот метод можно использовать, чтобы узнать, закончен ли уровень:
Читать дальше