Как создать игру “Шайбы” на JavaScript: Пошаговое руководство
В этом руководстве мы подробно рассмотрим, как создать классическую игру “Шайбы” (Air Hockey) с использованием HTML, CSS и JavaScript. Игра будет включать в себя подвижные шайбы, отскакивающие от стенок, и подсчет очков. Мы разберем каждый этап разработки, начиная от структуры HTML и стилизации CSS, и заканчивая логикой игры на JavaScript.
1. Подготовка окружения
Прежде чем начать, убедитесь, что у вас есть текстовый редактор (например, VS Code, Sublime Text или Atom) и базовые знания HTML, CSS и JavaScript. Создайте новую папку для проекта и в ней три файла:
index.html
– для структуры HTMLstyle.css
– для стилей CSSscript.js
– для логики JavaScript
2. Структура HTML (index.html
)
HTML файл будет содержать канвас (canvas) элемент, на котором будет отрисовываться игра. Также подключим CSS и JavaScript файлы.
html
В этом коде:
<!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, а не просто отрисовывать текст на канвасе.
- Пауза: Добавить возможность поставить игру на паузу.
Следуя этим рекомендациям, вы сможете значительно улучшить свою игру и сделать ее более интересной и увлекательной.