Как создать игру “Шайбы” на JavaScript: Пошаговое руководство

Как создать игру “Шайбы” на JavaScript: Пошаговое руководство

В этом руководстве мы подробно рассмотрим, как создать классическую игру “Шайбы” (Air Hockey) с использованием HTML, CSS и JavaScript. Игра будет включать в себя подвижные шайбы, отскакивающие от стенок, и подсчет очков. Мы разберем каждый этап разработки, начиная от структуры HTML и стилизации CSS, и заканчивая логикой игры на JavaScript.

1. Подготовка окружения

Прежде чем начать, убедитесь, что у вас есть текстовый редактор (например, VS Code, Sublime Text или Atom) и базовые знания HTML, CSS и JavaScript. Создайте новую папку для проекта и в ней три файла:

  • index.html – для структуры HTML
  • style.css – для стилей CSS
  • script.js – для логики JavaScript

2. Структура HTML (index.html)

HTML файл будет содержать канвас (canvas) элемент, на котором будет отрисовываться игра. Также подключим CSS и JavaScript файлы.

html





Air Hockey




В этом коде:

  • <!DOCTYPE html> объявляет тип документа как HTML5.
  • <html lang="ru"> задает язык документа как русский.
  • <meta charset="UTF-8"> задает кодировку символов UTF-8.
  • <meta name="viewport" content="width=device-width, initial-scale=1.0"> задает настройки viewport для адаптивного отображения на разных устройствах.
  • <title>Air Hockey</title> задает заголовок страницы.
  • <link rel="stylesheet" href="style.css"> подключает файл стилей CSS.
  • <canvas id="gameCanvas" width="800" height="600"></canvas> создает элемент canvas с id “gameCanvas”, шириной 800 пикселей и высотой 600 пикселей. Именно на этом элементе будет отрисовываться игра.
  • <script src="script.js"></script> подключает файл JavaScript.

3. Стили CSS (style.css)

CSS файл будет содержать стили для канваса. Например, зададим цвет фона.

css
body {
margin: 0;
overflow: hidden; /* Предотвращает появление полос прокрутки */
background-color: #222;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

#gameCanvas {
background-color: #000;
border: 2px solid white;
}

В этом коде:

  • body: Убираем отступы по умолчанию, скрываем полосы прокрутки, задаем темный фон, центрируем канвас по горизонтали и вертикали.
  • #gameCanvas: Задаем черный фон и белую рамку для канваса.

4. Логика игры JavaScript (script.js)

JavaScript файл будет содержать всю логику игры. Мы будем использовать канвас API для отрисовки элементов игры и обрабатывать события мыши для управления шайбами.

4.1. Начальная настройка

Сначала получим ссылку на канвас и его контекст. Также определим переменные для размеров канваса, положения шайб и т.д.

javascript
const canvas = document.getElementById(‘gameCanvas’);
const ctx = canvas.getContext(‘2d’);

const canvasWidth = canvas.width;
const canvasHeight = canvas.height;

// Размеры и положение шайб
const puckRadius = 25;
let puckX = canvasWidth / 2;
let puckY = canvasHeight / 2;
let puckSpeedX = 5;
let puckSpeedY = 5;

// Размеры и положение ракеток
const paddleWidth = 10;
const paddleHeight = 100;
const leftPaddleX = 0;
let leftPaddleY = canvasHeight / 2 – paddleHeight / 2;
const rightPaddleX = canvasWidth – paddleWidth;
let rightPaddleY = canvasHeight / 2 – paddleHeight / 2;

// Скорость ракеток
const paddleSpeed = 7;

// Управление ракетками
let leftPaddleUp = false;
let leftPaddleDown = false;
let rightPaddleUp = false;
let rightPaddleDown = false;

// Счет
let leftScore = 0;
let rightScore = 0;

В этом коде мы:

  • Получаем ссылку на канвас элемент и его 2D контекст (ctx), который используется для рисования.
  • Определяем переменные для ширины и высоты канваса.
  • Определяем радиус шайбы (puckRadius), начальное положение шайбы (puckX, puckY) и ее скорость (puckSpeedX, puckSpeedY).
  • Определяем размеры ракеток (paddleWidth, paddleHeight) и их начальное положение (leftPaddleX, leftPaddleY, rightPaddleX, rightPaddleY).
  • Определяем скорость движения ракеток (paddleSpeed).
  • Создаем булевы переменные для отслеживания нажатия клавиш управления ракетками.
  • Инициализируем счет игроков.

4.2. Функции отрисовки

Создадим функции для отрисовки шайбы, ракеток и счета.

javascript
function drawPuck() {
ctx.beginPath();
ctx.arc(puckX, puckY, puckRadius, 0, Math.PI * 2);
ctx.fillStyle = ‘white’;
ctx.fill();
ctx.closePath();
}

function drawPaddle(x, y, width, height) {
ctx.fillStyle = ‘white’;
ctx.fillRect(x, y, width, height);
}

function drawScore() {
ctx.font = ’30px Arial’;
ctx.fillStyle = ‘white’;
ctx.fillText(leftScore, canvasWidth / 4, 50);
ctx.fillText(rightScore, canvasWidth * 3 / 4, 50);
}

В этом коде:

  • drawPuck(): Рисует шайбу как окружность белого цвета.
  • drawPaddle(): Рисует прямоугольник (ракетку) белого цвета.
  • drawScore(): Рисует счет игроков белым цветом в верхней части экрана.

4.3. Функция обновления игры

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

javascript
function update() {
// Очистка канваса
ctx.clearRect(0, 0, canvasWidth, canvasHeight);

// Движение ракеток
if (leftPaddleUp) {
leftPaddleY -= paddleSpeed;
}
if (leftPaddleDown) {
leftPaddleY += paddleSpeed;
}
if (rightPaddleUp) {
rightPaddleY -= paddleSpeed;
}
if (rightPaddleDown) {
rightPaddleY += paddleSpeed;
}

// Ограничение движения ракеток
leftPaddleY = Math.max(0, Math.min(leftPaddleY, canvasHeight – paddleHeight));
rightPaddleY = Math.max(0, Math.min(rightPaddleY, canvasHeight – paddleHeight));

// Движение шайбы
puckX += puckSpeedX;
puckY += puckSpeedY;

// Отскок от верхней и нижней стенок
if (puckY + puckRadius > canvasHeight || puckY – puckRadius < 0) { puckSpeedY = -puckSpeedY; } // Проверка столкновения с ракетками if (puckX - puckRadius < paddleWidth && puckY > leftPaddleY && puckY < leftPaddleY + paddleHeight) { puckSpeedX = -puckSpeedX; // Увеличиваем скорость после удара puckSpeedX *= 1.1; puckSpeedY *= 1.1; } if (puckX + puckRadius > canvasWidth – paddleWidth &&
puckY > rightPaddleY && puckY < rightPaddleY + paddleHeight) { puckSpeedX = -puckSpeedX; // Увеличиваем скорость после удара puckSpeedX *= 1.1; puckSpeedY *= 1.1; } // Проверка, забита ли шайба if (puckX - puckRadius < 0) { rightScore++; resetPuck(); } if (puckX + puckRadius > canvasWidth) {
leftScore++;
resetPuck();
}

// Отрисовка элементов
drawPuck();
drawPaddle(leftPaddleX, leftPaddleY, paddleWidth, paddleHeight);
drawPaddle(rightPaddleX, rightPaddleY, paddleWidth, paddleHeight);
drawScore();

// Запрос следующего кадра анимации
requestAnimationFrame(update);
}

В этом коде:

  • ctx.clearRect(): Очищает канвас перед каждым кадром.
  • Движение ракеток: Изменяет положение ракеток в зависимости от нажатых клавиш.
  • Ограничение движения ракеток: Не позволяет ракеткам выходить за пределы экрана.
  • Движение шайбы: Изменяет положение шайбы в зависимости от ее скорости.
  • Отскок от стенок: Изменяет направление скорости шайбы, когда она достигает верхней или нижней границы экрана.
  • Проверка столкновения с ракетками: Изменяет направление скорости шайбы, когда она сталкивается с ракеткой. Так же увеличивает скорость шайбы после удара ракеткой.
  • Проверка, забита ли шайба: Увеличивает счет игрока и перезапускает шайбу, если она выходит за пределы экрана по горизонтали.
  • Вызывает функции отрисовки для рисования шайбы, ракеток и счета.
  • requestAnimationFrame(update): Запрашивает следующий кадр анимации, что обеспечивает плавное обновление экрана.

