Курс: Создание игры «Змейка» в DeepSeek на чистом JavaScript

Счет: 0
Скорость: 100%

🎮 Как играть:

📱 На телефоне: жми кнопки внизу
💻 На компьютере: используй стрелки ←↑→↓


Уровень: Начинающий
Продолжительность: 6 уроков (3-4 часа)


Урок 1: Подготовка структуры HTML

Цель: Создать базовую HTML-структуру игры
1.1 Основные элементы:

<div class=«game-container»>
<canvas id=«gameCanvas»></canvas>
<!— Интерфейсные элементы —>
</div>

1.2 Пояснение:

  • <canvas> — игровое поле для отрисовки графики
  • Система контроля через data-атрибуты: data-direction

Урок 2: Стилизация CSS

Цель: Создать адаптивный дизайн
2.1 Основные правила:

gameCanvas {

max-width: 600px;
image-rendering: crisp-edges; /* Сглаживание пикселей */
}

2.2 Адаптивность:

  • Медиа-запросы для мобильных устройств
  • Flex-распределение элементов управления

Урок 3: Инициализация игры

Цель: Настроить базовую логику
3.1 Основные константы:

const gridSize = 20; // Размер клетки
const BASE_SPEED = 400; // Начальная скорость

3.2 Состояние игры:

  • Змейка: массив координат
  • Еда: объект с позицией
  • Направление движения: строковая переменная

Урок 4: Игровой цикл и движение

Цель: Реализовать движение змейки
4.1 Алгоритм движения:

function moveSnake() {
const head = {…snake[0]};
// Обновление координат головы
snake.unshift(head);
if(!eaten) snake.pop();
}

4.2 Система скоростей:

  • Динамическое изменение интервала setInterval
  • Формула ускорения: speedMultiplier *= (1 - SPEED_INCREMENT)

Урок 5: Коллизии и взаимодействия

Цель: Реализовать столкновения
5.1 Проверка столкновений:

if(
head.x < 0 || head.x >= tileCount ||
snake.some(segment => …)
) gameOver();

5.2 Генерация еды:

  • Рекурсивная проверка свободных клеток
  • Использование Math.random()

Урок 6: Управление и UI

Цель: Добавить интерактивность
6.1 Обработчики событий:

document.addEventListener(‘keydown’, (e) => {
// Логика изменения направления
});

6.2 Система паузы:

  • Переключение состояния через isPaused
  • Обновление текста кнопок

Дополнительные задания:

  1. Добавить систему рекордов с LocalStorage
  2. Реализовать разные уровни сложности
  3. Создать меню выбора скинов для змейки
  4. Добавить звуковые эффекты

Рекомендации по улучшению кода:

  1. Рефакторинг:

// Было
function a() { … }
function b() { … }

// Стало
const Game = {
init() {},
draw() {},
move() {}
}

  1. Добавить Webpack для сборки
  2. Реализовать ООП-подход

Типичные ошибки:

  1. Некорректная работа ресайза:
  • Забыть вызвать resizeCanvas() при инициализации
  1. Наложение элементов:
  • Проверить z-index в CSS
  1. Мобильное управление:
  • Добавить touchstart обработчики

Весь код написан DeepSeek

<div class=«game-container»>
<canvas id=«gameCanvas»></canvas>
<div id=«score»>Счет: 0</div>
<div id=«speed»>Скорость: 100%</div>
<div class=«controls»>
<button id=«startBtn»>Старт</button>
<button id=«pauseBtn»>Пауза</button>
</div>
<div class=«instructions»>
<h3>🎮 Как играть:</h3>
<p>📱 На телефоне: жми кнопки внизу<br>
💻 На компьютере: используй стрелки ←↑→↓</p>
</div>
<div class=«mobile-controls»>
<button class=»arrow-btn» data-direction=»up»>↑</button>
<div>
<button class=»arrow-btn» data-direction=»left»>←</button>
<button class=»arrow-btn» data-direction=»down»>↓</button>
<button class=»arrow-btn» data-direction=»right»>→</button>
</div>
</div>
</div>

<style>
.game-container {
text-align: center;
margin: 0 auto;
max-width: 100%;
padding: 10px;
}

#gameCanvas {
width: 100% !important;
height: auto !important;
max-width: 600px;
max-height: 80vh;
border: 2px solid #333;
background-color: #87CEEB;
image-rendering: crisp-edges;
}

.controls button {
padding: 10px 20px;
font-size: 16px;
margin: 10px 5px;
cursor: pointer;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
}

#pauseBtn {
background-color: #f44336;
}

.instructions {
background: #fff3cd;
padding: 15px;
border-radius: 10px;
margin: 15px auto;
max-width: 400px;
}

.mobile-controls {
display: none;
margin-top: 20px;
}

.arrow-btn {
font-size: 30px;
width: 60px;
height: 60px;
margin: 5px;
border-radius: 50%;
background: #4CAF50;
color: white;
border: none;
cursor: pointer;
}

@media (max-width: 600px) {
.mobile-controls {
display: block;
}
}
</style>

<script>
const canvas = document.getElementById(‘gameCanvas’);
const ctx = canvas.getContext(‘2d’);
const startBtn = document.getElementById(‘startBtn’);
const pauseBtn = document.getElementById(‘pauseBtn’);
const scoreElement = document.getElementById(‘score’);
const speedElement = document.getElementById(‘speed’);
const gameContainer = document.querySelector(‘.game-container’);

// Настройки игры
let gridSize = 20;
let tileCount;
const BASE_SPEED = 400;
const SPEED_INCREMENT = 0.05;

// Состояние игры
let snake = [];
let food = {};
let direction = ‘right’;
let score = 0;
let gameLoop = null;
let isPaused = false;
let currentSpeed = BASE_SPEED;
let speedMultiplier = 1;

