Собирать цветные камни – лучший способ убить время. Заглянем под капот игры Bejeweled и создадим ее с нуля с помощью jQuery. Присоединяйтесь!
Инструменты
Что нам понадобится для создания игры?
-
3 версии – для более легкой работы с DOM-деревом; – для удобной обработки пользовательских событий;
- начальные знания HTML, CSS и JavaScript основы;
- любовь к казуальным играм.
Безусловно, можно обойтись без библиотек и плагинов. Язык JavaScript имеет достаточно возможностей для работы со страницей и пользовательскими событиями. Но если вы начинающий разработчик, эти инструменты существенно упростят вам жизнь.
Начало работы
Создаем файл index.html , который будет представлять нашу игру. Подключаем все необходимые скрипты – их всего три:
- сама библиотека jQuery (возьмем ее с CDN);
- скрипт плагина, который должен лежать в той же папке (можно загрузить из официального репозитория);
- скрипт игры bejeweled.js , который нам и предстоит написать (этот файл лежит в той же папке и пока пуст).
Состояния игры
Сразу определимся, в каких состояниях (стадиях) может находиться игровой процесс:
- pick – ожидаем, когда пользователь выберет гем (первый или второй рядом с первым);
- switch – после выбора второго гема меняем их местами;
- revert – после свитча не появилось групп сбора, возвращаемся к исходному состоянию (меняем позиции гемов обратно);
- remove – после свитча появились группы сбора, которые нужно удалить;
- refill – после удаления групп сбора нужно заполнить образовавшиеся пустоты новыми гемами.
Игровое поле
Поле для игры в Bejeweled представляет собой простую двумерную сетку, на которой располагаются гемы (драгоценные камни). Их необходимо удалять, собирая в группы одного цвета.
В нашей реализации для простоты будут учитываться только вертикальные или горизонтальные группы размером от трех камней (и более).
Примеры допустимых групп:
Первая попытка
Давайте определим основные параметры игры, нарисуем поле и заполним его гемами.
- Мы создали поле размером 7х6 ячеек и представляющий его массив jewels .
- Для начала заполнили его значениями -1 – отсутствие гема.
- Затем прошлись циклом по каждой ячейке, выбрали случайным образом цвет и записали его в jewels . Также создали DOM-элемент, который представляет гем на странице.
Есть проблема: на поле еще до начала игры появляются группы сбора (вертикальные и горизонтальные группы из 3 и более гемов одного цвета). Это происходит из-за того, что цвета мы выбираем случайным образом.
Проверка на группы сбора
Добавим проверку после выбора цвета для нового гема. Если он вдруг составит группу сбора с уже существующими на поле камнями, просто поменяем цвет.
Функция isVerticalStreak проверяет соседей по вертикали, а isHorizontalStreak – соответственно по горизонтали. Если где-то получится больше двух гемов одного цвета, создадим другой гем.
Обработка действий игрока
Чтобы наша Bejeweled заработала, нужно отслеживать, какие гемы выбирает игрок, менять их местами и убирать появившиеся группы.
Язык программирования JavaScript умеет работать со множеством пользовательских событий – кликами, тачами, движениями мыши и др. Организовать все это в единую рабочую (а также кроссбраузерную и кроссплатформенную!) систему очень непросто. Так давайте отдадим тяжелую и скучную работу плагину touchSwipe.
Начнем с простых тапов/кликов. Попробуйте кликнуть мышкой на поле – в консоли появится сообщение и выведется тот гем, на который вы нажали.
Игровые операции
Выделение активного гема
Чтобы было понятно, какой камень выбрал игрок, нужно его каким-то образом выделять. Для этого добавим элемент-маркер на поле:
А при клике на гем, поместим маркер прямо над ним:
Меняем гемы местами
Если игрок выбирает первый гем из двух, мы только сохраним его позицию в переменных selectedRow и selectedCol .
А вот если выбран уже второй гем, нужно проверить, является ли он соседом для первого.
Функция gemSwitch меняет местами два гема как на поле, так и в массиве jewels :
Вводим еще одну функцию – checkMoving . Она будет проверять, появились ли на поле группы сбора после свитча.
Проверка хода
Переменная movingItems хранит количество движущихся в данный момент гемов. Функция checkMoving вызывается после завершения каждой анимации, но отработать должна только тогда, когда все камни остановятся. Для этого мы просто каждый раз уменьшаем счетчик на единицу.
checkMoving – главная функция в нашей головоломке. Она будет проверять поле после каждого действия, поэтому мы добавим в нее конструкцию switch для разных состояний игры:
Если ни один из выбранных камней не образовал группу сбора, меняем состояние игры на revert и двигаем их обратно.
После реверта мы снова попадем в эту функцию. В данном случае просто сбрасываем выбор и устанавливаем gameState = “pick” .
Если группы сбора обнаружены, их нужно удалить.
Удаление групп сбора
Гемы из группы сбора нужно убрать с поля и из массива jewels . Сначала пометим их DOM-элементы классом remove :
А затем красиво уберем их со страницы:
После всех анимаций вновь проверим поле вызовом функции checkMoving .
Сдвигание гемов
После удаления необходимо опустить все камни, оказавшиеся над пустыми клетками. Добавим это действие в функцию checkMoving :
А вот и сама функция checkFalling :
Когда все камни опущены вниз, снова проверяем поле – checkMoving .
Если же опускать больше нечего, поле нужно снова заполнить. Для этого меняем состояние игры на refill .
Заполнение пустот
Функционал игры практически готов, осталось лишь заполнять поле камнями после удаления и запускать новый цикл игры.
Для этого добавим еще один case в функции checkMoving :
И реализуем функцию placeNewGems :
Не забываем про все проверки – вуа-ля! – наша игра готова 😉
Добавляем свайп c jQuery плагином
Можно сделать Bejeweled еще красивее и удобнее, добавив возможность двигать камни с помощью свайпов. Вот где нам пригодится плагин touchSwipe. Он замечательно обрабатывает жесты игрока и предоставляет для этого очень удобный интерфейс:
Вы можете немного поиграть с полем, чтобы понять, как работают свойства swipe и swipeStatus .
Реализуем обработчики. swipeStatusHandler будет отслеживать начало свайпа и записывать первый выделенный гем. swipeHandler сделает все остальное:
- отследит направление движения;
- найдет второй гем;
- запустит свитч.
Весь остальной функционал уже готов! Вы можете наслаждаться любимой головоломкой.