Разработка 2D игры на Unity (4/5) "Игровая логика"

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Привет, пикабу! По итогам вчерашнего поста на меня подписались ещё 52 человека. Спасибо вам, друзья, что проявили интерес. Буду стараться не разочаровать. Поэтому сегодня я снова не лёг спать, а сел пилить для вас очередной пост =)

Внимание! Очень-очень длиннопост!


Хронология постов:

1 - Знакомство с редактором.

2 - Подготовка сцены.

3 - Основы скриптинга в Unity.

И по вашей просьбе - ссылка на ассеты (гуглодиск). Там все исходники, кроме скриптов.


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

А начнём мы с перемещения персонажа. Для начала, давайте договоримся, что в управлении будут принимать участие четыре клавиши. Левый шифт, правый шифт, левый контрол и правый контрол. Чуть позже мы задействуем пробел, но я вам этого не говорил =)

Теперь запустим Unity и снова откроем для редактирования наш скрипт Game.

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Оставим в покое функцию Start, которую мы заполняли в прошлом посте и перейдём к функции Update. Напомню, что она вызывается каждый раз перед обновлением кадра. А это значит, что производить смену положения игрока нам нужно именно здесь.

За перехват событий ввода, в Unity, отвечает класс Input. Поэтому - пишем условие, в свойствах которого укажем, когда игрок нажимает на кнопку Left Shift, нам необходимо...


Тут сразу оговорюсь. Мы можем перехватывать аж три события ввода. Игрок нажал клавишу (GetKeyDown) - вернёт true в тот момент, когда клавиша будет нажата. Игрок отпустил клавишу (GetKeyUp) - вернёт true в тот момент, когда клавиша будет отпущена. И состояние клавиши (GetKey) - будет возвращать true, пока клавиша нажата и false, если игрок эту клавишу не трогает. В нашем случае производится однократное действие и было бы удобнее, если бы оно производилось именно по нажатию на кнопку.


Итак. Свойства условия (строка 91) мы заполнили. Давайте перейдём к его телу. Давайте рассуждать логически. Во первых нам необходимо сообщить скрипту, какое положение сейчас занимает игрок. Хорошо, присвоим переменной playerPos единицу. Далее нам необходимо включить спрайт, соответствующий данному положению. Ставим флаг активности объекта player1 в состояние true. А оставшиеся спрайты нам необходимо отключить. Вдруг, до этого мы занимали другое положение. Деактивируем объекты player2, player3 и player4.


Строки с 90 по 99 - заполнены. Все остальные положения мы меняем по тому же принципу. Не забывая менять названия клавиш и вспоминать, где какой объект расположен.


С перемещением персонажа разобрались. Пришло время научить вас плохому слову. А слово это - КОРУТИН. На хабре видел спор, что это девочка (женский род). Но я, со своим знанием английского на уровне пятого класса, слово Corutine читаю как корутин. Можете меня побить.

Так что же такое корутины? Корутинами называют сопрограммы. То есть функции, которые выполняются параллельно основному потоку и позволяют делать временные задержки, не прерываясь и не мешая выполнению функции Update. А теперь я вас окончательно запутаю и скажу, что выполняются они всё таки НЕ параллельно, но вы это можете забыть, так как пишу я это для знатоков, которые уже приготовились плеваться в комментариях. Если интересно, как работают сопрограммы - гуглите. Нас интересует только одно её свойство. Задержка.

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Итак. Суть нашей игры в том, что через какие-то промежутки времени, на сцене появляется новое яйцо. И через те же самые промежутки времени эти яйца "падают", то есть перемещаются вперёд на одну позицию. Как это организовать? Если спавнить яйца в функции апдейт, мы просто не успеем их ловить... И тут нам поможет магическая функция - корутин.


Обратите внимание, для того, чтобы корректно создать корутин, необходимо выполнить два условия: первое - функция должна начинаться с надписи IEnumerator (129 строка). Второе - функция должна возвращать yield (144 строка).


Давайте создадим корутин с названием Timer. Он, через равные промежутки времени, будет создавать на сцене новый игровой объект. Делается это функцией Instantiate. А образом и подобием ему станет объект, закреплённый за переменной zero. Дадим имя egg создаваемому объекту, чтобы было удобно с ним работать далее (131 строка).

Далее, нам необходимо повесить на него скрипт Egg, так как он будет отвечать за созданную сущность. Каждый прикреплённый к объекту скрипт называется компонентом. Поэтому создаём переменную comp и указываем, что она будет создавать компонент Egg на объекте, хранящемся в переменной egg (133 строка).