4.4. Функция сброса шайбы

Создадим функцию, которая будет сбрасывать положение шайбы в центр экрана и задавать ей случайное направление.

javascript
function resetPuck() {
puckX = canvasWidth / 2;
puckY = canvasHeight / 2;
puckSpeedX = 5 * (Math.random() > 0.5 ? 1 : -1);
puckSpeedY = 5 * (Math.random() > 0.5 ? 1 : -1);
}

Эта функция:

  • Возвращает шайбу в центр экрана.
  • Задает случайное направление движения шайбы.

4.5. Обработка событий клавиатуры

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

javascript
document.addEventListener(‘keydown’, function(event) {
switch (event.key) {
case ‘w’:
leftPaddleUp = true;
break;
case ‘s’:
leftPaddleDown = true;
break;
case ‘ArrowUp’:
rightPaddleUp = true;
break;
case ‘ArrowDown’:
rightPaddleDown = true;
break;
}
});

document.addEventListener(‘keyup’, function(event) {
switch (event.key) {
case ‘w’:
leftPaddleUp = false;
break;
case ‘s’:
leftPaddleDown = false;
break;
case ‘ArrowUp’:
rightPaddleUp = false;
break;
case ‘ArrowDown’:
rightPaddleDown = false;
break;
}
});

Этот код:

  • Обрабатывает события keydown и keyup.
  • Устанавливает значения переменных leftPaddleUp, leftPaddleDown, rightPaddleUp, rightPaddleDown в зависимости от нажатых клавиш (W, S для левой ракетки, стрелки вверх и вниз для правой ракетки).

4.6. Запуск игры

Запустим игру, вызвав функцию update().

javascript
update();

5. Полный код script.js

javascript
const canvas = document.getElementById(‘gameCanvas’);
const ctx = canvas.getContext(‘2d’);

const canvasWidth = canvas.width;
const canvasHeight = canvas.height;

// Размеры и положение шайб
const puckRadius = 25;
let puckX = canvasWidth / 2;
let puckY = canvasHeight / 2;
let puckSpeedX = 5;
let puckSpeedY = 5;

// Размеры и положение ракеток
const paddleWidth = 10;
const paddleHeight = 100;
const leftPaddleX = 0;
let leftPaddleY = canvasHeight / 2 – paddleHeight / 2;
const rightPaddleX = canvasWidth – paddleWidth;
let rightPaddleY = canvasHeight / 2 – paddleHeight / 2;

// Скорость ракеток
const paddleSpeed = 7;

// Управление ракетками
let leftPaddleUp = false;
let leftPaddleDown = false;
let rightPaddleUp = false;
let rightPaddleDown = false;

// Счет
let leftScore = 0;
let rightScore = 0;

function drawPuck() {
ctx.beginPath();
ctx.arc(puckX, puckY, puckRadius, 0, Math.PI * 2);
ctx.fillStyle = ‘white’;
ctx.fill();
ctx.closePath();
}

function drawPaddle(x, y, width, height) {
ctx.fillStyle = ‘white’;
ctx.fillRect(x, y, width, height);
}

function drawScore() {
ctx.font = ’30px Arial’;
ctx.fillStyle = ‘white’;
ctx.fillText(leftScore, canvasWidth / 4, 50);
ctx.fillText(rightScore, canvasWidth * 3 / 4, 50);
}

function update() {
// Очистка канваса
ctx.clearRect(0, 0, canvasWidth, canvasHeight);

// Движение ракеток
if (leftPaddleUp) {
leftPaddleY -= paddleSpeed;
}
if (leftPaddleDown) {
leftPaddleY += paddleSpeed;
}
if (rightPaddleUp) {
rightPaddleY -= paddleSpeed;
}
if (rightPaddleDown) {
rightPaddleY += paddleSpeed;
}

// Ограничение движения ракеток
leftPaddleY = Math.max(0, Math.min(leftPaddleY, canvasHeight – paddleHeight));
rightPaddleY = Math.max(0, Math.min(rightPaddleY, canvasHeight – paddleHeight));

// Движение шайбы
puckX += puckSpeedX;
puckY += puckSpeedY;

// Отскок от верхней и нижней стенок
if (puckY + puckRadius > canvasHeight || puckY – puckRadius < 0) { puckSpeedY = -puckSpeedY; } // Проверка столкновения с ракетками if (puckX - puckRadius < paddleWidth && puckY > leftPaddleY && puckY < leftPaddleY + paddleHeight) { puckSpeedX = -puckSpeedX; // Увеличиваем скорость после удара puckSpeedX *= 1.1; puckSpeedY *= 1.1; } if (puckX + puckRadius > canvasWidth – paddleWidth &&
puckY > rightPaddleY && puckY < rightPaddleY + paddleHeight) { puckSpeedX = -puckSpeedX; // Увеличиваем скорость после удара puckSpeedX *= 1.1; puckSpeedY *= 1.1; } // Проверка, забита ли шайба if (puckX - puckRadius < 0) { rightScore++; resetPuck(); } if (puckX + puckRadius > canvasWidth) {
leftScore++;
resetPuck();
}

// Отрисовка элементов
drawPuck();
drawPaddle(leftPaddleX, leftPaddleY, paddleWidth, paddleHeight);
drawPaddle(rightPaddleX, rightPaddleY, paddleWidth, paddleHeight);
drawScore();

// Запрос следующего кадра анимации
requestAnimationFrame(update);
}

function resetPuck() {
puckX = canvasWidth / 2;
puckY = canvasHeight / 2;
puckSpeedX = 5 * (Math.random() > 0.5 ? 1 : -1);
puckSpeedY = 5 * (Math.random() > 0.5 ? 1 : -1);
}

document.addEventListener(‘keydown’, function(event) {
switch (event.key) {
case ‘w’:
leftPaddleUp = true;
break;
case ‘s’:
leftPaddleDown = true;
break;
case ‘ArrowUp’:
rightPaddleUp = true;
break;
case ‘ArrowDown’:
rightPaddleDown = true;
break;
}
});

document.addEventListener(‘keyup’, function(event) {
switch (event.key) {
case ‘w’:
leftPaddleUp = false;
break;
case ‘s’:
leftPaddleDown = false;
break;
case ‘ArrowUp’:
rightPaddleUp = false;
break;
case ‘ArrowDown’:
rightPaddleDown = false;
break;
}
});

update();

6. Заключение

В этом руководстве мы создали простую, но функциональную игру “Шайбы” на JavaScript. Вы можете расширить эту игру, добавив, например, уровни сложности, различные бонусы, или улучшенный AI для игры против компьютера. Экспериментируйте и наслаждайтесь процессом создания игр!

7. Дальнейшие улучшения

  • Улучшенный AI: Вместо простого управления ракеткой, можно реализовать более сложный AI, который будет предсказывать траекторию шайбы и двигаться более эффективно.
  • Разные уровни сложности: Можно добавить уровни сложности, изменяя скорость шайбы и ракеток.
  • Бонусы: Добавить бонусы, которые появляются на экране и дают игрокам временные преимущества, например, увеличение скорости ракетки или уменьшение размера шайбы.
  • Звуковые эффекты: Добавить звуковые эффекты при столкновении шайбы со стенками и ракетками, а также при забивании гола.
  • Скины: Позволить игрокам выбирать разные скины для ракеток и шайбы.
  • Мультиплеер: Реализовать возможность игры вдвоем по сети. Это потребует использования WebSocket или другой технологии для обмена данными между клиентами.
  • Анимация: Добавить анимацию при забивании гола или при получении бонусов.
  • Пользовательский интерфейс (UI): Создать более привлекательный UI с использованием HTML и CSS, а не просто отрисовывать текст на канвасе.
  • Пауза: Добавить возможность поставить игру на паузу.

Следуя этим рекомендациям, вы сможете значительно улучшить свою игру и сделать ее более интересной и увлекательной.

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments