Сегодня сделаем на JavaScript очень простую браузерную игру с динозавриком, как в Google Chrome. Наша игра будет проще оригинальной: динозаврик будет неанимированный и сможет только прыгать, чтобы преодолеть препятствие.
На примере этой игры мы потренируемся работать с DOM в JavaScript, то есть с объектной моделью документа, — получать элементы, изменять их классы, обрабатывать события, а также делать простую CS-анимацию и работать с позиционированием.
Логика проекта
В левом нижнем углу находится динозаврик, а справа налево ему навстречу движется кактус. Проехал один — появляется второй. При нажатии пробела динозаврик его перепрыгивает. При этом игра постоянно проверяет положение динозаврика и кактуса: если было столкновение без прыжка — всё, гейм овер.
Что для этого будем делать:
- Создадим HTML-страницу, где разместим контейнер для игры и элементы для динозаврика и кактуса.
- В CSS зададим стили и реализуем анимации для прыжка динозаврика и движения кактуса.
- В JS-скрипте напишем функцию
jump()
, которая будет отвечать за анимацию прыжка. - Добавим обработчик событий для нажатия пробела, который вызывает функцию
jump()
. - В скрипте сделаем постоянную проверку положения динозаврика и кактуса.
Создаём веб-страницу
Создадим новый html-файл и добавим в него простую разметку: добавим контейнер для игровой сцены, блок для динозаврика и блок для кактуса. Также сразу создадим в проекте файлы styles.css и script.js и подключим их.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Игра с динозавриком</title>
<!-- подключаем стили -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- контейнер игрового поля -->
<div class="game">
<!-- контейнер динозаврика -->
<div id="dino"></div>
<!-- контейнер кактуса -->
<div id="cactus"></div>
</div>
<!-- подключаем скрипт -->
<script src="script.js"></script>
</body>
</html>
Мы не задали никаких стилей и ничего не добавили в код, кроме блоков, страница будет пустой, поэтому пока без скриншота.
Добавляем стили для сцены и динозаврика
Зададим размеры контейнеров самой игры и динозаврика и добавим картинку. Чтобы не рисовать всё самим, динозаврика возьмём отсюда. Для картинок создадим папку img и пропишем путь к ней в настройках стилей.
.game {
/* ширина игровой области */
width: 600px;
/* высота игровой области */
height: 200px;
/* рамка серого цвета и отступы вокруг неё */
border: 1px solid rgb(122, 122, 122);
/* автоматические отступы */
margin: auto;
}
#dino {
/* ширина и высота динозаврика */
width: 50px;
height: 50px;
/* путь к изображению динозаврика */
background-image: url(img/trex.png);
/* ширина и высота подложки */
background-size: 50px 50px;
/* относительное позиционирование */
position: relative;
/* отступ сверху */
top: 150px;
}
Создаём анимацию прыжка
Анимацию прыжка динозаврика реализуем в CSS с помощью ключевых кадров @keyframes
, а дальше для обработки напишем JS-скрипт.
/* класс анимации прыжка */
.jump {
animation: jump 0.3s linear;
}
/* 5 ключевых кадров для анимации прыжка */
@keyframes jump {
0% {
/* начальная позиция */
top: 150px;
}
30% {
/* начало прыжка */
top: 130px;
}
50% {
/* самая высокая точка прыжка */
top: 80px;
}
80% {
/* начало спуска */
top: 130px;
}
100% {
/* возврат в начальную позицию */
top: 150px;
}
}
Пишем скрипт для реализации прыжка
Чтобы всё это заработало, напишем скрипт, который будет управлять прыжком динозаврика. Скрипт будет проверять, находится ли динозаврик в прыжке, и, если нет, запускать анимацию, добавляя класс jump
. После анимации класс будет удаляться, и динозаврик сможет прыгать снова.
// получаем элемент динозаврика по его ID
const dino = document.getElementById("dino");
// функция прыжка
function jump() {
// проверяем, не находится ли динозаврик в прыжке
if (dino.classList != "jump") {
// добавляем класс jump для начала анимации прыжка
dino.classList.add("jump");
// удаляем класс jump через 300 миллисекунд, чтобы завершить прыжок
setTimeout(function () {
dino.classList.remove("jump");
}, 300);
}
}
Добавляем обработку нажатия клавиши для прыжка
Теперь сделаем так, чтобы динозаврик прыгал при нажатии на пробел. Для этого добавим обработчик событий для нажатий клавиш:
// добавляем обработчик событий
document.addEventListener("keydown", function (event) {
// проверяем, была ли нажата клавиша пробела
if (event.key === " ") {
// если пробел нажат, вызываем функцию jump()
jump();
}
});
Для прыжка динозаврика всё готово. Проверим:
Создаём и анимируем кактус
Динозаврик готов, теперь добавим кактус. Пропишем его размер и зададим позиционирование. Затем с помощью @keyframes
сделаем так, чтобы кактус двигался справа налево. Картинку кактуса тоже возьмём уже готовую.
#cactus {
/* ширина и высота кактуса */
width: 20px;
height: 40px;
/* относительное позиционирование */
position: relative;
/* начальное положение кактуса */
top: 110px;
left: 580px;
/* путь к изображению кактуса*/
background-image: url("img/cactus.png");
/* ширина и высота подложки */
background-size: 20px 40px;
/* анимация перемещения кактуса */
animation: block 2s infinite linear;
}
@keyframes block {
/* начальная позиция кактуса (справа) */
0% {
left: 580px;
}
/* конечная позиция кактуса (слева, за пределами экрана) */
100% {
left: -20px;
}
}
Проверяем. Кактус движется, динозаврик прыгает. Все наготове:
Пишем скрипт для столкновения объектов
Мы уже сделали анимацию прыжка динозаврика и движения кактуса, но при этом объекты не сталкиваются, а суть игры именно в этом. Поэтому напишем финальный скрипт, где нужно сделать вот что:
- Получить позиции динозаврика и кактуса: скрипт будет проверять, где находится динозаврик — на земле или в воздухе, и насколько близко к нему расположен кактус.
- Оценить возможность столкновения по заданным условиям и показать сообщение, если столкновение произошло.
В оригинальной игре Chrome динозаврик как будто бы бежит по земле, но на самом деле его координата X на экране не меняется. Поэтому для определения столкновения нам нужно знать только его Y-координату, то есть понимать, находится ли он в прыжке.
Напишем код:
// Получаем элемент кактуса по его ID
const cactus = document.getElementById("cactus");
// Устанавливаем интервал для проверки состояния игры каждые 10 мс
let isAlive = setInterval(function () {
// Получаем текущую y-позицию динозаврика
let dinoTop = parseInt(window.getComputedStyle(dino).getPropertyValue("top"));
// Получаем текущую x-позицию кактуса
let cactusLeft = parseInt(window.getComputedStyle(cactus).getPropertyValue("left"));
// Проверяем условия столкновения:
// кактус находится в пределах 50 пикселей от динозаврика по оси x,
// кактус ещё не прошёл динозаврика, и динозаврик не прыгнул высоко
if (cactusLeft < 50 && cactusLeft > 0 && dinoTop >= 140) {
// Если произошло столкновение, выводим сообщение
alert("Потрачено!");
}
}, 10);
Готово!
Что дальше
Дальше игру можно улучшить и усложнить: добавить анимированный фон, дополнительные препятствия и действия.
А чтобы поиграть в оригинальную игру в Chrome и вдохновиться, нужно ввести в строке браузера chrome://dino/ или chrome://network-error/-106.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Игра с динозавриком</title>
<!-- подключаем стили -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- контейнер игрового поля -->
<div class="game">
<!-- контейнер динозаврика -->
<div id="dino"></div>
<!-- контейнер кактуса -->
<div id="cactus"></div>
</div>
<!-- подключаем скрипт -->
<script src="script.js"></script>
</body>
</html>
.game {
/* ширина игровой области */
width: 600px;
/* высота игровой области */
height: 200px;
/* рамка серого цвета и отступы вокруг неё */
border: 1px solid rgb(122, 122, 122);
/* автоматические отступы */
margin: auto;
}
#dino {
/* ширина и высота динозаврика */
width: 50px;
height: 50px;
/* путь к изображению динозаврика */
background-image: url(img/trex.png);
/* ширина и высота подложки */
background-size: 50px 50px;
/* относительное позиционирование */
position: relative;
/* отступ сверху */
top: 150px;
}
/* класс анимации прыжка */
.jump {
animation: jump 0.3s linear;
}
/* 5 ключевых кадров для анимации прыжка */
@keyframes jump {
0% {
/* начальная позиция */
top: 150px;
}
30% {
/* начало прыжка */
top: 130px;
}
50% {
/* самая высокая точка прыжка */
top: 80px;
}
80% {
/* начало спуска */
top: 130px;
}
100% {
/* возврат в начальную позицию */
top: 150px;
}
}
#cactus {
/* ширина и высота кактуса */
width: 20px;
height: 40px;
/* относительное позиционирование */
position: relative;
/* начальное положение кактуса */
top: 110px;
left: 580px;
/* путь к изображению кактуса*/
background-image: url("img/cactus.png");
/* ширина и высота подложки */
background-size: 20px 40px;
/* анимация перемещения кактуса */
animation: block 2s infinite linear;
}
@keyframes block {
/* начальная позиция кактуса (справа) */
0% {
left: 580px;
}
/* конечная позиция кактуса (слева, за пределами экрана) */
100% {
left: -20px;
}
}
// получаем элемент динозаврика по его ID
const dino = document.getElementById("dino");
// функция прыжка
function jump() {
// проверяем, не находится ли динозаврик в прыжке
if (dino.classList != "jump") {
// добавляем класс jump для начала анимации прыжка
dino.classList.add("jump");
// удаляем класс jump через 300 миллисекунд, чтобы завершить прыжок
setTimeout(function () {
dino.classList.remove("jump");
}, 300);
}
}
// добавляем обработчик событий
document.addEventListener("keydown", function (event) {
// проверяем, была ли нажата клавиша пробела
if (event.key === " ") {
// если пробел нажат, вызываем функцию jump()
jump();
}
});
// Получаем элемент кактуса по его ID
const cactus = document.getElementById("cactus");
// Устанавливаем интервал для проверки состояния игры каждые 10 мс
let isAlive = setInterval(function () {
// Получаем текущую y-позицию динозаврика
let dinoTop = parseInt(window.getComputedStyle(dino).getPropertyValue("top"));
// Получаем текущую x-позицию кактуса
let cactusLeft = parseInt(window.getComputedStyle(cactus).getPropertyValue("left"));
// Проверяем условия столкновения:
// кактус находится в пределах 50 пикселей от динозаврика по оси x,
// кактус ещё не прошёл динозаврика, и динозаврик не прыгнул высоко
if (cactusLeft < 50 && cactusLeft > 0 && dinoTop >= 140) {
// Если произошло столкновение, выводим сообщение
alert("Потрачено!");
}
}, 10);