// Инициализация размеров
function resizeCanvas() {
const containerWidth = gameContainer.clientWidth;
const maxSize = Math.min(containerWidth, window.innerHeight * 0.6);
const canvasSize = Math.min(maxSize, 600) — 20;

canvas.width = Math.floor(canvasSize / gridSize) * gridSize;
canvas.height = canvas.width;
tileCount = Math.floor(canvas.width / gridSize);

if(!gameLoop) drawStartScreen();
}

function drawStartScreen() {
ctx.fillStyle = ‘#87CEEB’;
ctx.fillRect(0, 0, canvas.width, canvas.height);

ctx.fillStyle = ‘white’;
ctx.font = ’30px Arial’;
ctx.textAlign = ‘center’;
ctx.fillText(‘Игра DeepSeek’, canvas.width/2, canvas.height/2);

ctx.font = ’20px Arial’;
ctx.fillText(‘Нажмите «Старт» чтобы начать’, canvas.width/2, canvas.height/2 + 40);
}

function initGame() {
snake = [{x: 5, y: 5}];
food = generateFood();
direction = ‘right’;
score = 0;
currentSpeed = BASE_SPEED;
speedMultiplier = 1;
scoreElement.textContent = `Счет: ${score}`;
updateSpeedDisplay();
}

function generateFood() {
while(true) {
const newFood = {
x: Math.floor(Math.random() * tileCount),
y: Math.floor(Math.random() * tileCount)
};
if (!snake.some(segment => segment.x === newFood.x && segment.y === newFood.y)) {
return newFood;
}
}
}

function drawGame() {
ctx.fillStyle = ‘#87CEEB’;
ctx.fillRect(0, 0, canvas.width, canvas.height);

// Отрисовка змейки
snake.forEach((segment, index) => {
ctx.fillStyle = index === 0 ? ‘#0096ff’ : ‘#00c8ff’;
ctx.beginPath();
ctx.roundRect(
segment.x * gridSize,
segment.y * gridSize,
gridSize — 2,
gridSize — 2,
5
);
ctx.fill();

if(index === 0) {
ctx.fillStyle = ‘white’;
ctx.font = ’12px Arial’;
ctx.textAlign = ‘center’;
ctx.fillText(‘DS’,
segment.x * gridSize + gridSize/2,
segment.y * gridSize + gridSize/2 + 4
);
}
});

// Отрисовка еды
ctx.fillStyle = ‘#ff6b6b’;
ctx.beginPath();
ctx.arc(
food.x * gridSize + gridSize/2,
food.y * gridSize + gridSize/2,
gridSize/2 — 2,
0,
Math.PI * 2
);
ctx.fill();
}

function moveSnake() {
if(isPaused) return;

const head = {…snake[0]};

switch(direction) {
case ‘up’: head.y—; break;
case ‘down’: head.y++; break;
case ‘left’: head.x—; break;
case ‘right’: head.x++; break;
}

// Проверка столкновений
if (head.x < 0 || head.x >= tileCount ||
head.y < 0 || head.y >= tileCount ||
snake.some(segment => segment.x === head.x && segment.y === head.y)) {
gameOver();
return;
}

snake.unshift(head);

if (head.x === food.x && head.y === food.y) {
score += 10;
scoreElement.textContent = `Счет: ${score}`;
food = generateFood();
increaseSpeed();
} else {
snake.pop();
}

drawGame();
}

function increaseSpeed() {
speedMultiplier *= (1 — SPEED_INCREMENT);
currentSpeed = BASE_SPEED * speedMultiplier;
updateSpeedDisplay();
restartGameLoop();
}

function updateSpeedDisplay() {
const percentage = Math.round((1 / speedMultiplier) * 100);
speedElement.textContent = `Скорость: ${percentage}%`;
}

function restartGameLoop() {
clearInterval(gameLoop);
gameLoop = setInterval(() => moveSnake(), currentSpeed);
}

function gameOver() {
clearInterval(gameLoop);
gameLoop = null;
alert(`Игра окончена! Счет: ${score}`);
startBtn.textContent = ‘Старт’;
drawStartScreen();
}

function togglePause() {
isPaused = !isPaused;
startBtn.textContent = isPaused ? ‘Продолжить’ : ‘Пауза’;
}

// Обработчики событий
startBtn.addEventListener(‘click’, () => {
if(!gameLoop) {
initGame();
restartGameLoop();
startBtn.textContent = ‘Пауза’;
} else {
togglePause();
}
});

pauseBtn.addEventListener(‘click’, togglePause);

document.addEventListener(‘keydown’, (e) => {
switch(e.key) {
case ‘ArrowUp’: if (direction !== ‘down’) direction = ‘up’; break;
case ‘ArrowDown’: if (direction !== ‘up’) direction = ‘down’; break;
case ‘ArrowLeft’: if (direction !== ‘right’) direction = ‘left’; break;
case ‘ArrowRight’: if (direction !== ‘left’) direction = ‘right’; break;
}
});

document.querySelectorAll(‘.arrow-btn’).forEach(btn => {
btn.addEventListener(‘click’, () => {
const newDir = btn.dataset.direction;
if(
(direction === ‘up’ && newDir === ‘down’) ||
(direction === ‘down’ && newDir === ‘up’) ||
(direction === ‘left’ && newDir === ‘right’) ||
(direction === ‘right’ && newDir === ‘left’)
) return;
direction = newDir;
});
});

// Инициализация
resizeCanvas();
window.addEventListener(‘resize’, resizeCanvas);
drawStartScreen();
</script>


Like this post? Please share to your friends:
DeepSeek
Comments: 1
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: