Как сделать три в ряд

Делаем игру «Три в ряд» («Match-3») в программе Construct 2: Основы

Добро пожаловать в новую серию обучающих статей, в которой я покажу вам, как создать с нуля игру-головоломку «Три в ряд» в программе Construct 2. В этой первой части самоучителя мы подготовим фундамент для нашей игры и выведем на экран поле из блоков головоломки.

Введение

Большая часть таких игр является соревновательной по природе и цель игрока в основном сводится к набору наивысшего возможного количества очков перед тем, как его время закончится или выполнится другое условие проигрыша. Примерами игр «Три в ряд» могут служить Pokemon Puzzle League, Bejeweled, и недавний хит Candy Crush Saga.

Игра, которую мы будем делать

Я решил базировать нашу игру «Три в ряд», которую мы будем делать, на игре Pokemon Puzzle League:

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Если вы раньше никогда не играли в PPL, то это довольно простая игра серии «Три в ряд», в которой блоки поднимаются снизу игрового экрана и игроку нужно создавать группы из блоков, чтобы не дать игровому экрану заполниться ими. Если блоки достигают верха экрана, то игрок проигрывает и игра начинается заново.

Здесь дается демонстрация игры, над созданием которой мы будем работать в этих частях самоучителя:

В этой первой части мы сфокусируемся над созданием фундамента нашей игры. В частности, в ней мы подготовим наш проект и выведем для игрока на экран квадратное поле из случайных блоков.

Перед тем, как начать

Перед тем, как начать работать с этой частью самоучителя, вам нужно убедиться, что у вас установлена новейшая версия программы Construct 2 (C2). Когда я создавал оригинальную версию этой игры, я использовал версию 122, и если у вас установлена более новая версия программы, то все должно работать, как нужно. Также, если вы никогда еще не работали с программой C2, то вам нужно сначала обратиться к этому руководству в котором дается детальное описание основ пользования программой C2 и создания большинства различных типов объектов.

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

Итак, после того, как вы все подготовили для работы и имеете хорошее понимание программы C2, будем двигаться дальше!

Подготовка проекта

Перед тем, как начать работу над механизмом игры, нам нужно подготовить сам проект. Запустите C2 и следуйте следующим шагам:

И в конце нам нужно создать фон для поля, где будут появляться блоки.

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

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

Создание квадратного поля из блоков

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

Перейдите на Страницу событий 1 (Event Sheet 1) и добавьте следующие глобальные переменные, чтобы определить начальную позицию появления блоков:

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Также нам нужно сделать еще одну вещь перед созданием первого события: нам нужно создать переменную для объекта Блок (Block), которая указывает, какого он цвета

Создайте новую переменную для объекта Блок (Block), назовите ее Цвет (Color) и оставьте остальные настройки без изменений.

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Теперь мы создадим наше первое событие. Целью этого события является создание статичного поля из блоков в качестве теста:

Обе эти формулы в основном обозначают одно и то же. Сначала мы добавляем 2 к ширине блока (Block.Width), что создает буфер в 2 пикселя между соседними блоками для избежания ошибок во время определения столкновения. Затем мы умножаем это число на текущее значения индекса цикла «For» (loopIndex) и добавляем это значение к начальной позиции X (SPAWNX) или Y (SPAWNY). Также, мы отнимаем из значения Y, так как в C2 точка 0 на оси Y находится вверху игрового экрана, поэтому, уменьшая значение позиции Y, мы помещаем объект ближе к верху экрана.

Итак, что же выполняет это событие? Оно означает, что когда выполняется цикл по X и Y и значения их возрастают, изменяется позиция появления каждого из блоков, что в результате приводит к созданию квадратного поля из блоков:

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в рядКак сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

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

Чтобы исправить это, нам нужно сделать две вещи.

Вначале каждому блоку нужно придать значение цвета, используя переменную объекта «цвет» («color»), созданную нами ранее. Для этого добавьте следующее Действие (Action):

Ваша функция должна выглядеть так:

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в рядКак сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Нам также нужно добавить систему, меняющую изображение блока, базируясь на его значении. Для этого мы добавим новую переменную объекта Блок:

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Теперь добавим новое событие:

В этой формуле сначала мы отнимаем 1 от значения цвета блока, так как это значение начинается с 0, а не с 1. Затем умножаем эту цифру на 3, так как каждый блок имеет 3 кадра анимации. И, наконец, добавляем 1 к этому значению, так как стандартное изображение блока является первым изображением в группе.

Давайте рассмотрим небольшой пример, где блок будет иметь значение цвета равное 4, с целью определить, какой кадр анимации он будет использовать. Сначала отнимем 1 от значения его цвета и получим число 3. Затем умножим его на 3, получив 9. И, наконец, добавим к нему 1, получив число 10. Это значит, что блок со значением цвета, равным 4 будет использовать 10-й кадр в качестве кадра по умолчанию и будет блоком фиолетового цвета с квадратом на нем.

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

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

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в рядКак сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в рядКак сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд Щелкните мышкой для запуска демонстрации игры.

