https://habrahabr.ru/post/330174/- Разработка игр
- JavaScript
- Canvas
Здравствуй, Хабр!
Совсем недавно разбирая графический движок Pixi.js было обнаружено, что по нему практически нет обучающего материала на русском языке. И хоть все разработчики поголовно должны знать английский, вводный урок на родном языке, вряд ли сильно навредит. Мы будем писать простейшую мини-игру, суть которой уничтожать шарики, до того как они упали на землю. Вот что у нас получится в конечном итоге:
Итак, вкратце о движке. Pixi.js — это 2D фреймворк с поддержкой WebGL. Авторы фреймворка утверждают, что движок можно использовать для создания любой графики на странице, но первое, что приходит на ум видя его возможности — это разработка игр. Главные преимущества движка, это доступный API и конечно же, скорость. Вот для примера, известные в узких кругах зайчики, для оценки производительности:
www.goodboydigital.com/pixijs/bunnymark
Пожалуй, приступим к написанию игры.
В первую очередь скачиваем библиотеку.
Pixi можно скачать с официального сайта, вот
ссылка. Есть возможность подключить библиотеку с помощью CDN. И так же доступно скачивание с помощью npm.
я буду устанавливать с помощью последнего варианта. Открываем папку с проектом в консоли и пишем:
npm install pixi.js
Ждем когда установятся все пакеты и после этого, как это обычно бывает, создаем файл index.html и main.js
подключаем в шапку index.html наш фреймворк. В зависимости от способа установки, будут разные source. Если вы устанавливали с библиотеку с помощью npm путь будет такой:
node_module/pixi.js/dist/pixi.js
Сбрасываем стили браузера, я делаю это для собственного удобства(это можно упустить), подключаем main.js в тело страницы и начинаем писать.
В первую очередь нужно создать наш холст, в pixi это делается с помощью одной команда.
Итак, создаем глобальный объект model(в котором будут хранится все генерируемые объекты) и внутри пишем свойство createCanvas, которое будет создавать холст. В нем пишем функцию которая создает сам холст и вторая, очень важная команда(позже я напишу, чем она так важна) выводит это холст в тело страницы. Выглядит это следующим образом(у меня игра будет на всю страницу, поэтому сверху у меня параметры высоты и ширины страницы пользователя):
var width = window.innerWidth; //получаем ширину экрана
var height = window.innerHeight; // получаем высоту экрана
var app; //создаем глобальную переменную нашей игры
var model = {
createCanvas: function() {
app = new PIXI.Application(width, height); //создаем холст
document.body.appendChild(app.view); //выводим его в тело страницы
}
}
если вы все сделали правильно, то при вызове из консоли браузера:
model.createCanvas();
У вас сгенерируется canvas на всю ширину страницы. Сразу создадим объект view, в котором будет функция которая выводит нашу игру на экран:
var view = {
loadGame: function(){
model.createCanvas();
}
}
view.loadGame(); //запускаем игру
Следующий объект в модели — это шарик, который будет рандомно генерироваться вверху страницы и падать вниз. Для этого в модели создаем новое свойство(функцию), которая будет генерировать тот самый шарик. И создаем объект controller, в котором будет событие, которое будет происходить при клике на шарик. В нашем случае шарик должен исчезать.
Вот как разросся наш код(В комментариях я указал, что делает каждая строка):
var width = window.innerWidth; //получаем ширину экрана
var height = window.innerHeight; // получаем высоту экрана
var app; //создаем глобальную переменную нашей игры
var colors = [0xFFFF0B, 0xFF700B, 0x4286f4, 0x4286f4, 0xf441e8, 0x8dff6d, 0x41ccc9, 0xe03375, 0x95e032, 0x77c687, 0x43ba5b, 0x0ea3ba]; //массив цветов, 0x вместо #
var model = {
createCanvas: function() {
app = new PIXI.Application(width, height); //создаем холст
document.body.appendChild(app.view); //выводим его в тело страницы
},
drawCircle: function() {
rand = Math.floor(Math.random() * colors.length); //генерим рандомное число(в промежутке от 0 до количества цветов в массиве цветов)
var radius = 50; //радиус круга
var inAreaX = width - 100; //возможные координаты по оси X, которые может занимать круг, ширина страницы минус его диаметр
var circleY = -50; //круг должен создаваться за пределами холста(чтобы глянуть, отрисовался ли круг, измените отрицательное значение на положительное)
var circleX = Math.floor(Math.random()* inAreaX); //создаем круг в рандомном месте по оси X
var circle = new PIXI.Graphics(); //создаем новый графический элемент
circle.lineStyle(0); //начинаем рисовать
circle.beginFill(colors[rand], 1); //задаем рандомный цвет
circle.drawCircle(circleX, circleY, radius); //рисуем кружок, ведь он наш дружок
circle.endFill(); //закончили отрисовку
circle.interactive = true; //делаем круг интерактивным
circle.buttonMode = true; //меняем курсор при наведении
app.stage.addChild(circle); //выводим круг на холсте
circle.on('pointerdown', controller.clearFigure); //добавляем возможность при клике на фигуру удалить её
}
}
var view = {
loadGame: function() {
model.createCanvas();
model.drawCircle();//отрисовываем кружок, пока один раз
}
}
var controller = {
clearFigure: function(){
this.clear(); //удаляем фигуры по которой кликнули
}
}
view.loadGame();
app.stage.addChild(circle);
— это очень важная команда в Pixi, так как в этом фреймворке, чтобы на холсте что-то появилось, кроме создания объекта, его нужно обязательно вывести. В 70% процентах случаев, если вы все сделали правильно, а объект на холсте не отображается, то скорее всего вы забыли его вывести с помощью этой команды.
Далее.
Теперь добавим гравитацию, чтобы шарики падали и заодно сделаем чтобы эти шарики появлялись каждые пол секунды.
Для этого в начале страницы добавляем переменную gravity(сразу после массива colors), которая отвечает за гравитацию, по умолчанию ставим силу притяжение 4. Так же добавляем переменную figuresAmount с значение 0(количество фигур при запуске игры) и создаем пустой массив figure, куда мы будем отправлять все ново созданные шарики. В функции drawCircle добавляем два действия(я не буду вставлять весь код, только строку предшествующую новонаписанному, и строку которая была написана ранее и будет после новонаписанного):
var colors = [0xFFFF0B, 0xFF700B, 0x4286f4, 0x4286f4, 0xf441e8, 0x8dff6d, 0x41ccc9, 0xe03375, 0x95e032, 0x77c687, 0x43ba5b, 0x0ea3ba]; //массив цветов
var gravity = 4;
var figuresAmount = -1; //количество созданных фигур(не ноль, потому как с нуля мы начинаем считать фигуры)
var figure = []; //массив хранящий нашу фигуру
{
— наши добавленные переменные.
И новые действия в функции drawCircle:
circle.buttonMode = true; //меняем курсор при наведении
figuresAmount++; //увеличиваем количество созданных шариков
figure.push(circle); //обратиться на прямую к объекту circle мы не можем, поэтому отправляем его в массив
app.stage.addChild(circle); //выводим круг на холсте
Ну и во view.loadGame добавляем отрисовку шарика каждую секунду, сразу после первой отрисовки и запускаем функцию, которая постоянно обновляет холст с внесением изменений. В Pixi за это отвечает такая цепочка:
app.ticker.add();
у нас так:
model.drawCircle(); //рисуем круг в первый раз
setInterval(model.drawCircle, 500); //рисуем шарик каждые пол секунды
app.ticker.add(function() { //постоянное обновление холста
for (var i = 0; i < figuresAmount; i++) {
figure[i].position.y += gravity; //заставляем гравитацию работать
}
});
} //закрываем функцию loadGame();
Теперь шарики начинают падать.
Осталось добавить проверку столкновений с землей(нижней границей холста) и вывести на экран строку Game Over.
Для этого нужно в первую очередь для нашего шарика создать два состояния, существует он или уничтожен. Внутри drawCircle добавляем новое свойство circle.live, которое по умолчанию true(когда мы только создали шарик, по другому быть и не может), так же нужно задать ему порядковые номер, чтобы при попадании по шарику именно тот шарик в который мы попали стал false:)
Для этого у нас есть переменная figuresAmount, которая увеличивается при каждом новом шарике. В общем пишем в drawCircle:
circle.buttonMode = true; //меняем курсор при наведении
circle.live = true; //указываем что наш шарик жив и не пал жертвой выстрела
figuresAmount++;
circle.num = figuresAmount; //даем нашему кругу порядковый номер
figure.push(circle); //обратиться на прямую к объекту circle мы не можем, поэтому отправляем его в массив
Далее создаем функцию в модели которая выводит текст(что да как в комментариях):
gameOver: function() {
var style = new PIXI.TextStyle({ //стили для текста
fill: '0xffffff',
fontSize: 36,
});
var gameOverText = new PIXI.Text('Game Over', style); //собственно выводимый текст
gameOverText.x = width / 2; //центрируем относительно экрана
gameOverText.y = height / 2; //центрируем относительно экрана
gameOverText.pivot.x = 50; //выравниваем по оси х
gameOverText.pivot.y = 50; // выравниваем по оси y
app.stage.addChild(gameOverText); //выводим на холсте
}
в clearFigure указываем, что при каждом попадании по шарику, состояние circle.live меняется на false. Мы делаем это действие по той простой причине, что функция clear() не удаляет объект, а просто стирает его сanvasa(по сути шарик продолжает падать, поэтому надо указать что этот шарик уничтожен и его можно пропустить никак не реагируя).
Пример кода:
clearFigure: function() {
this.clear();
figure[this.num].live = false;
}
И запускаем проверку столкновения и вызов gameOver в случае необходимости при каждом обновлении сцены:
app.ticker.add(function() { //постоянное обновление холста
for (var i = 0; i < figuresAmount; i++) {
figure[i].position.y += gravity; //заставляем гравитацию работать
if (figure[i].position.y > height && figure[i].live == true) {//проверяет столкнулся ли шарик с низом страницы и если он жив, не пропускает его, а отменяет выводит на экран "игра окончена и завершает действие гравитации"
model.gameOver();
return false;
}
}
На этом все, надеюсь я ничего не забыл. Если есть какие-то ошибки, то можно свериться с примером на codepen. Пишите в комментариях об ошибках, поправлю.
Надеюсь после прочтения этой статьи изучение Pixi.js станет немного проще.
Позже я расскажу, как вывести подсчет очков на экран и сделать анимацию при попадании по шарику.
Всем спасибо!