Создание игры «Space Invaders» на JavaScript с использованием PixiJS.
В современном мире разработки игр создание простых, увлекательных проектов — отличный способ изучить основные концепции программирования и познакомиться с различными инструментами и библиотеками. Одной из таких классических игр, которая часто служит примером при обучении, является «Space Invaders». В этой статье мы подробно рассмотрим, как создать игру «Space Invaders» на языке JavaScript с использованием мощной графической библиотеки PixiJS. Это позволит не только самостоятельно реализовать игровую логику, но и понять, как работать с анимациями, обработкой событий и взаимодействием с пользователем.
PixiJS — это одна из самых популярных 2D GPU-ускоренных библиотек, которая позволяет создавать сложные и плавные визуальные эффекты в браузере. Благодаря простому API и высокой производительности, PixiJS отлично подходит для создания прототипов и полноценных игр. В ходе статьи мы поэтапно создадим игру, начиная с базовой сцены и заканчивая реализацией врагов, выстрелов и системы очков.
Подготовка окружения и знакомство с PixiJS
Перед тем как приступать непосредственно к разработке, необходимо подготовить среду и подключить необходимые библиотеки. PixiJS можно использовать как через CDN, так и устанавливая через npm для более сложных проектов. Для начального этапа подойдет вариант с прямым подключением через тег <script> в HTML.
Основные понятия PixiJS — это сцена (Stage, Container), спрайты (Sprite), текстуры и рендерер. Сцена — контейнер всех объектов, которые должны быть отображены. Спрайт — это объект с изображением, который можно перемещать и анимировать. Рендерер отвечает за вывод изображения на экран.
Рассмотрим простой пример создания приложения PixiJS, чтобы понять структуру проекта:
Пример базовой инициализации PixiJS
const app = new PIXI.Application({
width: 800,
height: 600,
backgroundColor: 0x000000,
});
document.body.appendChild(app.view);
Данный код создаёт игровой холст размером 800 на 600 пикселей с чёрным фоном и добавляет его в тело страницы. После этого можно добавлять спрайты и другие объекты в сцену и запускать игровой цикл.
Создание игрового поля и игрока
Первоочередной задачей станет создание области, где будет разворачиваться геймплей, и визуальное представление игрока — космического корабля. Мы создадим класс Player, который будет отвечать за отображение, движение и свойства игрока.
Для изображения игрока можно использовать простую фигуру или загрузить внешний файл с изображением, например, в формате PNG. Для упрощения возьмём встроенную графику и создадим треугольник, символизирующий корабль, с помощью API PixiJS — графического объекта Graphics.
Код для создания и управления игроком
// Создание объекта игрока
class Player {
constructor(app) {
this.app = app;
this.ship = new PIXI.Graphics();
this.ship.beginFill(0xFFFFFF);
this.ship.moveTo(0, 0);
this.ship.lineTo(40, 20);
this.ship.lineTo(0, 40);
this.ship.endFill();
this.ship.x = app.view.width / 2 - 20;
this.ship.y = app.view.height - 50;
app.stage.addChild(this.ship);
this.speed = 5;
// Инициализация флагов движения
this.moveLeft = false;
this.moveRight = false;
this.bindEvents();
}
bindEvents() {
window.addEventListener('keydown', e => {
if (e.code === 'ArrowLeft') this.moveLeft = true;
if (e.code === 'ArrowRight') this.moveRight = true;
});
window.addEventListener('keyup', e => {
if (e.code === 'ArrowLeft') this.moveLeft = false;
if (e.code === 'ArrowRight') this.moveRight = false;
});
}
update() {
if (this.moveLeft && this.ship.x > 0) {
this.ship.x -= this.speed;
}
if (this.moveRight && this.ship.x < this.app.view.width - 40) {
this.ship.x += this.speed;
}
}
}
Данный класс отвечает за создание корабля, движение влево и вправо с помощью стрелок клавиатуры и ограничение перемещения по краям игрового поля. В дальнейшем мы добавим методы для выстрелов.
Враги и их поведение
В игре "Space Invaders" противниками являются ряды вражеских инопланетян, которые движутся горизонтально с периодическим спуском вниз. Для создания врагов также можно использовать либо спрайты с текстурами, либо графику. Для демонстрации реализуем их с помощью простых квадратов, окрашенных в зелёный цвет.
Особенность врагов — групповой паттерн движения: одновременно все враги сдвигаются вправо до края, затем вниз и влево, и так далее. Также потребуется проверка столкновений с выстрелами игрока и удаление уничтоженных врагов.
Класс врага и группа врагов
class Enemy {
constructor(x, y, app) {
this.app = app;
this.sprite = new PIXI.Graphics();
this.sprite.beginFill(0x00FF00);
this.sprite.drawRect(0, 0, 30, 30);
this.sprite.endFill();
this.sprite.x = x;
this.sprite.y = y;
app.stage.addChild(this.sprite);
this.isAlive = true;
}
destroy() {
this.app.stage.removeChild(this.sprite);
this.isAlive = false;
}
}
class EnemyGroup {
constructor(app) {
this.app = app;
this.enemies = [];
this.speedX = 1;
this.speedY = 10;
this.moveDirection = 1; // 1 - вправо, -1 - влево
this.createEnemies();
}
createEnemies() {
const rows = 4;
const cols = 10;
const startX = 50;
const startY = 50;
const spacing = 40;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const enemy = new Enemy(startX + col * spacing, startY + row * spacing, this.app);
this.enemies.push(enemy);
}
}
}
update() {
// Проверяем необходимость изменить направление движения
let shouldChangeDirection = false;
for (let enemy of this.enemies) {
if (!enemy.isAlive) continue;
if (enemy.sprite.x + enemy.sprite.width >= this.app.view.width && this.moveDirection > 0) {
shouldChangeDirection = true;
}
if (enemy.sprite.x <= 0 && this.moveDirection < 0) {
shouldChangeDirection = true;
}
}
if (shouldChangeDirection) {
this.moveDirection *= -1;
for (let enemy of this.enemies) {
if (enemy.isAlive) enemy.sprite.y += this.speedY;
}
} else {
for (let enemy of this.enemies) {
if (enemy.isAlive) enemy.sprite.x += this.speedX * this.moveDirection;
}
}
}
}
В данном коде представлен класс Enemy, создающий отдельного врага и метод destroy для удаления из сцены. Класс EnemyGroup управляет всей группой врагов и реализует логику движения и смены направления при достижении границ игрового поля.
Реализация выстрелов и столкновений
Для полноценной игры необходимо реализовать возможность стрелять по врагам и обрабатывать столкновения пуль с ними. Мы создадим класс Bullet, который будет представлять выстрел игрока. Пуля будет двигаться вверх с постоянной скоростью и уничтожал врага при попадании.
Обработка столкновений проще всего осуществляется с помощью проверки пересечения прямоугольных областей (bounding box collision). Если прямоугольники пули и врага пересекаются, можно считать, что произошло попадание.
Класс Bullet и проверка столкновений
class Bullet {
constructor(x, y, app) {
this.app = app;
this.sprite = new PIXI.Graphics();
this.sprite.beginFill(0xFFFF00);
this.sprite.drawRect(0, 0, 5, 15);
this.sprite.endFill();
this.sprite.x = x;
this.sprite.y = y;
app.stage.addChild(this.sprite);
this.speed = 7;
this.isAlive = true;
}
update() {
this.sprite.y -= this.speed;
if (this.sprite.y < 0) {
this.destroy();
}
}
destroy() {
this.app.stage.removeChild(this.sprite);
this.isAlive = false;
}
}
// Проверка столкновения 2 прямоугольников
function isCollision(rect1, rect2) {
return !(
rect1.x + rect1.width < rect2.x ||
rect1.x > rect2.x + rect2.width ||
rect1.y + rect1.height < rect2.y ||
rect1.y > rect2.y + rect2.height
);
}
Класс Bullet создаёт жёлтый прямоугольник, который движется вверх, и удаляется, когда покидает поле видимости. Функция isCollision проверяет, пересекаются ли два объекта, основываясь на их координатах и размерах.
Объединение всех компонентов и игровой цикл
После реализации отдельных компонентов приступим к объединению их в одну игру. Для этого добавим в главный скрипт создание экземпляров Player, EnemyGroup и массив пуль. Реализуем управление выстрелами игрока — по нажатию пробела будет создаваться новая пуля из центра корабля.
Основной игровой цикл — функция update, вызываемая при помощи requestAnimationFrame через PIXI.Application.ticker, — будет обновлять положение игрока, врагов и пуль, а также проверять столкновения. Если пуля попадает во врага, последний уничтожается, а пуля удаляется.
Общий код игрового цикла и обработчиков событий
const app = new PIXI.Application({
width: 800,
height: 600,
backgroundColor: 0x000000,
});
document.body.appendChild(app.view);
const player = new Player(app);
const enemies = new EnemyGroup(app);
const bullets = [];
window.addEventListener('keydown', e => {
if (e.code === 'Space') {
// Создание новой пули из центра корабля
const bulletX = player.ship.x + 20 - 2.5; // центр корабля минус половина ширины пули
const bulletY = player.ship.y;
const bullet = new Bullet(bulletX, bulletY, app);
bullets.push(bullet);
}
});
app.ticker.add(() => {
player.update();
enemies.update();
// Обновление пуль
for (let i = bullets.length - 1; i >= 0; i--) {
const bullet = bullets[i];
if (!bullet.isAlive) {
bullets.splice(i, 1);
continue;
}
bullet.update();
// Проверка столкновений с врагами
for (let enemy of enemies.enemies) {
if (!enemy.isAlive) continue;
const bulletRect = {
x: bullet.sprite.x,
y: bullet.sprite.y,
width: bullet.sprite.width,
height: bullet.sprite.height
};
const enemyRect = {
x: enemy.sprite.x,
y: enemy.sprite.y,
width: enemy.sprite.width,
height: enemy.sprite.height
};
if (isCollision(bulletRect, enemyRect)) {
enemy.destroy();
bullet.destroy();
break;
}
}
}
});
В этом участке реализуется обработка выстрелов по нажатию пробела, обновление состояний всех игровых объектов и взаимодействие между ними. По мере удаления пуль они удаляются из массива, что предотвращает утечки памяти.
Дополнительные возможности и улучшения
Созданная версия игры — базовая и может быть значительно расширена. Например, можно добавить счёт очков, уровни сложности, улучшенную графику, звуковое сопровождение и анимацию врагов. Также стоит реализовать контроллеры для мобильных устройств и меню старта.
Следует продумать логику окончания игры — при достижении врагами нижней границы или попадании в игрока будет полезно показывать сообщение о проигрыше и предлагать перезапустить игру. Помимо этого, можно использовать спрайт-листы и анимации для улучшения визуального восприятия.
Таблица потенциальных улучшений
Улучшение | Описание | Сложность реализации |
---|---|---|
Счёт и таблица рекордов | Отслеживание набранных очков, сохранение и отображение лучших результатов | Средняя |
Анимации врагов | Использование спрайт-листов для плавного движения врагов и их атак | Высокая |
Звуковые эффекты | Добавление аудио при выстрелах и разрушениях | Низкая — средняя |
Уровни и увеличение сложности | Увеличение скорости врагов и их количества с продвижением по уровням | Средняя |
Меню и интерфейс | Создание экранов старта, паузы и конца игры с кнопками управления | Средняя |
Заключение
Создание игры "Space Invaders" с использованием JavaScript и PixiJS — увлекательный и полезный проект, который помогает разобраться с основами игровой логики, графики и взаимодействия с пользователем. В ходе статьи мы рассмотрели пошаговую реализацию ключевых компонентов: от инициализации сцены и создания игрока до программирования врагов, выстрелов и столкновений.
В результате получилась базовая, но уже вполне играбельная версия классической аркады, которую можно расширять и улучшать в зависимости от задач и уровня владения технологиями. PixiJS продемонстрировал свою гибкость и производительность, позволяя легко управлять спрайтами и обновлять игровой процесс в реальном времени.
Такой проект отлично подходит как учебное задание для начинающих разработчиков игр и веб-программирования, а также может служить основой для более сложных и масштабных игровых решений.
Вот HTML-таблица с 10 LSI-запросами для статьи 'Создание игры "Space Invaders" на JavaScript с использованием PixiJS':
```html
```
Эта таблица содержит пять строк и столбцов с релевантными LSI-запросами, которые могут помочь в оптимизации статьи.