Создание игры 2048 на JavaScript пошаговое руководство

Как сделать игру 2048 javascript

Содержание статьи

Как сделать игру 2048 javascript

Игра 2048 представляет собой логическую головоломку, где цель – объединять одинаковые числа на сетке 4×4 до появления числа 2048. Для реализации на JavaScript достаточно использовать стандартные элементы HTML, такие как div для клеток и table или flex-контейнер для сетки, без применения Canvas.

Основная логика игры строится на обработке событий клавиатуры. Необходимо отслеживать нажатия стрелок, сдвигать числа в соответствующем направлении и объединять одинаковые значения. Рекомендуется использовать массив 4×4 для хранения текущего состояния сетки и функции для обновления визуального отображения при каждом ходе.

Создание функции spawnTile() позволяет случайным образом добавлять новые числа (2 или 4) после каждого хода. Для проверки возможных ходов и окончания игры стоит реализовать отдельную функцию checkGameOver(), которая анализирует наличие пустых клеток и возможность объединения соседних значений.

Для оптимизации кода удобно разделить функционал на модули: управление сеткой, обработка ввода, логика объединения чисел и обновление DOM. Такой подход упрощает отладку, позволяет легко менять размеры сетки и добавлять дополнительные функции, например, счетчик очков или возможность отмены хода.

Настройка HTML и CSS для игрового поля

Настройка HTML и CSS для игрового поля

Создайте контейнер для игрового поля с классом game-container. Он должен иметь фиксированные размеры, например 400px на 400px, и позиционирование relative для корректного размещения плиток внутри.

Для каждой плитки используйте div с классом tile. Задайте плиткам одинаковую ширину и высоту, равные 90px, и внутренние отступы 10px для расстояния между плитками. Примените border-radius 5px для скругленных углов.

Используйте CSS Grid для разметки игрового поля. У контейнера game-container задайте display: grid, grid-template-columns: repeat(4, 1fr) и grid-gap: 10px для равномерного распределения плиток с промежутками.

Назначьте фоновый цвет контейнеру, например #bbada0, и плиткам – #eee4da для начального состояния. Для плиток с разными значениями предусмотрите отдельные классы tile-2, tile-4 и так далее с соответствующими цветами.

Добавьте текстовое выравнивание внутри плиток с помощью display: flex, justify-content: center и align-items: center. Размер шрифта можно задать через font-size: 24px, а цвет текста – #776e65 для четкости.

Для анимации появления и слияния плиток используйте CSS-трансформации: transition: transform 0.2s ease, background-color 0.2s ease. Это обеспечит плавное перемещение и смену цветов при обновлении значений плиток.

Обеспечьте адаптивность игрового поля с помощью медиа-запросов: уменьшайте размеры контейнера и плиток на экранах шириной меньше 400px, чтобы сохранить удобство управления на мобильных устройствах.

Создание массива для хранения состояния клеток

Создание массива для хранения состояния клеток

Для управления состоянием игрового поля используется двумерный массив размером 4×4. Каждая ячейка массива хранит число, соответствующее значению плитки, или 0, если клетка пустая.

Инициализация массива выполняется через цикл, чтобы гарантировать создание отдельных вложенных массивов для каждой строки, предотвращая случайное изменение всех строк при обновлении одной.

Пример инициализации:

let grid = Array.from({ length: 4 }, () => Array(4).fill(0));

При каждом ходе значения массива обновляются в соответствии с движением плиток. Это позволяет функции рендеринга точно отображать текущее состояние на игровом поле.

Для генерации новой плитки после хода используется поиск пустых ячеек через метод flatMap или циклы, выбирается случайная позиция, в которой устанавливается значение 2 или 4 с вероятностью 90% и 10% соответственно.

Хранение состояния через массив облегчает проверку условий победы или проигрыша: проверяется наличие плиток с числом 2048 и возможность объединения соседних плиток с одинаковыми значениями.

Добавление начальных чисел на поле

Для добавления начальных чисел выполняются следующие действия:

  1. Определить список пустых клеток. Пройтись по массиву поля и собрать координаты всех элементов с нулевым значением.
  2. Выбрать случайную клетку из списка пустых. Для этого можно использовать функцию генерации случайного индекса.
  3. Присвоить выбранной клетке значение 2 или 4. Вероятность появления числа 4 обычно составляет 10–20%, остальное – 2.
  4. Повторить процесс для второй стартовой клетки, убедившись, что она отличается от первой.

Пример реализации на JavaScript:


function addInitialNumbers(grid) {
let emptyCells = [];
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[i].length; j++) {
if (grid[i][j] === 0) emptyCells.push({x: i, y: j});
}
}
javascriptCopy codefor (let n = 0; n < 2; n++) {
let randomIndex = Math.floor(Math.random() * emptyCells.length);
let cell = emptyCells.splice(randomIndex, 1)[0];
grid[cell.x][cell.y] = Math.random() < 0.1 ? 4 : 2;
}
}

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

Реализация движения плиток по направлениям

Для движения плиток создаём четыре функции: moveLeft(), moveRight(), moveUp(), moveDown(). Каждая функция перебирает массив состояния клеток и сдвигает числа в указанном направлении, объединяя одинаковые значения.

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

После объединения формируем новый ряд или столбец, добавляя пустые клетки в конец (для движения влево/вверх) или в начало (для движения вправо/вниз), и записываем результат обратно в массив состояния.

Для обновления визуального состояния используем отдельную функцию renderGrid(), которая читает массив и изменяет содержимое и классы элементов DOM, соответствующих каждой клетке.

Для обработки нажатий клавиш добавляем обработчик события keydown. Каждое нажатие вызывает соответствующую функцию движения и проверку на возможность слияния или появления новых чисел.

После каждого сдвига проверяем, изменилось ли состояние массива. Если изменения есть, вызываем функцию addRandomTile(), которая добавляет новую плитку со значением 2 или 4 в случайную пустую клетку.

При реализации движения важно избегать двойного объединения плиток за один ход: после слияния плитка должна быть помечена как объединённая, чтобы последующие сдвиги в этом ходе не объединяли её повторно.

Объединение плиток с одинаковыми числами

Объединение плиток с одинаковыми числами

В 2048 объединение плиток происходит при движении и столкновении двух одинаковых чисел. Для реализации этого в JavaScript требуется проверить каждую строку или колонку после сдвига и объединить соседние равные значения.

Алгоритм объединения можно реализовать следующим образом:

  1. Сдвинуть все числа в выбранном направлении, чтобы убрать пустые клетки.
  2. Пройтись по сдвинутой линии и проверить соседние плитки.
  3. Если значения соседних плиток равны, объединить их, увеличив значение первой плитки в два раза и очистив вторую.
  4. После объединения снова сдвинуть плитки, чтобы убрать пустые клетки, образовавшиеся после объединений.

Пример функции для объединения одной строки:

function mergeRow(row) {
for (let i = 0; i < row.length - 1; i++) {
if (row[i] === row[i + 1] && row[i] !== 0) {
row[i] *= 2;
row[i + 1] = 0;
}
}
return row.filter(val => val !== 0).concat(Array(row.length).fill(0));
}

Особенности реализации:

  • Объединение происходит только один раз за ход для каждой пары плиток.
  • Порядок объединений важен: сначала сдвиг, затем объединение, затем повторный сдвиг.
  • Для движения вверх или вниз необходимо транспонировать массив и применять ту же логику, что и для строк.
  • После каждого объединения следует проверять, появились ли новые пустые клетки, чтобы корректно добавить новые плитки.

Эта логика позволяет корректно объединять плитки, обновлять состояние игрового поля и поддерживать правильный подсчёт очков при каждой комбинации.

Обновление отображения поля после хода

Обновление отображения поля после хода

После каждого хода необходимо синхронизировать визуальное состояние поля с данными массива клеток. Для этого удобно использовать HTML-таблицу, где каждая ячейка соответствует элементу массива.

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

Для улучшения наглядности можно динамически задавать классы ячейкам в зависимости от числа, например tile-2, tile-4 и так далее. Это позволит изменять цвет и фон каждой плитки через CSS.

Обновление выполняется сразу после завершения всех слияний и перемещений, чтобы игрок видел конечный результат хода. Важно, чтобы вставка новых чисел в массив происходила до обновления таблицы, иначе визуальное состояние не будет соответствовать внутреннему.

Пример подхода с использованием JavaScript:

function updateBoard() {
  for (let i = 0; i < 4; i++) {
    for (let j = 0; j < 4; j++) {
      let cell = document.getElementById(`cell-${i}-${j}`);
      cell.textContent = board[i][j] !== 0 ? board[i][j] : '';
      cell.className = board[i][j] !== 0 ? `tile tile-${board[i][j]}` : 'tile';
    }
  }
}

Этот метод гарантирует точное соответствие между внутренним состоянием массива и визуальным отображением таблицы после каждого хода.

Использование таблицы обеспечивает простую структуру для циклического обновления всех клеток и легко интегрируется с обработчиками клавиш или свайпов.

Обработка победы и проигрыша

Для обработки проигрыша необходимо отслеживать, есть ли свободные клетки или возможные объединения. Если пустых клеток нет и ни одно соседнее значение не совпадает, фиксируйте состояние поражения и вызывайте соответствующую функцию уведомления.

Важно после победы или поражения блокировать обработку клавиш, чтобы исключить дальнейшие ходы. Для этого добавьте проверку состояния игры в обработчики событий клавиатуры и свайпов.

Для повторной игры реализуйте кнопку «Начать заново», которая очищает массив клеток, сбрасывает счет и вызывает функцию добавления двух начальных чисел на поле.

Добавление обработки клавиатуры и свайпов

Для управления игрой 2048 с клавиатуры необходимо отслеживать нажатия стрелок. Используйте событие keydown на объекте document и определяйте направление по свойству event.key. Пример:

document.addEventListener('keydown', function(event) { if(event.key === 'ArrowUp'){ move('up'); } else if(event.key === 'ArrowDown'){ move('down'); } else if(event.key === 'ArrowLeft'){ move('left'); } else if(event.key === 'ArrowRight'){ move('right'); } });

Для мобильных устройств добавьте обработку свайпов. Определите начальные координаты касания через touchstart, а конечные через touchend. Разница по осям X и Y позволит определить направление свайпа:

let startX, startY; document.addEventListener('touchstart', function(e){ startX = e.touches[0].clientX; startY = e.touches[0].clientY; }); document.addEventListener('touchend', function(e){ let endX = e.changedTouches[0].clientX; let endY = e.changedTouches[0].clientY; let dx = endX - startX; let dy = endY - startY; if(Math.abs(dx) > Math.abs(dy)){ dx > 0 ? move('right') : move('left'); } else { dy > 0 ? move('down') : move('up'); } });

Для точной реакции свайпов рекомендуется учитывать минимальное смещение, чтобы случайные касания не вызывали движение. Например, игнорировать движения меньше 30 пикселей. Такая комбинация обработки клавиатуры и свайпов обеспечивает удобное управление на всех устройствах.

Вопрос-ответ:

Как создать массив для хранения состояния клеток в игре 2048 на JavaScript?

Для хранения состояния игрового поля создают двухмерный массив 4×4, где каждая ячейка соответствует одной клетке. Значение 0 обозначает пустую клетку, а числа 2, 4, 8 и так далее — занятые. Массив позволяет отслеживать положение и значения плиток, управлять их перемещением и объединением, а также проверять условия победы и поражения.

Каким образом реализовать движение плиток по направлениям?

Движение плиток выполняется по строкам и столбцам массива. При сдвиге нужно сначала сдвинуть все значения к выбранной границе, затем объединить соседние одинаковые числа и снова сдвинуть плитки, чтобы убрать промежутки. Логика должна отдельно обрабатывать четыре направления: вверх, вниз, влево и вправо, используя циклы и условные проверки.

Как добавить обработку нажатий клавиш и свайпов для управления игрой?

Для клавиатуры используют обработчик события ‘keydown’, проверяя коды стрелок. Для мобильных устройств добавляют обработку свайпов через события ‘touchstart’ и ‘touchend’, вычисляя разницу координат касаний по горизонтали и вертикали, чтобы определить направление. После определения направления вызывается функция сдвига и объединения плиток.

Каким образом обновлять отображение поля после хода игрока?

После каждого хода необходимо синхронизировать массив состояния с визуальным представлением. Обычно это делается через перерисовку всех клеток: очищают игровое поле, затем создают HTML-элементы для каждой плитки с соответствующими значениями и стилями. Можно использовать классы для различных чисел, чтобы изменить цвет и размер плиток автоматически.

Как реализовать проверку условий победы и поражения в игре 2048?

Победа фиксируется, когда на поле появляется плитка со значением 2048. Проверка поражения включает два условия: отсутствие пустых клеток и невозможность объединить соседние плитки по горизонтали и вертикали. Если оба условия выполняются, игра считается завершенной. Для информирования игрока используют всплывающие сообщения или отображение специального экрана с результатом.

Как реализовать движение плиток в игре 2048 на JavaScript?

Для движения плиток необходимо обрабатывать ввод пользователя с клавиатуры или свайпы, определять направление сдвига и изменять массив, который хранит состояние поля. Сначала нужно пройтись по каждой строке или столбцу в зависимости от направления движения и сдвинуть все числа к одному краю. При этом пустые клетки пропускаются, а одинаковые числа, которые встречаются друг за другом, объединяются в одну плитку с суммой значений. После обновления массива следует перерисовать поле, чтобы изменения были видны игроку. Такой подход позволяет управлять движением плиток без потери их текущих значений и сохраняет логику объединений по правилам игры.

Ссылка на основную публикацию