три в ряд исходный код
Три в ряд исходный код
Главная » 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. Если вам понравился урок, то добавьте его в закладки социальных сетей и сохраните (значки внизу).
Создаем игру жанра “Три в ряд” на Unity
В игре “3 в ряд” цель проста: меняйте местами фигурки, пока их не станет 3 или более в один ряд. Когда совпадение сделано, эти плитки удаляются, а пустые места заполняются новыми. Это позволяет игрокам набирать потенциальные комбо и тонны очков!
В этом уроке вы научитесь делать следующее:
Примечание. В этом руководстве предполагается, что вы знакомы с редактором Unity, знаете, как редактировать код в редакторе кода, и что у вас есть базовые знания C#.
Изучите некоторые другие наши уроки по Unity, если вам ещё нужно оттачивать свои навыки в Unity
Начнём
Скачайте стартовый проект Match 3 и извлеките его в каталог по вашему выбору.
Откройте стартовый проект в Unity. Активы отсортированы в нескольких папках:
Создаём игровую доску
Если он еще не открыт, откройте игровую сцену и нажмите кнопку воспроизведения. Это просто синий фон со счетом набранных очков и сделанных ходов. Время это исправить!
Сначала создайте пустой игровой объект и дайте ему имя BoardManager.
BoardManager отвечает за создание доски и ее заполнение тайлами.
Затем найдите BoardManager.cs в папке «Сценарии \ Доска и сетка» в окне «Проект». Перетащите его на пустой игровой объект BoardManager в окошко иерархии.
Теперь у вас должно получиться как на скриншоте:
Пришло время погрузиться в некоторый код. Откройте BoardManager.cs взгляните на код, там уже есть несколько сценариев и скриптов:
1. Другим сценариям потребуется доступ к BoardManager.cs, поэтому сценарий использует шаблон Singleton со статической переменной с именем instance, что позволяет вызывать его из любого сценария.
2. characters – является полным списком спрайтов, которые вы будут использоваться в качестве фрагментов плиток.
3. Игровой объект tile будет служить в качестве префаба, то есть это плитка игрового объекта, будет создана при генерации игрового поля.
4. xSize и ySize – это размеры X и Y платы.
5. Также есть двумерный массив с именами плиток, который будет использоваться для хранения плиток на доске.
6. Инкапсулированный bool IsShifting также очень важный элемент; он сообщит игре, когда совпадение найдено, и игровое поле пополняется новыми плитками.
7. Метод Start () устанавливает синглтон со ссылкой на BoardManager.
8. Вызовите CreateBoard (), передавая границы размера спрайта тайла.
9. В CreateBoard () исходя из названия, будут созданы плитки 2D-массива.
10. Найдите стартовые позиции для генерации доски.
11. Циклически перебирайте xSize и ySize, создавая экземпляр newTile каждую итерацию, чтобы получить сетку из строк и столбцов.
Затем найдите свои спрайты персонажей в разделе «Спрайты \ персонажи» в окне «Проект». Выберите BoardManager в окне Иерархия.
В окне «Инспектора» измените значение «Размер символа» для компонента сценария BoardManager на 7. Это добавит 7 элементов в массив «characters» и отобразит слоты для них в окне «Инспектора».
Теперь перетащите каждого персонажа в пустые слоты. Наконец, найдите префаб Tile внутри каталога Prefabs и перетащите его в слот Tile.
Когда закончите работу, ваша сцена будет выглядеть следующим образом:
Далее снова выбирайте BoardManager. В компоненте BoardManager в окне «Инспектора» задайте «Размер X» на 8 и «Размер Y» на 12. Это размер плитки, с которым вы будете работать в этом учебном пособии.
Нажмите кнопку Играть. Доска генерируется, но она странным образом выходит за пределы экрана:
Это потому, что ваша доска генерирует плитки вверх и вправо, причем первая плитка начинается с позиции BoardManager.
Чтобы это исправить, отрегулируйте положение BoardManager так, чтобы оно находилось внизу слева от поля зрения вашей камеры. Установите позицию X BoardManager на –2,66, а позицию Y на –3,83.
Запускайте игру. Уже выглядит лучше, но игра не будет интересной, если все плитки одинаковы. К счастью, есть простой способ рандомизировать доску.
Вносим элемент случайности в нашу доску
Откройте скрипт BoardManager и добавьте эти строки кода в метод CreateBoard, прямо под плитками [x, y] = newTile ;:
Эти строки делают три ключевых вещи:
Запустите игру, и вы увидите рандомизированную доску:
Как вы возможно заметили, ваша доска может генерировать подходящую комбинацию из 3 в начале, и это невероятно круто
Предотвратите повторение плиток
Плитки генерируется вверх, а затем вправо, поэтому для исправления «автоматического» комбинирования из 3х плиток, вам необходимо определить, какой спрайт находится слева от вашей новой плитки, и какой под вашей новой плиткой.
Для этого вам потребуется создать две переменные Sprite в методе CreateBoard прямо над двойными циклами for:
Эти переменные будут использоваться для хранения ссылки на соседние плитки, чтобы вы могли заменить их characters.
Посмотрите на изображение ниже:
Цикл перебирает все плитки снизу слева и поднимается по одной плитке за раз. Каждая итерация получает символ, отображаемый слева и под текущей плиткой, и удаляет его из списка новых возможных characters.
Случайный персонаж вытаскивается из этого списка и назначается как левой, так и нижней плитке.
Это гарантирует, что с самого начала уровня, на доске не будет строки из 3 одинаковых плиток.
Для этого вам нужно добавить следующие строки прямо над Sprite newSprite = characters [Random.Range (0, characters.Count)] ;
Код выберет новый спрайт из списка возможных значений и сохранит его.
Наконец, добавьте эти строки под newTile.GetComponent (). Sprite = newSprite ;:
Этот параметр установит newSprite для плитки слева и снизу от текущей для использования следующей итерации цикла.
Запустите игру и проверьте вашу новую динамическую сетку с плитками, которые не повторяются.
Меняем плитки местами
Самая важная игровая механика в играх «3 в ряд» – это выбор и замена смежных плиток, чтобы вы могли выстроиться в ряд 3 или 4 подряд. Для достижения этого вам нужно будет сделать некоторые дополнительные сценарии. Сначала выбираем плитку.
Откройте Tile.cs в редакторе исходного кода. Для удобства, этот скрипт уже был размечен с несколькими переменными и двумя методами: Select и Deselect.
Select сообщает игре, что этот фрагмент плитки выбран, меняет цвет плитки и воспроизводит звуковой эффект выбора. Отмена выбора возвращает спрайт к его первоначальному цвету и сообщает игре, что в данный момент объект не выбран.
Вам ещё не хватает способа взаимодействия игрока с плитками. Кажется, левый щелчок мыши является разумным вариантом для элементов управления.
В Unity есть встроенный метод поведения MonoBehaviour, готовый для использования: OnMouseDown.
Добавьте следующий метод в Tile.cs, прямо под методом Deselect:
Сохраняйте свой скрипт и возвращайтесь в редактор.
Теперь вы сможете выбирать и отменять выбор плиток, щелкая их левой кнопкой мыши.
Порядок? Теперь вы можете добавить механизм для свапа плиток.
Меняем расположение плиток
Начните с открытия Tile.cs и добавления следующего метода с именем SwapSpriteunderneath к методу OnMouseDown:
Этот метод поменяет местами спрайты 2 тайлов. Вот как это работает:
С реализованным методом SwapSprite, вы можете вызывать его из OnMouseDown
Добавьте эту строку прямо над previousSelected.Deselect (); в операторе else метода OnMouseDown:
Данный метод поменяет плитки местами, как только вы выбрали вторую из них.
Сохраняйте ваш прогресс и заходите обратно в редактор.
Запускайте вашу игру и попробуйте немного поиграть! Теперь вы можете выбрать две разные плитки и поменять их местами:
Находим соседние плитки
Вы наверное, заметили, что можете поменять любые две плитки на доске. Это делает игру слишком простой. Вам понадобится чекер, чтобы убедиться, что плитки можно поменять местами только с соседними.
Но как легко найти плитки рядом с данной плиткой?
Откройте Tile.cs и добавьте следующий метод под методом SwapSprite:
Этот метод получает информацию а соседней плитке, отправляя лучевую трансляцию в цель, указанную castDir. Если в этом направлении найден тайл, он вернёт GameObject.
Затем добавьте следующий метод ниже метода GetAdjacent:
Этот метод использует GetAdjacent () для генерации списка плиток, окружающих текущую плитку. Это перебирает все направления и добавляет любые соседние, найденные к соседним направлениям, которые были определены в верхней части скрипта.
С помощью новых удобных методов, которые вы только что создали, теперь вы можете принудительно менять плитку только с соседними плитками.
Замените следующий код в методе OnMouseDown:
Сохраните этот скрипт и вернитесь в редактор Unity.
Поиграйте в свою игру и проверьте, что все работает, как задумано. Теперь вы должны поменять местами только две плитки, которые находятся рядом друг с другом.
Далее вам нужно разобраться с самым важным элементом игры – комбо!
Комбинирование тайлов / плиток
Соответствие может быть разбито на несколько ключевых шагов:
Откройте файл Tile.cs и добавьте следующий метод ниже метода GetAllAdjacentTiles:
Итак, вас интересует что здесь происходит?
Сохраняйте темп и добавьте следующий логический элемент в начало файла, прямо над методом Awake:
Когда совпадение найдено, для переменной будет установлено значение true.
Теперь добавьте следующий метод под методом FindMatch:
Этот метод находит все совпадающие плитки по заданным путям, а затем очищает совпадения соответственно.
Теперь, когда вы нашли совпадение, вам нужно очистить плитки. Добавьте следующий метод ниже метода ClearMatch:
Это запустит метод домино. Он вызывает ClearMatch как для вертикального, так и для горизонтального соответствия. ClearMatch будет вызывать FindMatch для каждого направления, влево/вправо, либо вверх и вниз.
Если вы найдете совпадение по горизонтали или вертикали, тогда вы устанавливаете текущий спрайт на ноль, сбрасываете matchFound на false и воспроизводите соответствующий звуковой эффект.
Чтобы все это работало корректно, вам нужно вызывать ClearAllMatches () всякий раз, когда вы делаете свап.
В методе OnMouseDown добавьте следующую строку непосредственно перед предыдущей Selected.Deselect ();
нужный вам код:
Теперь добавьте следующий код непосредственно после previousSelected.Deselect ();
Вам нужно вызывать ClearAllMatches для предыдущего выбранного, а также для текущего тайла, потому что есть шанс, что оба могут иметь совпадение.
Сохраните этот скрипт и вернитесь в редактор. Нажмите кнопку воспроизведения и проверьте механику матча, если вы выстроите 3 плитки одного типа в ряд, они должны исчезнуть.
Чтобы заполнить пустое пространство, вам нужно сдвинуть и снова заполнить доску.
Перемещение, и автозаполнение игрового поля новыми плитками
Прежде чем вы сможете сдвинуть плитки, вам нужно найти пустые.
Откройте BoardManager.cs и добавьте следующую сопрограмму ниже метода CreateBoard:
Примечание: После добавления этой сопрограммы вы получите сообщение об отсутствии ShiftTilesDown. Вы можете спокойно игнорировать эту ошибку, так как добавите сопрограмму в следующий раз!
Эта сопрограмма будет проходить по всей доске в поисках кусочков плитки с нулевыми спрайтами. Когда он находит пустую плитку, он запускает другую сопрограмму ShiftTilesDown для обработки фактического смещения.
Добавьте следующую сопрограмму под предыдущей:
Функционал ShiftTilesDown принимает в позиции X, Y позиции и задержку между ними. X и Y используются для определения того, какие плитки поменять местами. Вам нужно, чтобы плитки перемещались вниз, поэтому значения для X останется постоянным, а Y будет изменится.
Функционал сопрограммы:
Теперь вам нужно остановиться и запустить сопрограмму FindNullTiles всякий раз, когда найдено совпадение.
Сохраните скрипт BoardManager и откройте файл Tile.cs. Добавьте следующие строки в код:
Это остановит сопрограмму FindNullTiles и снова запустит ее с самого начала..
Сохраните этот скрипт и вернитесь к редактору. Сыграйте в игру снова и сделайте выбейте несколько совпадений, если вы заметите, что на доске заканчиваются плитки, когда вы получаете матчи. Чтобы сделать нескончаемую доску, вам нужно ее заново заполнять, когда она очищается.
Открывайте BoardManager.cs, сюда вам нужно добавить новый метод под ShiftTilesDown:
Этот фрагмент создает список всех возможных значений, которыми может быть заполнен спрайт. После чего, он использует серию операторов if, чтобы убедиться, что вы не выходите за пределы. Теперь открывайте операторы if, и удаляете возможные совпадения, которые могут привести к рандомному совпадению, когда будет выбран новый спрайт. Наконец, вы возвращаете случайный спрайт из списка возможных.
В сопрограмме ShiftTilesDown замените код:
Это гарантирует, что доска будет всегда заполнена тайлами.
Когда состязание сделано и сдвинуты фигуры, есть шанс, что может быть сформировано другое совпадение. Теоретически, это может продолжаться вечно, поэтому вам нужно продолжать проверять, пока доска не найдет все возможные совпадения.
Комбо
Повторно проверив все плитки после того, как совпадение найдено, вы сможете найти любые возможные комбинации, которые могли быть созданы во время процесса сдвига.
Откройте BoardManager.cs и найдите метод FindNullTiles ().
Добавьте следующий код для в нижней части метода, под циклом for:
После всей этой тяжелой работы, пришло время убедиться, что все работает как и задумывалось.
Сохраните свою работу и запустите игру. Начните менять плитки местами и обратите внимание на то, как бесконечный запас новых плиток, будет держать игровое поле заполненным, пока вы играете.
Настроим счетчик для ведение счета
Пришло время отслеживать результаты игры, за ходами игрока и его счетом.
За это у нас будут отвечать параметры Score и MoveCounter.
Откройте GUIManager.cs, расположенный в папке Scripts \ Managers в вашем любимом редакторе кода. Этот скрипт обрабатывает аспекты пользовательского интерфейса игры, в том числе счетчик ходов и хранитель счета.
Чтобы начать, добавьте эту переменную в начало файла, под private int Score;
Теперь добавьте код в начало метода Awake (), чтобы инициализировать количество возможных ходов, которые может сделать игрок:
Теперь вам нужно инкапсулировать оба целых числа, чтобы вы могли обновлять текст интерфейса каждый раз, когда обновляете значение. Добавьте следующий код прямо над методом Awake ():
Это гарантирует, что при каждом изменении переменных значений Score и MoveCounter, текстовые компоненты, представляющие их, также будут обновляться. Вы могли бы поместить текстовое обновление в метод Update (), но сделать это таким способом намного лучше для производительности, особенно потому, что это включает обработку строк.
Время начинать добавлять очки и отслеживать ходы игрока! Каждый раз, когда игрок выбывает комбо из 3х плиток, он получает вознаграждение в виде нескольких очков
Сохраняйте этот скрипт и откройте BoardManager.cs. Пропишите следующий код в методе ShiftTilesDown, прямо над yield return new WaitForSeconds (shiftDelay);
Это событие, будет увеличивать счет каждый раз, когда будет найдена пустая плитка.
В Tile.cs добавьте следующую строку ниже SFXManager.instance.PlaySFX (Clip.Swap); в методе ClearAllMatches:
Это будет уменьшать значение MoveCounter каждый раз при замене спрайта.
Сохраните свою работу и проверьте, правильно ли работают счетчики ходов и очков. Каждый ход должен вычитать счетчик ходов, а каждое совпадение должно давать несколько очков.
Настройка экрана конца игры – Game Over
Игра должна закончиться, когда счетчик хода достигнет 0. Откройте GUIManager.cs и добавьте следующий оператор if в установщик MoveCounters, прямо под moveCounter = value ;
В общем все должно работать, если вы всё правильно настроили. Поскольку GameOver () вызывается прямо на последнем ходу, комбо не засчитываются в счет окончательного результата. За такую игру, вам максимум поставят одну звезду в отзыве!
Чтобы предотвратить это, вам нужно создать сопрограмму, которая ожидает, пока BoardManager.cs завершит все свои изменения. Затем вы можете вызвать GameOver ().
Добавьте следующую сопрограмму в GUIManager.cs под методом GameOver ()
Теперь замените следующую строку в установщике MoveCounter:
Это гарантирует, что все комбо будут подсчитаны до окончания игры.
Теперь сохраните весь ваш процесс, запускайте игру и получайте очки! :]
Что дальше?
Теперь вы знаете, как сделать базовую игру «Матч 3» с помощью Unity! Я призываю вас продолжать работать над этим учебником! Попробуйте добавить следующее самостоятельно:
Если вам понравился урок, посмотрите книгу Unity Games by Tutorials, которая обучает созданию 4 игр, скриптингу в C# и многому другому.
Дополнительные ресурсы для изучения:
Если у вас есть вопросы или замечания, пишите их в комментариях.