Теперь, в созданный нами компонент, необходимо передать несколько параметров. Для начала - присвоим ссылку на текущий скрипт (Game) в переменную comp.game (135 строка). Далее, нам необходимо определить, в каком месте появится яйцо. В этом нам поможет рандом. Запишем в переменную comp.spawn рандомное значение от 1 ДО 5 (137 строка). Пять не включается. Ну и, в зависимости от того, какой нам выпал спавн - записываем соответствующий массив яиц в переменную comp.egg (строки 139 - 142).


Вся логика корутина готова. Теперь нам необходимо задать паузу. Чтобы это сделать, нам необходимо вернуть yield с функцией WaitForSeconds, в свойствах которой указать время задержки. В нашем случае - это переменная time (144 строка). Как понятно из названия, эта функция ожидает, в течение указанного в свойствах времени (в секундах). После чего продолжает выполнение корутина. Но нам, после паузы, необходимо повторить все те же действия, поэтому мы просто перезапускаем корутин. Запуск корутина осуществляется функцией StartCoroutine, с указанием корутина в её свойствах (146 строка).


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

Лучший отдых - это смена вида деятельности =) Поэтому переходим в редактор Unity и импортируем загруженный пак в проект. Делается это в меню Assets -> Import Package -> Custom Package. Выглядит это вот так:

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Возможно, вам не нужны все исходники, которыми я с вами делюсь. В открывшемся окне можете просто снять галочки с тех, что вам не нужны. Далее нажимаем Import и все файлы появятся в вашем окне Project. Нас интересует папка Sounds и шрифт Electron.


Возвращаемся к редактированию скрипта Game и добавим ещё несколько переменных.

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Переменная типа TextMesh с именем counter - будет хранить счётчик пойманных яиц.

Три переменные типа GameObject с именами hp1, hp2 и hp3 - будут хранить иконки "штрафных очков", то есть индикаторы тех яиц, что игрок уронил.


Переменная типа GameObject с именем pressStart будет хранить объект надписи "нажмите такую-то кнопку, чтобы начать".


Три переменные типа AudioSource c именами soundStep, soundCrash и soundCount будут хранить звуковые файлы, которые мы будем воспроизводить каждый "шаг", при разбитии и при поимке яйца, соответственно.


Булевая переменная со странным именем isPlaying будет сообщать нам, воспроизведена ли сейчас игра. По умолчанию присвоим ей значение false.


Готово. Переменные есть, давайте вернёмся в редактор и поместим на сцену новые объекты. Создадим два пустых объекта и назовём их GUI и Sounds.

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Перетащим звуки на сцену, сделаем их дочерними объекту Sounds и перетащим звуки в соответствующие переменные скрипта Game на объекте Main Camera.

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Теперь графические элементы (GUI от "графический юзер интерфейс").

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

Теперь давайте создадим два объекта с текстом. Нажимаем правой клавишей мыши, 3D Object -> 3D Text. Один назовём Counter, а другой Press Start. После того, как объекты созданы - перетащите их в соответствующие поля скрипта Game на объекте Main Camera.

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Ну и давайте настроим наши надписи. Начнём со счётчика. Выбираем объект Counter и идём в инспектор. Изменим позицию, чтобы шрифт было чётко видно (отдалив его по оси Z) и разместим надпись в правом верхнем углу экрана. Изменим текст на "0", размер шрифта поставим 50, а сам шрифт перетащим из окна проект. Цвет выберем пипеткой. Готово. 

Разработка 2D игры на Unity (4/5) "Игровая логика" Unity, Gamedev, 2D, Игры, Урок, Длиннопост, Текст, Гифка

Прошу прощения за обрезанную гифку. Сайт просит не больше 800px.

По тому же примеру, размещаем надпись "Press Start" в центре. Только не меняя шрифт. Напишем текст "Нажмите пробел, чтобы начать". Теперь наша сцена полностью готова.


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


Спасибо, что прочитали до конца и подписывайтесь, чтобы не пропустить следующий пост ;)

1
DELETED
Автор поста оценил этот комментарий
Можно было не путать людей короутинами, а использовать InvokeRepeating().
раскрыть ветку
1
DELETED
Автор поста оценил этот комментарий
Как всегда плюс!:) Хорошая работа)
Автор поста оценил этот комментарий

Очень запутало то что скрипт Egg ещё не писали, но уже что-то присваиваем переменным внутри него

раскрыть ветку