Если вы захотите самостоятельно продолжить работу над этой игрой, попробуйте поискать способ смены анимации блока, основываясь на событии «Мышь > Курсор мыши над объектом» («Mouse > Cursor is over object»). Также вы можете попробовать использовать Поведение «Перетаскивание» («Drag & Drop» behavior), чтобы манипулировать блоком, и попробуйте решить вопрос о том, что игрок пробует сделать с блоком, когда он начинает его перетаскивать или отпускает его.

Заключение

Спасибо за прочтение этой части самоучителя, где мы подготовили фундамент для нашей игры «Три в ряд». До встречи в следующей его части! Чтобы оставаться в курсе новостей используйте Facebook, Twitter, Google+, RSS или email.

Источник

Как сделать три в ряд

Главная » ActionScript 3: Создание игры «три-в-ряд» Bejeweled (первая часть)

ActionScript 3: Создание игры «три-в-ряд» Bejeweled (первая часть)

Bejeweled первая «современная» (первый релиз игры состоялся в 2001 году) игра, которая будет рассмотрена в этой книге. Я решил посвятить последние три главы этой книги современным играм, чтобы показать вам, как относительно легко можно создать код большинства современных успешных казуальных игр, а это значит, что в этой нише рынка хорошие идеи преобладают над сложностью игры. Миллионы копий Bejeweled были проданы, и в их Facebook версии играют миллионы людей каждый месяц.

Игра происходит на сетке размером 8×8 с 64 драгоценными камнями семи различных видов, расположенных на ней. Цель — обменивать местами драгоценный камень с соседним, чтобы сформировать горизонтальную или вертикальную линию из трех и более драгоценных камней. Эти камни затем исчезают и сверху падают новые, чтобы заполнить пробелы.

В этой главе вы напишете полностью рабочий код прототипа Bejeweled, изучив следующие методы:

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

Создание документов и объектов

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

Затем нарисуйте что-то вроде этого:

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Размещение драгоценных камней

Размещение драгоценных камней на сцене может показаться простым делом — добавить какие-то случайные объекты типа DisplayObject в список отображения (Display List), но вы увидите, что мы скоро столкнемся с некоторыми трудностями.

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

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

Два цикла for будут заполнять массив случайными числами, когда объекты типа gem_mc будут помещаться на сцену.

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

Я также дал имя этому экземпляру класса DisplayObject, чтобы сделать его выбор мышью более легким при необходимости. Имя состоит из номера, за которым стоит знак подчеркивания, далее идет номер столбца. Вы уже видели эту концепцию во время разработки игры «сапер».

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

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

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

Проверка комбинаций драгоценных камней в начале игры

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

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

Разработка: Проверка линии не отличается от проверки на победу в игре «Connect 4». Можно даже сказать, что это намного проще, поскольку нужно просматривать только по горизонтали и вертикали, не заботясь о диагонали.

Следуя концепциям, рассмотренным во время создания игры «Connect 4», давайте начнем с создания основных функций.

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

Функция просто проверяет, чтобы значение элемента массива jewels[row][col] равнялось gem, как только мы проверили, что это не нулевое значение. Могут быть нулевые значения, когда мы пытаемся найти драгоценный камень в неверной позиции, которая находится за пределами заполненного массива.

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

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

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

Это функция rowStreak с аргументами row и col, представляющими позицию проверяемого драгоценного камня, которая возвращает количество совпадающих драгоценных камней.

Давайте кратко рассмотрим код:

Переменная streak будет сохранять счетчик (count) строки. Он установлен на 1 потому что начальный драгоценный камень сам по себе, который является частью линии.

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

Этот цикл while сканирует драгоценные камни слева. Так как переменная tmp — это значение столбца, уменьшение которого означает перемещение одного столбца влево. Вот что мы делаем внутри цикла:

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

Как только мы выходим из цикла, значение переменной tmp сохраняется в col и мы начинаем сканирование справа таким же образом.

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

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

Как только мы узнаем, что есть линия-комбинация, то мы так же можем предотвратить функцию jewelsInit для ее генерации. Мы просто запустим генерацию случайного драгоценного камня, пока он не станет частью линии-комбинации.

Изменим функцию jewelsInit следующим образом:

Теперь проверьте приложение, и вы не увидите каких-либо линий-комбинаций.

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Главная работа происходит в цикле do while, используемом в функции.

Цикл do while работает также как и цикл while, за исключением того, что код в цикле выполняется хотя бы раз, потому что условие while проверяется в конце блока цикла.

Теперь можно поиграть и проверить приложение.

Это первая часть урока по созданию игры «три-в-ряд» Bejeweled на ActionScript 3 из книги «Flash game development by example» Emanuele Feronato. Если вам понравился урок, то добавьте его в закладки социальных сетей и сохраните (значки внизу).

Источник

Создание игры Match-3 в Unity

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд

Несколько лет назад на SeishunCon я заново открыл для себя игры match-3. Я играл в Dr. Mario детстве, но такие более соревновательные игры, как Magical Drop, Bust-A-Move и Tokimeki Memorial Taisen Puzzle-Dama, сильно отличаются от неё.

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд
Dr. Mario

В результате я осознал, как много нейтральных решений связано с созданием игры match-3.

На следующем джеме Ludum Dare я решил поэкспериментировать, но сначала за неделю до этого для разогрева попробовал разработать алгоритм «Тетриса», обнаруживающий и удаляющий линии. Мне очень помог этот туториал Unity Plus. [Прим. пер.: у меня ссылка не открывается. Если вы знаете, как решить проблему, напишите мне, я дополню статью.] Разумеется, алгоритм «Тетриса» для поиска заполненных рядов гораздо проще, чем алгоритм, выискивающий разнообразные сочетания совпадающих тайлов.

Если вы хотите изучить эти примеры кода в контексте, то зайдите в мой репозиторий Ludum Dare 30. (Для бесстыдной саморекламы я снова использовал эту логику для игры Shifty Shapes.)

Два мира

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд
Magical Drop 3 (источник: Kazuya_UK)

Самая мудрёная часть создания игры-головоломки в Unity заключается в том, что игра не живёт в пространстве мира. Во всяком случае, живёт не полностью.

В этом её отличие от других жанров. Платформеры, например, почти полностью живут в игровом мире Unity. Transform игрока сообщает о его положении. Коллайдеры (или, в некоторых случаях, raycast) говорят, находится ли игрок на земле, ударяется ли об потолок или столкнулся с врагом. Даже если вы не используете внутриигровую физику, то всё равно, скорее всего, добавляете силу или указываете скорость Rigidbody, чтобы обеспечить распознавание столкновений без затрат.

Игры-головоломки совсем другие. Если в вашей игре нужно щёлкать мышью, то она наверно получает какие-то координаты в пространстве мира, но их обычно преобразовывают в ячейку сетки, которая полностью живёт в коде. Для этого есть понятная причина: гораздо проще создать логику для такой игры как Tetris или Dr. Mario, когда работаешь не с отдельными пикселями, а с блоками или тайлами.

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд
Блоки «Тетриса» определённо не должны прилипать к стенкам стакана

На самом деле, в своих экспериментах я стремился как можно больше придерживаться пространства мира. Я использовал физику для определения «приземления» тайлов и передавал данные в двухмерный массив только для определения заполнения строки. Это казалось более безопасным: в конце концов, то, что происходит в игровом мире реально. Именно это видит игрок, поэтому если хранить данные тут, то нет риска рассинхронизации, правда?

Я ошибался. Как бы я ни пытался настроить систему, она просто не работала правильно.

Туториал Unity Plus, ссылку на который я дал выше, оказал мне огромную помощь. Как минимум, он показал, что правильным подходом был полный перенос логики из игрового мира в абстрактную структуру данных. Если вы ещё этого не сделали, то хотя бы вкратце просмотрите его, потому что в этой статье я расширю логику «Тетриса» до логики match-3.

Преобразование из поля в пространство мира

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

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд
Тайлы в сетке

Заметьте, что в этом случае TileSize является константой, определяющей размер тайла в единицах Unity. Я использую тайлы размером 64×64 пикселя, а спрайт в Unity имеет разрешение 100 пикселей на единицу, поэтому TileSize оказывается равным 0.64. Также я использую постоянное смещение, чтобы середина поля 7×7 находилась в координатах 0,0 пространства мира, а левый нижний угол являлся тайлом 0, 0 в игровом пространстве.

Также я создал массив, определяющий игровое поле как статичное поле (static field) в классе Board. (Board сначала был статичным классом, а потом превратился в синглтон (singleton), потому что мне нужно было изменять значения в редакторе, поэтому он неуклюже сочетает в себе черты игрового объекта и статичного класса.)

В туториале Unity Plus двухмерный массив использовался для хранения целых чисел, я же решил хранить в этом массиве ссылки на мои объекты GameTile. Это позволило мне передавать данные от тайлов и к ним напрямую (как вы увидите позже), что упростило удаление тайлов и создание анимации.

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

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

… и обратно

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

Вот, собственно, и всё. Заметьте, что в сущности в нём выполняется действие, обратное UpdatePosition(), где игровое пространство преобразуется в пространство мира.

Распознавание и удаление совпавших тайлов

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд
Удаление совпавших тайлов

Это самая хитрая часть. Наверно, именно ради этого вы читаете статью.

Горизонтальное совпадение (как в «Тетрисе») реализовать довольно просто: нужно всего лишь искать смежные тайлы в одной строке. Даже добавление горизонтальных или вертикальных совпадений (как в Dr. Mario) является просто вариацией этой темы. Однако отслеживание набора смежных тайлов в одновременно горизонтальном и вертикальном направлении потребует рекурсии.

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

Зачем? Мы увидим позже, что так будет гораздо проще определить, какие тайлы мы проверяли.

Мы начинаем процесс с «грубого» перебора. Пройдём от ячейки к ячейке (сначала строки, потом столбцы), проверяя каждую ячейку. Для каждой проверки мы сбрасываем некоторые переменные, используемые для отслеживания проверки, а затем вызываем отдельную функцию (которую позже применим для рекурсии):

Давайте рассмотрим эту функцию TestTile:

Если функция обнаруживает, что ячейка имеет значение null, то пропускает её. Ячейка с null означает, что она или пуста, или мы уже тестировали её. (Именно поэтому мы скопировали её в отдельный массив — так проще произвольно манипулировать новым массивом.)

Если ячейка имеет значение, то мы делаем следующие действия. Во-первых, мы запоминаем её как «текущую» ячейку, ту, которая находится на вершине рекурсивной цепочки. Затем мы удаляем её из копии игрового поля, чтобы не проверять дважды. Также добавляем её в список (List), чтобы запомнить, сколько смежных тайлов одного цвета мы нашли.

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

«Текущая» ячейка уже установлена, и это значит, что мы не на первом уровне рекурсии. В этих вызовах функций у нас есть три варианта для каждой ячейки.

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

Во-вторых, ячейка может не совпадать с «текущей» ячейкой. В этом случае мы не считаем её «проверенной». Наша рекурсия проверяет наличие одного набора смежных тайлов одного цвета. Только потому, что этот тайл не является частью текущего набора, не значит, что он не является частью какого-нибудь другого.

В-третьих, ячейка может быть того же цвета, что и «текущая» ячейка. В таком случае, она «проверена», поэтому мы устанавливаем ей значение null в копии игрового поля. Также мы добавляем её в List, который используем как накопитель. Это одно из состояний, которое мы пропустили в примере выше:

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

Если в накопителе есть больше трёх тайлов, то мы нашли совпадение. Если нет, то мы проверили один или два тайла, но нам не нужно выполнять никаких действий:

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

Падение тайлов

Как сделать три в ряд. Смотреть фото Как сделать три в ряд. Смотреть картинку Как сделать три в ряд. Картинка про Как сделать три в ряд. Фото Как сделать три в ряд
Падающий тайл

Определённые изменения — например, падение тайла или удаление тайлов, в этом случае — оставляют тайлы без опоры, и этот случай нужно разрешить (конечно, если это требуется по правилам вашей игры). И на самом деле это довольно простой алгоритм.

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

В каждом столбце мы проходим снизу вверх, пока не находим пустую ячейку. Затем мы помечаем её. Следующий найденный тайл мы просто смещаем вниз, в это положение, и добавляем единицу к индексу «пустой ячейки»:

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

На самом деле, если в игре ведётся счёт, то это упростит отслеживание комбо или множителей очков. Все эти повторения падений и удаления блоков являются рекурсиями того первого вызова, запущенного действием игрока. Мы можем понять, сколько всего совпадений возникло после действия игрока и какое количество уровней «цепочек» потребовалось для каждого действия.

Анимации

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

Это тоже сложный момент. Игровые объекты всегда являются отражением состояния игры, поэтому тайлы постоянно расположены в сетке. Тайлы всегда занимают то или иное место: тайл может быть в строке 1 или 2, но никогда — в строке 1,5.

В чём заключается сложность? Нам нельзя одновременно манипулировать игровым полем и анимацией. Вспомните, как работает «Тетрис» или Dr. Mario — следующий тайл не падает, пока все тайлы на поле не «улягутся». Это даёт игроку короткую передышку, а также гарантирует отсутствие непредвиденных состояний и взаимодействий.

Кстати, при начале нового проекта я рекомендую создавать перечисление (enumeration) «игровых состояний». Мне никогда не приходилось писать игру, в которой не нужно было знать состояние игры: сам процесс игры, пауза, отображение меню, диалоговое окно, и так далее. Лучше всего спланировать состояния на ранних этапах разработки, таким образом можно сделать так, чтобы каждая написанная вами строка кода проверяла, должна ли она выполняться в текущем состоянии.

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

После завершения анимации удаления игра должна проверить наличие падающих тайлов:

После завершения анимации падения нужно проверить наличие совпадений:

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *