ГРА ЗМІЙКА
Створення змійки
Сьогодні ми створимо просту гру "Змійка" на веб-сторінці. Спочатку ми створюємо базову сторінку з HTML. Це код, який розповідає браузеру, як виглядатиме наша гра. Ось що ми робимо:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>27 Гра змійка</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById("canvas"); // Отримуємо доступ до елемента canvas
const ctx = canvas.getContext("2d"); // Отримуємо контекст для малювання 2D на полотні
</script>
</body>
</html>
Визначаємо розміри ігрового поля. Розмір полотна встановлюється 400x400 пікселів, але ми будемо працювати з "блоками" (частинами цього поля):
var blockSize = 10;
var width = canvas.width; // Задаємо змінну для ширини полотна
var height = canvas.height; // Задаємо змінну для висоти полотна
var widthInBlock = width / blockSize;
var heightInBlock = height / blockSize;Малювання кордонів. Щоб обмежити область гри, ми малюємо кордони з усіх боків:
var drawBorder = function() {
ctx.fillStyle = "Gray";
ctx.fillRect(0, 0, width, blockSize); // Верхній кордон
ctx.fillRect(0, height - blockSize, width, blockSize); // Нижній кордон
ctx.fillRect(0, 0, blockSize, height); // Лівий кордон
ctx.fillRect(width - blockSize, 0, blockSize, height); // Правий кордон
};Малювання рахунку. Тут ми будемо малювати рахунок гри в лівому верхньому кутку:
var score = 0; // Ініціалізація змінної для зберігання рахунку
var drawScore = function() {
ctx.font = "20px Courier";
ctx.fillStyle = "Black";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Score: " + score, blockSize, blockSize);
};Функція для малювання кола. Це допоміжна функція для малювання круглих елементів, таких як яблуко:
var circle = function(x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false);
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
};Блоки для змійки та яблука. Ми створюємо конструктор Block, щоб легко працювати з блоками, що складаються з стовпців і рядків:
var Block = function(col, row) {
this.col = col;
this.row = row;
};У кожного блоку є методи:
Для малювання квадрата (drawSquare) або кола (drawCircle).
Для порівняння з іншими блоками (equal).
Block.prototype.drawSquare = function(color) { // Метод для малювання квадратного блоку
var x = this.col * blockSize; // Обчислюємо координату X
var y = this.row * blockSize; // Обчислюємо координату Y
ctx.fillStyle = color; // Встановлюємо колір для блоку
ctx.fillRect(x, y, blockSize, blockSize); // Малюємо квадрат
};
Block.prototype.drawCircle = function(color) { // Метод для малювання круглих блоків
var centerX = this.col * blockSize + blockSize / 2; // Обчислюємо центр по X
var centerY = this.row * blockSize + blockSize / 2; // Обчислюємо центр по Y
ctx.fillStyle = color; // Встановлюємо колір
circle(centerX, centerY, blockSize / 2, true); // Малюємо коло
};
Block.prototype.equal = function(otherBlock) { // Метод для перевірки чи два блоки рівні (за координатами)
return this.col === otherBlock.col && this.row === otherBlock.row;
};Змійка в нашій грі складається з блоків. Кожен блок є прямокутником, який ми малюємо canvas. Кожного разу, коли змійка рухається, ми додаємо новий блок на початок змійки і видаляємо останній блок, якщо змійка не з'їла яблуко.
Ось код для створення змійки:
var Snake = function() {
this.segments = [
new Block(7, 5),
new Block(6, 5),
new Block(5, 5)
]; // Початкові блоки змійки
this.direction = "right"; // Початковий напрямок
this.nextDirection = "right"; // Напрямок для наступного руху
};- segments — це масив, що зберігає всі блоки змійки.
- direction — це напрямок, в якому рухається змійка.
Механізм руху змійки. Щоб змійка рухалася, ми додаємо новий блок на початок змійки, а потім видаляємо останній блок, якщо змійка не з'їла яблуко.
Snake.prototype.move = function() {
var head = this.segments[0]; // Голова змійки
var newHead; // Нова голова після руху
this.direction = this.nextDirection; // Оновлюємо напрямок
// Визначаємо, куди рухатиметься змійка
if (this.direction === "right") {
newHead = new Block(head.col + 1, head.row);
} else if (this.direction === "down") {
newHead = new Block(head.col, head.row + 1);
} else if (this.direction === "left") {
newHead = new Block(head.col - 1, head.row);
} else if (this.direction === "up") {
newHead = new Block(head.col, head.row - 1);
}
this.segments.unshift(newHead); // Додаємо нову голову на початок змійки
if (newHead.equal(apple.position)) {
score++; // Якщо змійка з'їла яблуко, збільшуємо рахунок
apple.move(); // Переміщаємо яблуко
} else {
this.segments.pop(); // Видаляємо останній сегмент, якщо яблуко не з'їдено
}
};Перевірка зіткнення. Щоб зробити гру цікавою, ми додаємо перевірку на зіткнення змійки з кордоном або з її власним тілом. Якщо це відбувається, ми завершуємо гру.
Snake.prototype.checkCollision = function(head) {
var leftCollision = (head.col === 0); // Зіткнення з лівим кордоном
var topCollision = (head.row === 0); // Зіткнення з верхнім кордоном
var rightCollision = (head.col === widthInBlock - 1); // Зіткнення з правим кордоном
var bottomCollision = (head.row === heightInBlock - 1); // Зіткнення з нижнім кордоном
var wallCollision = leftCollision || topCollision || rightCollision || bottomCollision;
var selfCollision = false; // Перевірка на зіткнення з собою
for (var i = 0; i < this.segments.length; i++) {
if (head.equal(this.segments[i])) {
selfCollision = true; // Якщо голова збігається з тілом
}
}
return wallCollision || selfCollision; // Якщо є зіткнення, гра закінчиться
};Метод setDirection для змійки. Цей метод дозволяє змійці змінювати напрямок руху, забороняючи рух в протилежному напрямку.
Snake.prototype.setDirection = function(newDirection) {
// Якщо змійка рухається вгору, не дозволяємо рухатися вниз
if (this.direction === "up" && newDirection === "down") {
return;
}
// Якщо змійка рухається вправо, не дозволяємо рухатися вліво
else if (this.direction === "right" && newDirection === "left") {
return;
}
// Якщо змійка рухається вниз, не дозволяємо рухатися вгору
else if (this.direction === "down" && newDirection === "up") {
return;
}
// Якщо змійка рухається вліво, не дозволяємо рухатися вправо
else if (this.direction === "left" && newDirection === "right") {
return;
}
// Якщо напрямок допустимий, оновлюємо новий напрямок
this.nextDirection = newDirection;
};Метою методу є уникнення того, щоб змійка могла рухатися в протилежному напрямку. Якщо вона рухається вгору, то не дозволяється рухатися вниз (і так для всіх напрямків).
Якщо напрямок допустимий, ми змінюємо значення nextDirection, яке вказує на наступний напрямок, у якому змійка рухатиметься. Це важливо, тому що змійка не змінює напрямок миттєво, а рухається по черзі.
Малювання яблука. Яблуко — це ще один блок, який з'являється в випадковому місці, коли змійка його з'їдає. Ось як ми малюємо яблуко:
var Apple = function() {
this.position = new Block(10, 10); // Початкова позиція яблука
};
Apple.prototype.draw = function() {
this.position.drawCircle("LimeGreen"); // Малюємо яблуко зеленим
};
Apple.prototype.move = function() {
var randomCol = Math.floor(Math.random() * (widthInBlock - 2) + 1); // Випадкова колонка
var randomRow = Math.floor(Math.random() * (heightInBlock - 2) + 1); // Випадковий рядок
this.position = new Block(randomCol, randomRow); // Оновлюємо позицію яблука
};Ініціалізація змійки та яблука. Це код, що створює об'єкти змійки та яблука, та ініціалізує цикл гри.
var snake = new Snake(); // Створюємо об'єкт змійки
var apple = new Apple(); // Створюємо об'єкт яблукаОб'єкти snake та apple ініціалізуються, щоб ми могли використовувати їх у грі для подальших маніпуляцій, таких як рух змійки або переміщення яблука.
Обробка натискання клавіші для зміни напрямку змійки. Тут обробляються натискання клавіш, що змінюють напрямок змійки.
var direction = { // Об'єкт, який визначає напрямки для клавіш
"ArrowLeft": "left",
"ArrowUp": "up",
"ArrowRight": "right",
"ArrowDown": "down"
};Це об'єкт, що визначає, яку дію виконує кожна клавіша (стрілки на клавіатурі).
$("body").keydown(function(event) {
var newDirection = direction[event.key]; // Знаходимо напрямок по натиснутій клавіші
if (newDirection !== undefined) { // Якщо напрямок знайдений
snake.setDirection(newDirection); // Встановлюємо новий напрямок
}
});- keydown — цей обробник події спрацьовує при натисканні клавіші.
- event.key — повертає значення натиснутої клавіші.
Якщо натиснута клавіша відповідає одному з напрямків (ліво, вправо, вгору, вниз), ми викликаємо метод setDirection для зміни напрямку змійки.
Основний цикл гри. І на заключення, створюємо наш основний цикл, де таймер відповідає за періодичне оновлення ігрового поля. Всі елементи гри (змійка, яблуко, кордони) малюються кожні 100 мілісекунд.
var intervalId = setInterval(function() {
ctx.clearRect(0, 0, width, height); // Очищаємо екран перед кожним малюванням
drawScore(); // Малюємо рахунок
snake.move(); // Рухаємо змійку
snake.draw(); // Малюємо змійку
apple.draw(); // Малюємо яблуко
drawBorder(); // Малюємо кордони
}, 100);- clearRect — очищає область екрану перед кожним новим малюванням, щоб забезпечити оновлення ігрового поля.
- drawScore — малює рахунок на екрані.
- snake.move() — рухає змійку, враховуючи новий напрямок.
- snake.draw() — малює нову позицію змійки на екрані.
- apple.draw() — малює яблуко.
- drawBorder — малює кордони ігрового поля.
Цей цикл виконується кожні 100 мілісекунд, що забезпечує плавний рух гри. Коли ми розібрали кожну стадію коду, виглядає код у нас так:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Гра змійка</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
const canvas = document.getElementById("canvas"); // Отримуємо доступ до елемента canvas
const ctx = canvas.getContext("2d"); // Отримуємо контекст для малювання 2D на полотні
var width = canvas.width; // Задаємо змінну для ширини полотна
var height = canvas.height; // Задаємо змінну для висоти полотна
var blockSize = 10; // Розмір одного блоку, що буде використовуватися для змійки та яблука
var widthInBlock = width / blockSize; // Розраховуємо кількість блоків по ширині
var heightInBlock = height / blockSize; // Розраховуємо кількість блоків по висоті
var score = 0; // Ініціалізація змінної для зберігання рахунку
var drawBorder = function() { // Функція для малювання кордону навколо ігрового поля
ctx.fillStyle = "Gray"; // Встановлюємо колір для кордону
ctx.fillRect(0, 0, width, blockSize); // Малюємо верхній кордон
ctx.fillRect(0, height - blockSize, width, blockSize); // Малюємо нижній кордон
ctx.fillRect(0, 0, blockSize, height); // Малюємо лівий кордон
ctx.fillRect(width - blockSize, 0, blockSize, height); // Малюємо правий кордон
};
var drawScore = function() { // Функція для малювання рахунку гри
ctx.font = "20px Courier"; // Встановлюємо шрифт
ctx.fillStyle = "Black"; // Встановлюємо колір тексту
ctx.textAlign = "left"; // Встановлюємо вирівнювання тексту по лівому краю
ctx.textBaseline = "top"; // Встановлюємо вирівнювання тексту по верхньому краю
ctx.fillText("Score: " + score, blockSize, blockSize); // Виводимо рахунок гри на екран
};
var gameOver = function() { // Функція для відображення повідомлення про кінець гри
clearInterval(intervalId); // Зупиняємо гру
ctx.font = "60px Courier"; // Встановлюємо шрифт для тексту "GAME OVER"
ctx.fillStyle = "Black"; // Встановлюємо колір тексту
ctx.textAlign = "center"; // Встановлюємо вирівнювання тексту по центру
ctx.textBaseline = "middle"; // Встановлюємо вирівнювання тексту по середині
ctx.fillText("GAME OVER", width / 2, height / 2); // Виводимо повідомлення про кінець гри в центрі екрану
};
var circle = function(x, y, radius, fillCircle) { // Функція для малювання кола
ctx.beginPath(); // Починаємо малювання
ctx.arc(x, y, radius, 0, Math.PI * 2, false); // Малюємо коло
if (fillCircle) { // Якщо потрібно заповнити коло кольором
ctx.fill();
} else {
ctx.stroke(); // Якщо не потрібно, малюємо тільки контур
}
}
var Block = function(col, row) { // Конструктор для блоку, який буде використовуватися для змійки та яблука
this.col = col; // Стовпчик блоку
this.row = row; // Рядок блоку
};
Block.prototype.drawSquare = function(color) { // Метод для малювання квадратного блоку
var x = this.col * blockSize; // Обчислюємо координату X
var y = this.row * blockSize; // Обчислюємо координату Y
ctx.fillStyle = color; // Встановлюємо колір для блоку
ctx.fillRect(x, y, blockSize, blockSize); // Малюємо квадрат
};
Block.prototype.drawCircle = function(color) { // Метод для малювання круглих блоків
var centerX = this.col * blockSize + blockSize / 2; // Обчислюємо центр по X
var centerY = this.row * blockSize + blockSize / 2; // Обчислюємо центр по Y
ctx.fillStyle = color; // Встановлюємо колір
circle(centerX, centerY, blockSize / 2, true); // Малюємо коло
};
Block.prototype.equal = function(otherBlock) { // Метод для перевірки чи два блоки рівні (за координатами)
return this.col === otherBlock.col && this.row === otherBlock.row;
};
var Snake = function() { // Конструктор для змійки
this.segments = [
new Block(7, 5),
new Block(6, 5),
new Block(5, 5)
]; // Початкові сегменти змійки
this.direction = "right"; // Початковий напрямок руху змійки
this.nextDirection = "right"; // Наступний напрямок, який змійка має вибрати
};
Snake.prototype.draw = function() { // Метод для малювання змійки
for (var i = 0; i < this.segments.length; i++) {
this.segments[i].drawSquare("Blue"); // Кожен сегмент змійки малюється синім кольором
}
};
Snake.prototype.move = function() { // Метод для руху змійки
var head = this.segments[0]; // Голова змійки
var newHead; // Нова голова після руху
this.direction = this.nextDirection; // Оновлюємо напрямок руху
// Обчислюємо нові координати для голови
if (this.direction === "right") {
newHead = new Block(head.col + 1, head.row);
} else if (this.direction === "down") {
newHead = new Block(head.col, head.row + 1);
} else if (this.direction === "left") {
newHead = new Block(head.col - 1, head.row);
} else if (this.direction === "up") {
newHead = new Block(head.col, head.row - 1);
}
// Перевіряємо чи сталася колізія з кордоном або власним тілом
if (this.checkCollision(newHead)) {
gameOver(); // Якщо колізія, гра завершена
return;
}
this.segments.unshift(newHead); // Додаємо нову голову на початок списку сегментів
// Якщо нова голова знаходиться на яблуці, змінюємо рахунок і переміщаємо яблуко
if (newHead.equal(apple.position)) {
score++;
apple.move();
} else {
this.segments.pop(); // Видаляємо останній сегмент, якщо яблуко не зібрано
}
};
Snake.prototype.checkCollision = function(head) { // Метод для перевірки колізій змійки
var leftCollision = (head.col === 0); // Перевіряємо колізію з лівим кордоном
var topCollision = (head.row === 0); // Перевіряємо колізію з верхнім кордоном
var rightCollision = (head.col === widthInBlock - 1); // Перевіряємо колізію з правим кордоном
var bottomCollision = (head.row === heightInBlock - 1); // Перевіряємо колізію з нижнім кордоном
var wallCollision = leftCollision || topCollision || rightCollision || bottomCollision; // Якщо є колізія з будь-яким кордоном
var selfCollision = false; // Перевірка колізії з самим собою
for (var i = 0; i < this.segments.length; i++) {
if (head.equal(this.segments[i])) {
selfCollision = true; // Якщо нова голова збігається з будь-яким сегментом змійки
}
}
return wallCollision || selfCollision; // Повертаємо true, якщо є колізія з кордоном або самим собою
};
Snake.prototype.setDirection = function(newDirection) { // Метод для встановлення нового напрямку
if (this.direction === "up" && newDirection === "down") {
return; // Не дозволяємо рухатися в протилежному напрямку
} else if (this.direction === "right" && newDirection === "left") {
return; // Не дозволяємо рухатися в протилежному напрямку
} else if (this.direction === "down" && newDirection === "up") {
return; // Не дозволяємо рухатися в протилежному напрямку
} else if (this.direction === "left" && newDirection === "right") {
return; // Не дозволяємо рухатися в протилежному напрямку
}
this.nextDirection = newDirection; // Якщо напрямок допустимий, оновлюємо наступний напрямок
};
var Apple = function() { // Конструктор для яблука
this.position = new Block(10, 10); // Початкова позиція яблука
};
Apple.prototype.draw = function() { // Метод для малювання яблука
this.position.drawCircle("LimeGreen"); // Яблуко малюється зеленим кольором
};
Apple.prototype.move = function() { // Метод для переміщення яблука на нову випадкову позицію
var randomCol = Math.floor(Math.random() * (widthInBlock - 2) + 1); // Генеруємо випадкову колонку
var randomRow = Math.floor(Math.random() * (heightInBlock - 2) + 1); // Генеруємо випадковий рядок
this.position = new Block(randomCol, randomRow); // Оновлюємо позицію яблука
};
var snake = new Snake(); // Створюємо об'єкт змійки
var apple = new Apple(); // Створюємо об'єкт яблука
var direction = { // Об'єкт, який визначає напрямки для клавіш
"ArrowLeft": "left",
"ArrowUp": "up",
"ArrowRight": "right",
"ArrowDown": "down"
};
$("body").keydown(function(event) { // Обробник події натискання клавіші
var newDirection = direction[event.key]; // Знаходимо напрямок по натиснутій клавіші
if (newDirection !== undefined) { // Якщо напрямок знайдений
snake.setDirection(newDirection); // Встановлюємо новий напрямок
}
});
var intervalId = setInterval(function() { // Створюємо таймер для гри
ctx.clearRect(0, 0, width, height); // Очищаємо екран перед кожним малюванням
drawScore(); // Малюємо рахунок
snake.move(); // Рухаємо змійку
snake.draw(); // Малюємо змійку
apple.draw(); // Малюємо яблуко
drawBorder(); // Малюємо кордони
}, 100); // Оновлюємо кожні 100 мілісекунд (10 кадрів в секунду)
</script>
</body>
</html>
build info
- compiler
- 2.0.5.1 · 4054EF9BF6C4510A
- built
- 2026-11-08 14:31:25 UTC
WebUniverse