Текст
                    С нуля
до первой игры

Практический гайд по Unity и C#
для абсолютных новичков

Nick GameDev

Оглавление Предисловие..........................................8 Почему эта книга попала вам в руки (и почему вы справитесь)........................................8 Что вы получите из этой книги...................9 Эта книга для вас, если вы.....................10 Эта книга НЕ для вас, если вы..................11 Чем эта книга отличается от других.............12 Как устроена книга.............................13 Чего в этой книге НЕ будет.....................14 И последнее перед стартом......................15 Глава 1. Подготовка (День первый)...................17 1.1. Что такое Unity и почему мы выбрали именно его. 17 Что такое Unity..............................17 Почему Unity, а не что-то другое.............18 Кто делает игры на Unity.....................20 Честно: чего Unity не умеет..................21 Что вы теперь знаете (чек-лист подглавы 1.1).22 1.2. Установка Unity Hub и Visual Studio: инструкция для тех, кто боится что-то сломать....................25 Что мы устанавливаем и зачем...............25 Важное предупреждение перед началом........26 Шаг первый. Скачиваем Unity Hub..............27 Шаг второй. Устанавливаем Unity Editor.......28 Шаг третий. Устанавливаем Visual Studio (если её нет).........................................30 Шаг четвёртый. Создаем первый проект.........32 Что делать, если что-то пошло не так.........34 Что вы теперь знаете и умеете (чек-лист подглавы 1.2) 36 1.3. Интерфейс Unity: экскурсия для тех, кто боится нажать не туда 39 Как устроен Unity Editor.....................39
Главные окна Unity.........................39 Чем отличается Сцена от Игрового вида.......41 Панель инструментов........................42 Иерархия: список всех объектов.............43 Инспектор: панель свойств..................44 Окно Проект: где живут ваши файлы..........45 Консоль: ваш друг и помощник...............46 Практическое задание: просто потыкайте кнопки ...........................................47 Что нужно запомнить из этой подглавы.......48 Задание перед следующей главой.............49 Напутствие.................................50 Что вы теперь знаете и умеете (чек-лист для всей главы 1).................................... 51 Если вы сомневаетесь.........................54 Глава 2. Создаём «Лопни шарик» (День второй)......56 2.1. Подготовка сцены и первый спрайт...........56 С чего начинается игра.....................56 Настраиваем камеру.........................57 Создаём спрайт шарика......................58 Настраиваем шарик..........................59 Добавляем фон..............................61 Проверяем результат........................63 Что вы теперь знаете и умеете (чек-лист подглавы 2.1).......................................63 От автора..................................65 2.2. Первый скрипт и реакция на клик............67 Что такое скрипт и зачем он нужен..........67 Создаём папку для скриптов.................68 Создаём первый скрипт......................69 Прикрепляем скрипт к шарику................70 Открываем скрипт для редактирования........70 Пишем первый код...........................72 Проверяем..................................74
Проблема: шарик исчезает, но это не «лопание»..75 Добавляем Collider — невидимую границу.....75 Что мы сделали и что дальше................76 Что вы теперь знаете и умеете (чек-лист подглавы 2.2).......................................77 От автора..................................79 2.3. Счет, звук и возрождение шарика............80 Что мы сделаем в этой подглаве.............80 Часть первая. Добавляем счёт...............81 Часть вторая. Пишем код для счёта..........83 Часть третья. Добавляем звук...............88 Часть четвёртая. Возрождение шарика........91 Что у нас получилось.......................95 Что вы теперь знаете и умеете (чек-лист подглавы 2.3).......................................95 От автора..................................97 Глава 3. Враги, движение и жизни (День пятый).....99 3.1. Создаём врага и учим его летать............99 Что изменится в нашей игре.................99 Создаём спрайт врага......................100 Создаём скрипт для врага..................101 Как заставить объект двигаться к другому объекту ..........................................102 Проверяем движение........................106 Проблема: враг настигает шарик и... ничего не происходит................................106 Небольшая проблема: поиск объекта по имени..107 Что вы теперь знаете и умеете (чек-лист подглавы 3.1)......................................107 От автора.................................109 3.2. Столкновения, жизни и конец игры..........110 Что мы сделаем в этой подглаве............110 Часть первая. Добавляем на шарик физическое тело......................................111
Часть вторая. Добавляем врагу коллайдер....112 Часть третья. Пишем код для столкновений...113 Часть четвёртая. Создаём текстовую надпись для жизней....................................119 Часть пятая. Настраиваем теги для врага...120 Часть шестая. Проверяем...................121 Что пока не идеально......................123 Что вы теперь знаете и умеете (чек-лист подглавы 3.2) 124 От автора.................................125 3.3. Бесконечные враги и нарастающая сложность..127 Что мы сделаем в этой подглаве............127 Часть первая. Создаём префаб врага........128 Часть вторая. Создаём менеджер спавна.....129 Часть третья. Настраиваем спавнер.........133 Часть четвёртая. Нарастающая сложность....134 Часть пятая. Настраиваем публичные переменные в Инспекторе..............................141 Часть шестая. Проверяем...................142 Что пока не идеально......................143 Что вы теперь знаете и умеете (чек-лист подглавы 3.3)......................................144 От автора.................................145 3.4. Экран Game Over, кнопка Restart и защита от спавна на игроке.....................................147 Что мы сделаем в этой подглаве............147 Часть первая. Создаём панель Game Over....148 Часть вторая. Программируем появление панели Game Over.................................151 Часть третья. Кнопка Restart..............153 Часть четвёртая. Привязываем кнопку.......156 Часть пятая. Защита от спавна на игроке...157 Часть шестая. Финальная проверка..........160
Бонус: добавляем звук потери жизни (по желанию) ...........................................161 Что у нас получилось.......................162 Что вы теперь знаете и умеете (чек-лист подглавы 3.4).......................................163 От автора..................................164 Глава 4. Публикация, полировка и что дальше (День седьмой)..........................................166 4.1. Настройка иконки и названия игры...........166 Почему это важно...........................166 Часть первая. Настройки проекта............167 Часть вторая. Название игры................168 Часть третья. Настройка разрешения экрана....170 Часть четвёртая. Иконка игры...............171 Часть пятая. Дополнительные настройки (по желанию).............................173 Что вы теперь знаете и умеете (чек-лист подглавы 4.1).......................................174 От автора..................................175 4.2. Сборка игры для Windows и WebGL............176 Что такое сборка и зачем она нужна.........176 Часть первая. Подготовка к сборке..........177 Часть вторая. Сборка для Windows...........178 Часть третья. Сборка для WebGL.............180 Часть четвёртая. Возвращаемся в редактор...182 Что вы теперь знаете и умеете (чек-лист подглавы 4.2) 183 От автора..................................184 4.3. Публикация на itch.io и финальная проверка.185 Почему именно itch.io......................185 Часть первая. Регистрация на itch.io.......186 Часть вторая. Подготовка веб-сборки к загрузке 187 Часть третья. Создание новой игры на itch.io.188 Часть четвёртая. Проверка игры.............190
Часть пятая. Публикация игры............191 Бонус: дополнительные настройки для itch.io....192 Что вы теперь знаете и умеете (чек-лист подглавы 4.3)....................................193 Что делать, если игра не работает на itch.io.194 Финальная проверка всей игры............195 От автора...............................197 Эпилог.........................................199
Предисловие Почему эта книга попала вам в руки (и почему вы справитесь) Признаюсь честно: когда я написал свою первую игру, я ненавидел программирование. Звучит странно для человека, который сейчас учит вас C# и Unity, правда? Но это чистая правда. Я думал, что код — это магия для избранных, что нужно быть математическим гением или с детства писать на ассемблере. Я открывал учебники по C# и закрывал их на второй странице, потому что там говорили про «объектно-ориентированное программирование» и «наследование классов». Слова-то какие страшные, да? Но потом я случайно наткнулся на фразу, которая всё изменила. «Программирование — это просто способ объяснить компьютеру, что ты хочешь. А игры —лучший повод этому научиться.»
Я решил попробовать ещё раз. Не читать толстые учебники, а сразу делать. Взять Unity, добавить шарик на экран и заставить его лопаться по клику мыши. И знаете что? У меня получилось. Через три часа у меня была готова примитивная, смешная, но работающая игра. Я тыкал в шарики, они лопались, счёт рос, и я чувствовал себя волшебником. С тех пор я сделал десяток маленьких игр, прошёл путь от новичка до разработчика, который кормит себя кодом. И главное, что я понял: страх — это единственное, что отделяет вас от вашей первой игры. Что вы получите из этой книги Прочитав эту книгу и выполнив все задания, вы сделаете несколько важных вещей. Вы напишете свой первый рабочий код на С#. И вы поймёте каждую строчку, а не просто скопируете её из интернета. Вы создадите полноценную игру с управлением, врагами, стрельбой и счётом. Это не «пример из учебника», а настоящая игра, в которую можно играть.
Вы узнаете, как устроен Unity — самый популярный движок для инди-разработчиков. Вы не станете экспертом за семь дней, но вы получите твёрдую основу, на которой можно строить дальше. Вы соберёте игру в исполняемый файл и сможете отправить другу со словами: «Это я сделал!» Поверьте, это чувство стоит того, чтобы потратить неделю. И самое главное — вы перестанете бояться. Вы увидите, что код — это просто инструмент, как молоток или кисть. И вы им уже умеете пользоваться. Эта книга для вас, если вы... Если вы никогда не писали код — даже слово «переменная» вызывает у вас лёгкую дрожь. Это нормально. Мы начнём с абсолютного нуля. Я не буду перескакивать через объяснения. Если вы пробовали учиться по видео на YouTube — но ролики были рваными, автор перескакивал с темы на тему, а вы так и не поняли, как собрать всё воедино. Книга устроена иначе: мы идём последовательно, от простого к сложному, и не пропускаем шагов.
Если вы хотите сделать игру «для себя» или показать друзьям — и не планируете пока становиться профессиональным разработчиком в большой студии. Эта книга даст вам ровно столько, сколько нужно для старта, и не перегрузит лишним. Если вы боитесь, что «поздно начинать» или «не хватит терпения». Спойлер: не поздно. И хватит. Я проверил это на сотнях своих учеников, и у них получилось. Получится и у вас. Эта книга НЕ для вас, если вы... Если вы уже уверенно пишете на C# и ищете продвинутые техники оптимизации — вам будет скучно. Эта книга для новичков, и я не стану прыгать выше головы. Если вам нужна теория ради теории, а не практический результат — вы тоже не найдёте здесь удовольствия. Мы здесь ради того, чтобы сделать игру, а не сдать экзамен.
Чем эта книга отличается от других Я пересмотрел десяток книг по Unity и C# на русском языке. И вот что я понял. Почти все они написаны так, будто читатель уже умеет программировать. Термины сыплются как из рога изобилия, а до первой практики нужно продираться через сотни страниц скучной теории. Эта книга сделана наоборот. В других книгах вы сначала учите сто страниц про переменные, циклы и классы — и только потом, на трёхсотой странице, доходите до первой игры. В этой книге вы пишете первый код уже на десятой странице. В других книгах примеры абстрактные — «сложите два числа», «выведите строку на экран». В этой книге каждый пример работает на вашу будущую игру. Вы сразу видите смысл того, что делаете. В других книгах итог — «теперь вы знаете основы». В этой книге итог — готовая игра, в которую можно играть, которую можно показать друзьям. В других книгах автор — профессор с кафедры, который забыл, каково это — быть новичком. Автор этой книги — человек, который сам был новичком, помнит, как это
страшно, и специально пишет так, чтобы вы ничего не боялись. Как устроена книга Я разбил материал на семь дней. Но вы можете идти в своём темпе — кто-то сделает всё за выходные, кому-то понадобится две недели. Это неважно. Важно, чтобы вы дошли до конца. В день первый вы устанавливаете Unity и создаёте первый проект. Звучит сложно, но на самом деле это просто следование инструкции — как собрать стул из IKEA. В день второй вы делаете игру «Лопни шарик» за два часа. Да, уже на второй день! Вы напишете код, добавите звук, настроите счёт — и у вас будет первая работающая игра. В дни третий и четвёртый вы изучаете язык С#. Но не в отрыве от реальности, а прямо в процессе создания игры. Вам не нужно запоминать всё — нужно просто понимать, как работают переменные, условия и циклы на примерах из вашей игры.
В дни пятый и шестой вы собираете главную игру этой книги. В ней будет управление персонажем, враги, которые движутся к вам, стрельба, очки здоровья, счёт и несколько волн. В день седьмой вы публикуете свою игру. Вы соберёте ее в исполняемый файл, выложите на йсЬ.ю и сможете отправить ссылку другу. И он сможет поиграть в браузере, даже не устанавливая Unity. В конце каждой главы есть краткий чек-лист — три-пять вопросов, которые помогут вам проверить, всё ли вы сделали правильно. Если что-то пошло не так, в приложении есть список типичных ошибок. Спойлер: в девяноста пяти процентах случаев вы просто забыли поставить точку с запятой или перепутали заглавную букву. Чего в этой книге НЕ будет Я хочу быть с вами честным, чтобы вы не разочаровались. В этой книге не будет сложной математики. Векторы, матрицы, тригонометрия — всему этому своё время, но не сейчас. Мы обойдёмся арифметикой первого класса.
В этой книге не будет трёхмерных игр. Мы делаем 2D — это проще и нагляднее для старта. Когда вы освоитесь, перейти на 3D будет несложно, потому что принципы те же. В этой книге не будет сетевых игр. Мультиплеер — это продвинутая тема для отдельной книги. В этой книге не будет создания сложных ЗВ-моделен или анимации. Для этого нужны отдельные инструменты, и это другая история. Зато здесь будет твёрдая база. После этой книги вы не станете экспертом, но вы получите уверенность в своих силах. Вы поймёте, можете ли вы вообще заниматься геймдевом — и с большой вероятностью поймёте, что да, можете. 14 у вас будет желание идти дальше. И последнее перед стартом Если вы откроете эту книгу, дойдёте до конца и сделаете свою первую игру — вы уже будете в меньшинстве. Большинство людей даже не начинают. Они боятся. Они ждут «подходящего момента». Они думают, что
недостаточно умны, что у них не те гены, не то образование, не тот возраст. Не будьте как большинство. Сделайте первый шаг прямо сейчас. Установите Unity. Напишите первую строчку кода. Увидите, как шарик лопается от вашего клика — ив этот момент всё станет понятно. Страх уйдёт, потому что страх живёт только в голове. А результат — на экране. Я буду рядом на каждой странице. Я не буду использовать слова, которых вы не понимаете. Я не буду пропускать шаги. Я буду объяснять так, как хотел бы, чтобы объясняли мне, когда я был на вашем месте. Поехали? Ваш Nick GameDev
Глава 1. Подготовка (День первый) 1.1. Что такое Unity и почему мы выбрали именно его Время чтения: около 5 минут. Цель: понять, с чем мы имеем дело, и убедиться, что выбор правильный. Что такое Unity Представьте, что вы захотели испечь торт. Можно сделать всё с нуля: вырастить пшеницу, смолоть муку, сбить масло из молока, построить печь. Это займёт годы, и вы бросите на второй день. А можно взять готовую основу, добавить начинку по вкусу, украсить — и через час торт готов. Unity — это готовая основа для игр. Тех, кто любит сложные слова, называют это «игровым движком». Простыми словами, Unity — это программа, которая берёт на себя всю самую сложную и скучную работу: рисование картинки на экране, обработку нажатий
клавиш и кликов мыши, расчёт столкновений (например, чтобы шарик отскочил от стенки), проигрывание звуков. Вам не нужно писать всё это вручную. Вы просто говорите Unity: «Вот здесь у меня будет персонаж. Вот так он будет двигаться, когда игрок нажимает стрелку вверх. А если он коснётся врага — пусть потеряет жизнь». Остальное движок делает сам. Проще некуда: Unity — это конструктор для игр. Вы берёте готовые детали — движение, физику, графику, звук — и собираете из них свою игру, дописывая только то, чего не хватает. Почему Unity, а не что-то другое На свете существует несколько популярных игровых движков, и новичок в них легко запутаться. Поэтому я сразу скажу, почему для вашей первой игры Unity подходит лучше всего. Первая причина — огромное количество уроков на русском языке. Unity существует уже больше двадцати лет. За это время миллионы людей научились на нём работать, тысячи записали курсы и гайды. На YouTube, в блогах, на профильных сайтах вы найдёте ответ на любой
вопрос. Если у вас что-то пошло не так — кто-то уже сталкивался с тем же и выложил решение. Вторая причина — язык С#. Это не какой-то экзотический язык, который нужен только в играх. На C# пишут приложения для Windows, веб-сервисы, программы для банков и страховых компаний. То есть, выучив C# ради игры, вы получите навык, который может пригодиться в самой обычной работе — если вдруг решите сменить профессию или подработать. Третья причина — Unity умеет делать и 2D, и 3D. Мы начинаем с плоской, двумерной игры, потому что это проще и нагляднее. Но когда вы освоитесь, вы можете остаться в том же движке и перейти на объёмную графику — вам не придётся учить всё заново. Четвёртая причина — это почти бесплатно. Unity можно скачать и использовать совершенно бесплатно. Платить нужно только в одном случае: если ваша игра заработала больше двухсот тысяч долларов за год. Если вы дочитали до этого места — можете не волноваться. До двухсот тысяч мы ещё доберёмся нескоро. Пятая причина, и, наверное, самая важная для новичка — результат приходит быстро. В этой книге вы напишете код и запустите первую игру уже на второй день. Не через
месяц теории, а завтра. Это невероятно важно, потому что именно быстрый результат даёт энергию двигаться дальше. Кто делает игры на Unity Многие новички думают, что Unity — это игрушка для школьников. На самом деле это серьёзный профессиональный инструмент. Вот несколько известных игр, которые сделаны на Unity. Вы в них наверняка играли или хотя бы слышали о них. Hollow Knight — красивая и сложная двухмерная игра, которую обожают миллионы игроков по всему миру. Among Us — та самая игра про предателя на космическом корабле, которая стала сенсацией в две тысячи двадцатом году. Pokemon GO — весь этот огромный мир дополненной реальности, где вы ловите покемонов на улицах, работает на Unity.
Genshin Impact — одна из самых дорогих и популярных, трёхмерных игр последних лет, с миллиардными сборами. Да, она тоже сделана на Unity. Ori and the Blind Forest — визуальный шедевр, рисованная сказка, которая выглядит как ожившая акварель. И это только верхушка айсберга. Тысячи маленьких игр от одиночек-разработчиков, которые просто хотели сделать игру для души — и вдруг проснулись знаменитыми, — тоже сделаны на Unity. Эти люди когда-то были там же, где вы сейчас. Они открывали Unity в первый раз, ничего не понимали, пугались красных ошибок в консоли. Но они сделали первый шаг. И у них получилось. У вас получится тоже. Честно: чего Unity не умеет Чтобы не было неожиданностей, я скажу прямо, где Unity бессилен. Unity не рисует за вас персонажей и фоны. Это отдельная работа. Графику нужно создавать в других программах — например, в Photoshop, в бесплатном аналоге Krita, в
специализированной программе для пиксельной графики Asesprite. Или можно брать готовые бесплатные наборы картинок из интернета. Я покажу, где их искать. Unity не пишет за вас музыку и звуки. Это тоже отдельная область — саунд-дизайн. Но звуки можно брать из бесплатных библиотек, и я тоже покажу, где. Unity не делает игру «умной» сама по себе. Он не догадается, что персонаж должен убегать от врага или что после десяти очков нужно открыть новый уровень. Это всё придётся написать вам. Но не пугайтесь: код для таких вещей короткий и понятный. При этом всё, что связано с физикой — столкновения, гравитация, прыжки, отскоки — Unity берёт на себя. Отрисовку изображений и обработку нажатий клавиш — тоже. Это примерно восемьдесят процентов всей работы, которую вам не придётся делать вручную. Что вы теперь знаете (чек-лист подглавы 1.1) Перед тем как идти дальше, давайте проверим, что вы вынесли из этого раздела.
Вы понимаете, что такое игровой движок. Это программа, которая берёт на себя сложную и скучную работу: рисует картинку, обрабатывает нажатия клавиш, считает столкновения и проигрывает звуки. Вам не нужно изобретать велосипед. Вы знаете, почему для новичка выгоднее всего начинать с Unity. Потому что на русском языке тысячи бесплатных уроков. Потому что язык C# пригодится не только в играх. Потому что Unity умеет и 2D, и 3D — можно начать с простого и не переучиваться потом. Потому что это почти бесплатно. И потому что результат вы увидите уже на второй день. Вы можете назвать несколько известных игр, сделанных на Unity. Hollow Knight, Among Us, Pokemon GO, Genshin Impact, Ori and the Blind Forest. Если кто-то спросит вас «на чём делают игры?», вы уже знаете ответ. Вы не ждёте от Unity невозможного. Вы знаете, что Unity не рисует картинки и не пишет музыку. Эти материалы нужно приносить извне — либо создавать самим, либо брать готовые из бесплатных библиотек. И вы знаете, что «умное поведение» игры (например, решение врага, куда идти) — это ваш код, а не магия движка. Вы понимаете, что ваш путь начинается ровно там же, где начинали создатели Hollow Knight и Among Us. Они
тоже ничего не понимали, боялись и ошибались. Но они не остановились. Если все эти пункты для вас — не пустой звук, значит, вы готовы двигаться дальше. Если что-то осталось непонятным — перечитайте подглаву, она короткая. Лучше потратить лишние пять минут сейчас, чем путаться потом. В следующей подглаве мы перейдём от слов к делу и установим Unity. Это просто, я проведу вас за руку.
1.2. Установка Unity Hub и Visual Studio: инструкция для тех, кто боится что-то сломать Время выполнения: 15-20 минут. Цель: установить всё необходимое и создать первый проект. Чти мы устанавливаем и зачем Прежде чем скачивать что-либо, давайте разберёмся, из каких частей состоит наше рабочее место. Их три, и каждая делает своё дело. Первое — Unity Hub. Это что-то вроде пульта управления. Через него вы будете устанавливать разные версии Unity, создавать новые проекты, открывать старые. Сам по себе Unity Hub игру не делает — это просто дверь, через которую вы входите в мир разработки. Второе — Unity Editor. Это сердце всего процесса. Именно здесь вы будете собирать сцену, расставлять объекты, настраивать физику и запускать игру. Unity Editor устанавливается через Unity Hub, и без него Hub бесполезен.
Третье — Visual Studio. Это программа для написания кода. В Unity вы делаете «внешность» игры — персонажей, уровни, кнопки. A Visual Studio нужна для того, чтобы объяснить компьютеру, как всё это должно работать: что произойдёт, когда игрок нажмёт на шарик, куда полетит пуля, сколько очков добавить за попадание. Если провести аналогию, то Unity Hub — это гараж. Unity Editor — это верстак в гараже. A Visual Studio — ящик с инструментами. Все три нужны, чтобы смастерить игру. Важное предупреждение перед началом Я хочу, чтобы вы сразу успокоились. Вы ничего не можете сломать на своём компьютере, устанавливая Unity. Даже если вы выберете «не ту» версию или поставите галочку не там — программа просто не запустится или будет работать криво. В худшем случае вы удалите её и установите заново. Никаких системных поломок не случится. Есть всего три вещи, которые стоит проверить прямо сейчас. Первое. У вас должна быть Windows 10 или новее. Или MacOS. Если у вас Windows 7 — Unity работать не будет, придётся обновлять операционную систему. Если Linux —
технически Unity работает, но новичку без опыта лучше не начинать с этого. Второе. На диске С должно быть свободно хотя бы десять гигабайт. В идеале двадцать-тридцать — особенно если вы потом захотите устанавливать дополнительные компоненты. Третье. У вас должны быть права администратора, то есть возможность устанавливать программы. Если это рабочий компьютер — попросите системного администратора помочь. Если домашний — вы, скорее всего, уже администратор. Всё проверили? Поехали. Шаг первый. Скачиваем Unity Hub Откройте браузер и перейдите на официальный сайт Unity. Адрес такой: https: //unity. com/ru/download Обратите внимание: именно на страницу c/ru/dovvnload,aHe просто на главную. На главной странице легко запутаться в кнопках и планах.
На этой странице вы увидите большую жёлтую кнопку с надписью «Скачать Unity Hub». На английском она может называться «Download Unity Hub». Нажимайте на неё. Скачается установочный файл. На Windows он будет называться UnityHubSet up . ехе, на Mac — UnityHubSet up . dmg. Запустите этот файл. Установка предельно простая. На Windows просто нажимайте «Next», потом еще раз «Next», потом «Install». На Мас перетащите иконку Unity Hub в папку «Программы». Всё. Не меняйте папку установки, оставьте как есть — это избавит вас от проблем в будущем. Шаг второй. Устанавливаем Unity Editor Теперь откройте Unity Hub. Если вы сделали всё правильно, он запустится без ошибок. Пока что внутри него пусто, потому что мы установили только «пульт», а сам движок ещё не скачали. В левом меню Unity Hub найдите вкладку «Установки» (на английском Installs). Нажмите на неё. В правой части окна появится синяя кнопка «Установить редактор» (Install Editor). Нажмите на неё.
Перед вами откроется список версий Unity. Их много, и это может напугать. Но нам нужна только одна — LTS-версия. LTS расшифровывается как Long Term Support, то есть «долгосрочная поддержка». Это самая стабильная и проверенная версия, которую используют большинство разработчиков. На момент написания книги это Unity 2022.3 LTS или 2023.3 LTS. Выбирайте самую свежую LTS на сегодняшний день. Не выбирайте версии с пометкой Beta или Alpha — это тестовые версии для смелых, в них могут быть ошибки. Нажали на нужную версию? Отлично. Теперь нажмите «Далее». Откроется окно с заголовком «Add modules» — дополнительные компоненты. Вот здесь новички часто ошибаются. Запомните: вам нужно поставить галочки ровно напротив двух пунктов. Первый обязательный пункт— поддержка вашей операционной системы. Если у вас Windows, найдите пункт «Windows Build Support». Если Mac — «Мас Build Support». Если Linux — «Linux Build Support». Это нужно, чтобы вы могли собрать игру в исполняемый файл и запустить её на своём компьютере.
Второй обязательны]! пункт — «WebGL Build Support». Это позволит собрать игру так, чтобы в неё можно было играть прямо в браузере. Вы сможете выложить игру на сайт и отправить ссылку другу — он откроет её в Chrome, и ему не придётся ничего устанавливать. Всё остальное можно пока не трогать. Android, iOS, документация — это для продвинутых или для других целей. Мы вернёмся к ним, когда захотим делать игры для телефона. Поставили галочки? Нажимайте «Установить». Процесс займёт десять-пятнадцать минут, потому что Unity весит около пяти-семи гигабайт. Скорость зависит от вашего интернета. Пока идёт установка, можете выпить чай, посмотреть короткое видео или просто порадоваться, что вы уже на полпути. Шаг третий. Устанавливаем Visual Studio (если её нет) Во время установки Unity вы могли заметить, что в списке модулей был пункт «Visual Studio». Если вы поставили там галочку — значит, Visual Studio уже установилась вместе с Unity. В этом случае вы можете пропустить этот шаг.
Как проверить? Нажмите кнопку «Пуск» на вашем компьютере и введите в поиске Visual Studio Если программа появилась — вы великолепны, переходите к следующему шагу. Если нет — ничего страшного. Установим её сейчас. Перейдите на официальный сайт Visual Studio: https : //visualstudio.microsoft. com/ru /downloads/ Вы увидите три варианта: Community, Professional и Enterprise. Нам нужен Community — он полностью бесплатный. Нажмите кнопку «Скачать бесплатно» под надписью Visual Studio Community 2022. Скачается установщик. Запустите его. Теперь самое важное. Установщик попросит вас выбрать компоненты. Вы увидите длинный список. Нам нужно минимальное, но достаточное. Поставьте галочку напротив пункта «Разработка классических приложений .NET». Это займёт примерно полтора гигабайта.
Затем найдите вкладку «Компоненты для отдельных пакетов» (она обычно справа) и найдите в ней пункт «Unity для Visual Studio». Тоже поставьте галочку. Этот пункт крайне важен. «Unity для Visual Studio» — это плагин, который связывает две программы. Без него Visual Studio не будет понимать команды Unity, и у вас не появятся автоподсказки при написании кода. А без автоподсказок новичку очень трудно. Поставили галочки? Нажимайте «Установить». Процесс займёт ещё десять-пятнадцать минут. Шаг четвёртый. Создаём первый проект Самое приятное — убедиться, что всё сработало. Откройте Unity Hub. В левом меню выберите вкладку «Проекты» (Projects). Справа будет синяя кнопка «Новый проект» (New Project). Нажмите на неё. Перед вами появится список шаблонов. Выберите «2D Core» (на русском может быть написано «20-ядро»). Не перепутайте с «3D Core» — для нашей книги нужно именно 2D.
Теперь заполните поля. Название проекта — напишите Му Firs tGame. Можно любое другое слово, но соблюдайте два правила: никаких пробелов и никаких русских букв. Пробелы и кириллица в названиях проектов могут вызвать странные ошибки. Лучше сразу привыкнуть к английским буквам. Папка — выберите место, где будут храниться все ваши проекты. Можете создать папку UnityProjects прямо на диске С или D. Главное, чтобы на этом диске было достаточно свободного места — хотя бы несколько гигабайт. Шаблон уже выбран — 2D Core, ничего менять не нужно. Всё проверили? Нажимайте «Создать» (Create). Unity Hub начнёт создавать проект. Это займёт одну-две минуты. Не закрывайте программу, просто подождите. И вот он — момент истины. Откроется Unity Editor. Вы увидите серое поле по центру (это сцена), панели по бокам и снизу, и, возможно, какие-то непонятные надписи.
Поздравляю! Вы только что установили Unity Hub, Unity Editor, Visual Studio и создали свой первый проект. Больше никогда в жизни это не будет так страшно. Первый раз — самый сложный. Что делать, если что-то пошло не так В интернете полно страшилок про установку Unity. На самом деле девяносто пять процентов проблем решаются за две минуты. Я перечислю самые частые. Если Unity Hub не запускается или не устанавливается — скорее всего, дело в правах администратора. Попробуйте запустить установщик от имени администратора: нажмите на файл правой кнопкой мыши и выберите «Запуск от имени администратора». Если вы видите ошибку «Failed to download» — проблема либо в плохом интернете, либо в антивирусе. Антивирус иногда блокирует загрузку, думая, что Unity — это что-то подозрительное. Попробуйте отключить антивирус на время установки. Если не помогает — возможно, ваш провайдер или страна блокирует серверы Unity. В таком случае поможет VPN.
Если Visual Studio не видит Unity — вы, скорее всего, забыли установить плагин «Unity для Visual Studio». Запустите установщик Visual Studio снова, нажмите «Изменить» и добавьте недостающую галочку. Это можно сделать в любой момент, не переустанавливая всю программу. Если при открытии проекта вы видите чёрный экран вместо серой сцены — возможно, проблема с видеокартой или драйверами. Попробуйте обновить драйвер видеокарты. Но для двухмерных проектов такая проблема возникает редко. Если Unity пишет «The project needs to be converted to this version» — вы установили не ту версию Unity. Проверьте, что у вас стоит LTS-версия, а не Beta или более старая. И главное правило. Если ничего не помогло — не паникуйте. Скопируйте точный текст ошибки (выделите и нажмите Ctrl+C) и вставьте в поиск Google или YouTube. С вероятностью девяносто пять процентов кто-то уже сталкивался с тем же. Что вы теперь знаете и умеете (чек-лист подглавы 1.2) Перед тем как переходить к интерфейсу Unity, давайте проверим, что вы успешно прошли техническую часть.
Вы понимаете разницу между Unity Hub, Unity Editor и Visual Studio. Unity Hub — пульт управления и установщик. Unity Editor — место, где вы собираете сцену и объекты. Visual Studio — программа для написания кода. Вы установили Unity Hub. Он открывается, не выдаёт ошибок, и вы можете зайти в него. Вы установили Unity Editor — и именно LTS-версию, а не Beta или Alpha. Вы выбрали самую стабильную версию, которую используют профессионалы. При установке вы добавили два обязательных модуля: поддержку вашей операционной системы (Windows Build Support) и WebGL Build Support (чтобы игра работала в браузере). Вы установили Visual Studio Community — бесплатную версию. И самое главное — вы не забыли про плагин «Unity для Visual Studio», который связывает редактор кода с Unity. Вы создали свой первый проект в Unify Hub. Назвали его латиницей, без пробелов, выбрали шаблон 2D Core. И вы дождались, пока откроется Unity Editor.
Вы видите перед собой интерфейс Unity — серое поле сцены, панели по бокам и снизу. Да, пока страшно и непонятно. Ь1о это нормально. Вы знаете, что делать, если что-то пошло не так. Проверить права администратора, отключить антивирус, обновить драйверы, загуглить ошибку или написать мне. Если вы отметили все пункты — вы великолепны. Поздравляю: установка — это самый технически сложный этап во всей книге. Дальше будет только интереснее. Если какой-то пункт пропущен — не переживайте. Вернитесь на несколько страниц назад, найдите то место, где возникла заминка, и пройдите его ещё раз. Лучше потратить лишние десять минут сейчас, чем полчаса гадать потом, почему что-то не работает. В следующей подглаве мы наконец начнём осваиваться в Unity. Я проведу экскурсию по самым важным окнам — только по тем, которые реально нужны для вашей первой игры. Обещаю, будет не страшно.
1.3. Интерфейс Unity: экскурсия для тех, кто боится нажать не туда Время чтения: 10 минут. Цель: понять, где что находится, и перестать бояться. Как устроен Unity Editor Представьте, что вы сели за руль автомобиля в первый раз. Вокруг куча кнопок: круиз-контроль, подогрев сидений, регулировка зеркал... Но чтобы просто поехать, вам нужны только руль, педали и рычаг коробки передач. Остальное можно изучить потом. Unity устроен так же. Сейчас я покажу вам те 10% интерфейса, которые вы будете использовать 90% времени. Всё остальное пока можно игнорировать. Главные окна Unity По центру экрана находится самое важное — окно Сцены. Это ваш игровой мир. Здесь вы расставляете объекты, двигаете их, смотрите, как они выглядят. Вы будете работать здесь постоянно.
Рядом со Сценой есть вкладка Игровой вид. Это то, что увидит игрок. Здесь вы будете тестировать игру. Главное отличие: в Игровом виде нельзя двигать объекты — это режим игрока, а не дизайнера. Слева находится Иерархия. Это простой список всех объектов, которые есть в вашей игре: персонажи, стены, враги, камера. Если вы что-то создали и не видите на сцене — проверьте, есть ли это в Иерархии. Справа расположен Инспектор. Это панель свойств. Нажмите на любой объект в Иерархии — ив Инспекторе появятся все его настройки: размер, цвет, скорость, скрипты. Здесь вы будете менять параметры. Внизу находится окно Проект. Это как Проводник Windows, но внутри Unity. Здесь лежат все файлы вашего проекта: скрипты, изображения, звуки, сцены. Организация файлов — залог спокойной разработки. Рядом с окном Проект есть вкладка Консоль. Сюда Unity пишет сообщения и ошибки. Красные строчки означают, что что-то сломалось. Не пугайтесь их — программисты видят красные ошибки каждый день. Консоль просто говорит: «Я не понял, что ты хочешь, поправь вот это». Совет: Если какое-то окно пропало (бывает), нажмите в верхнем меню Window -> General
-» и выберите нужное окно. Всё вернётся на место. Чем отличается Сцена от Игрового вида Это самый частый вопрос новичков. Представьте, что вы снимаете кино. Сцена — это ваша съёмочная площадка. Вы видите камеры, микрофоны, осветителей, режиссёра с мегафоном. Вы видите всё, даже то, что не попадёт в кадр. Здесь можно всё двигать, переставлять, менять. Игровой вид — это то, что увидит зритель в кинотеатре. Только финальная картинка. Здесь нельзя подойти к актёру и поправить ему воротник — вы только наблюдаете. Вот и в Unity: вы работаете в Сцене (двигаете объекты, настраиваете), а проверяете результат в Игровом виде. Переключаться между ними просто — кликаете на нужную вкладку в центре экрана.
Панель инструментов В самом верху Unity есть горизонтальная полоска с кнопками. Их не так много, и все они нужны. Самая важная кнопка — Play. Это большой треугольник, как на старом плеере. Нажимаете её — и ваша игра запускается. Тут же рядом кнопка Stop — квадратик, который останавливает игру. Рядом с ними — инструменты для работы с объектами. По умолчанию всегда включена стрелка (инструмент выбора). Вы просто нажимаете на любой объект в сцене, и он выделяется. Если вы хотите передвинуть объект — нажмите на иконку с перекрестьем (инструмент «Переместить»). Появятся разноцветные стрелки. Тянете за красную — объект движется вправо-влево, за зелёную — вверх-вниз. Чтобы повернуть объект — возьмите инструмент с круговой стрелкой (инструмент «Повернуть»). Появятся цветные дуги, потянув за которые, вы вращаете объект. Инструмент с квадратиком (инструмент «Масштаб») позволяет растягивать или сжимать объект. Обычно он нужен реже.
Важнейшее правило Unity, которое вы должны запомнить: Всё, что вы сделали, когда игра запущена (горит оранжевая рамка и кнопка Play подсвечена), НЕ СОХРАНЯЕТСЯ. Если вы во время игры подвинули персонажа, а потом нажали Stop — он вернётся на место. Это защита от случайных изменений. Чтобы изменить объект навсегда — делайте это только когда игра НЕ запущена. Раз и навсегда: Edit mode — сохраняется, Play mode — не сохраняется. Иерархия: список всех объектов Слева вы видите белый список. Пока там всего одна строчка — Main Camera. Это камера. Без неё игрок ничего не увидит, была бы темнота. Скоро вы сами добавите сюда персонажа, врагов, стены. Каждый объект — это отдельная строчка в Иерархии. Как добавить объект: нажмите правой кнопкой мыши в пустом месте Иерархии, выберите 2D Ob j ect, а потом Sprites -> Square. На сцене появится белый квадрат.
Чтобы переименовать объект: нажмите на него один раз, потом нажмите клавишу F2 (или кликните на названии медленно, не двойным кликом, а с паузой). Напишите новое имя, например Игрок или Стена. Чтобы удалить объект: нажмите на него и нажмите Delete. Инспектор: панель свойств Нажмите на Main Camera в Иерархии. Справа откроется Инспектор. Вы увидите несколько разделов: Transform (положение в пространстве), Camera (настройки камеры) и Другие. Сейчас для нас важнее всего раздел Transform. Там три цифры: Position (координаты X, Y, Z), Rotation (поворот) и Scale (масштаб). Попробуйте изменить X в Position на 2. Камера подвинется вправо. Не понравилось — верните обратно на 0. Чуть позже, когда у нас появятся персонажи, в Инспекторе появятся и другие важные разделы: Sprite Renderer (как выглядит картинка), Box Collider 2D (форма для столкновений), Rigidbody 2D (физика и гравитация). Совет: Если вы запутались в настройках и всё сломалось — не паникуйте. Нажмите на
значок шестерёнки в правом верхнем углу раздела и выберите Reset. Все настройки этого раздела вернутся к исходным. Окно Проект: где живут ваши файлы Внизу находится окно Project. Это как ваш компьютерный стол, на котором разложены все материалы для игры. Здесь лежат ваши скрипты, картинки, звуки, сохранённые сцены. Самая главная папка здесь — Assets. Всё, что вы кладёте в Assets, Unity видит и может использовать. Если вы положите файл в любую другую папку на диске, Unity его не увидит. Запомните это правило. Как создать папку: нажмите правой кнопкой в окне Project, выберите Create -» Folder. Назовите её, например, Scripts (для кода) или Sprites (для картинок). Организация порядка в файлах сэкономит вам часы нервов в будущем.
Консоль: ваш друг и помощник Когда вы запустите игру и что-то пойдёт не так, Unity не промолчит. Он напишет об этом в Консоли (вкладка рядом с Project). Строчки в консоли бывают разного цвета. Белые или жёлтые — просто информация, можно не обращать внимания. Зелёные — предупреждение, что-то работает неоптимально, но игра не вылетает. Красные — ошибка. Если видите красное, значит, игра не работает, и нужно что-то исправить. Не бойтесь красных ошибок. Профессиональные разработчики видят их десятки раз за день. Консоль не ругается на вас, она просто пытается помочь: «Смотри, вот тут я ожидал переменную, а ты мне дал текст. Поправь, пожалуйста». Как очистить консоль: нажмите на иконку с тремя полосками и крестиком в левом верхнем углу окна Console. Иногда там накапливается много старых сообщений, мешая видеть новые.
Практическое задание: просто потыкайте кнопки Теперь, когда мы знаем, где что лежит, давайте просто поиграем с интерфейсом. Ничего не бойтесь, вы ничего не сломаете. Задание первое: научитесь летать по сцене. Зажмите правую кнопку мыши и двигайте мышью. Видите, как камера вращается вокруг сцены? Это полезно, чтобы осмотреть объект со всех сторон. Теперь зажмите колёсико мыши (не крутите, а именно зажмите) и двигайте мышью. Камера перемещается влево- вправо, вверх-вниз — как в Google Maps. Покрутите колесико вперёд-назад. Камера приближается и отдаляется. Задание второе: создайте первый объект. Нажмите правой кнопкой в пустом месте Иерархии (левая панель). Выберите 2D Object -> Sprites - Square. На сцене появится белый квадрат. Нажмите на него в Иерархии. Посмотрите в Инспектор (справа). Найдите раздел Transform и измените Position X на 2. Квадрат подвинулся вправо. Теперь нажмите ► Play вверху. Посмотрите на вкладку Game. Квадрат там? Виден? Отлично. Нажмите Stop. Квадрат вернулся на место. Помните правило Edit mode vs Play mode? Вот оно в действии.
Задание третье: не пугайтесь первой ошибки. Нажмите Play. Посмотрите в Консоль внизу. Скорее всего, там появится жёлтая или красная строчка: There is no audio listener. . . Это Unity напоминает, что в сцене нет микрофона, чтобы слушать звуки. Для нашего квадрата это неважно. Нажмите Stop. Мы разберёмся со звуком, когда будем делать «Лопни шарик». Что нужно запомнить из этой подглавы У вас в голове не должно быть каши. Запомните всего пять вещей. Первое. Сцена (Scene) — ваша кухня, вы всё видите и можете двигать. Игровой вид (Сате) — то, что видит игрок, там двигать нельзя. Второе. Иерархия (Hierarchy) — список всех объектов в игре. Инспектор (Inspector) — свойства выбранного объекта. Третье. Окно Проект (Project) — ваши файлы. Консоль (Console) — помощник, который пишет об ошибках.
Четвёртое. Режим Play (игра запущена) — изменения НЕ сохраняются. Режим Edit (игра остановлена) — изменения СОХРАНЯЮТСЯ. Это железное правило. Пятое. Если что-то сломалось или пропало — не паникуйте. Закройте Unity, откройте заново. Или загуглите ошибку. Задание перед следующей главой В следующей главе (Глава 2) мы перестанем играться с интерфейсом и начнём делать настоящую игру. «Лопни шарик» — с кликами, звуками и счётом. А пока сделайте одну простую вещь. Сохраните вашу текущую сцену под новым именем. Сейчас она называется SampleScene. Найдите её в окне Project (в папке Assets Scenes), кликните один раз, нажмите F2 и переименуйте в MainScene. Привыкайте часто нажимать Ctrl + S (или Cmd + S на Мас). Сохранять игру нужно постоянно, как воздух. Потерять час работы из-за вылета компьютера — самый глупый способ расстроиться.
Напутствие Unity — сложная программа. Но не сложнее, чем первый раз сесть за компьютер или открыть Excel. Вы не обязаны знать все кнопки с первого дня. Даже профессиональные разработчики с десятилетним стажем не знают всего интерфейса. Они знают 20% возможностей, которые используют 80% времени. Вы сейчас знаете достаточно, чтобы сделать свою первую игру. Л это главное. День первый завершён. Завтра (или просто на следующей странице, а может даже на этой) мы начнём Главу 2 — и сразу, без долгих предисловий, напишем первую работающую игру Поехали! Хотя нет: сначала — чек-лист.
Что вы теперь знаете и умеете (чек-лист для всей главы 1) Перед тем как переходить к Главе 2 и созданию первой настоящей игры, давайте убедимся, что вы освоились в интерфейсе Unity. Вы не обязаны знать все наизусть, но вы должны чувствовать себя уверенно в самых главных окнах. Вы знаете, где находится Сцена. Это центральное окно, где вы видите ваш игровой мир. Здесь вы двигаете объекты, расставляете их, меняете их положение. Вы не путаете Сцену с Игровым видом. Вы знаете, где находится Игровой вид. Это соседняя вкладка рядом со Сценой. Здесь вы видите игру глазами игрока. И вы твёрдо усвоили: в Игровом виде нельзя двигать объекты, можно только смотреть. Вы знаете, где находится Иерархия. Это левая панель со списком всех объектов в игре — камера, персонажи, враги, стены. Если объект не виден на Сцене, вы знаете, что первым делом нужно проверить, есть ли он в Иерархии. Вы знаете, где находится Инспектор. Это правая панель. Когда вы нажимаете на любой объект в Иерархии или на Сцене, в Инспекторе появляются его свойства — размер,
цвет, скорость, скрипты. Вы уже меняли там цифру Position X и видели, как объект двигается. Вы знаете, где находится окно Проект. Это нижняя панель. Здесь лежат все файлы вашего проекта — сцены, скрипты, картинки, звуки. Вы знаете, что всё, что не лежит в папке Assets, Unity не видит. Вы знаете, где находится Консоль. Это вкладка рядом с окном Проект. Сюда Unity пишет сообщения и ошибки. Вы знаете, что красные строчки — это не конец света, а просто подсказки, которые помогают найти проблему. Вы умеете навигироваться в Сцене. Вы знаете, что зажатая правая кнопка мыши вращает камеру, зажатое колёсико перемещает её, а простое кручение колёсика приближает и отдаляет. Вы попробовали все эти движения и не боитесь «летать» по сцене. Вы знаете, зачем нужны кнопки Play и Stop. Play запускает игру, Stop останавливает. Вы уже нажимали на них и видели, как игра (пустая, с одним квадратом) запускается и останавливается. И самое главное — вы запомнили железное правило Unity. Всё, что вы делаете, когда игра запущена и горит оранжевая рамка, НЕ сохраняется. Если вы подвинули
объект во время игры, а потом нажали Stop — он вернётся на место. Чтобы изменить объект навсегда, нужно делать это при остановленной игре. Это правило спасает новичков от тысяч часов потерянной работы. Вы умеете создавать простой объект. Нажать правой кнопкой в Иерархии, выбрать 2D Object, потом Sprites, потом Square. На Сцене появляется белый квадрат. Вы пробовали это сделать и видели результат. Вы умеете переименовывать объект. Нажать на объект в Иерархии, нажать клавишу F2 (или кликнуть медленно, с паузой), написать новое имя. Вы переименовали Square во что-то своё, например, «Тестовый квадрат». Вы умеете менять положение объекта. Выбрать объект на Сцене или в Иерархии, найти в Инспекторе раздел Transform, изменить цифру X или Y. Квадрат двигается. Вы пробовали и убедились, что это работает. Вы сохранили свою сцену. Вы нажали Ctrl+S (или Cmd+S на Мас) и убедились, что изменения записались. Вы переименовали сцену из Samp]eScene во что-то осмысленное, например, MainScene. Вы не боитесь запустить и остановить игру с каким-то объектом. Вы пробовали создать квадрат, запустить Play,
посмотреть на него в Игровом виде, йогом остановить. Вы видели, что он остался на месте (потому что вы его не двигали в режиме Play). Вы видели свою первую ошибку в Консоли. Скорее всего, это было «There is no audio listener». Вы не испугались, поняли, что это просто напоминание про звук, и двинулись дальше. Вы чувствуете, что перестали бояться интерфейса Unity. Да, там много кнопок, но вы знаете главные. Вы знаете, куда смотреть, чтобы найти объект, изменить его свойство или посмотреть ошибку. Вам не всё понятно, но вам уже не страшно. Если вы сомневаетесь Если на какие-то пункты вы мысленно ответили «нет» или «не уверен» — ничего страшного. Вот что можно сделать. Если вы не уверены, где находится какое-то окно — просто вернитесь к тексту подглавы 1.3. Там все описано коротко и ясно. Перечитайте раздел «Главные окна Unity» — это буквально две минуты.
Если вы не пробовали создавать объект или двигать его — сделайте это прямо сейчас. Откройте Unity (ваш проект, который вы создали в подглаве 1.2) и просто поиграйтесь. Создайте три квадрата разного цвета (чтобы поменять цвет, найдите в Инспекторе раздел Sprite Renderer, а в нём — строчку Color). Покрутите их. Нажмите Play. Посмотрите. Нажмите Stop. Ничего не бойтесь. Если вы забыли, как сохранить сцену — просто нажмите Ctrl+S. Сделайте это привычкой. Каждый раз, когда вы сделали что-то, что не хотите потерять, — сохраняйте. Если вы всё ещё боитесь интерфейса — это нормально. Страх уходит только с практикой. Вы не избавитесь от него, читая книгу. Вы избавитесь от него, когда проведёте в Unity полчаса, создавая и удаляя квадраты. Просто откройте программу и тыкайте кнопки. Вы ничего не сломаете. Вот теперь поехали!
Глава 2. Создаём «Лопни шарик» (День второй) 2.1. Подготовка сцены и первый спрайт Время выполнения: 15-20 минут. Цель: создать фон, добавить шарик и настроить камеру. С чего начинается игра Любая игра начинается с пустого листа. У вас сейчас открыт Unity Editor с новым проектом. Вы видите серую сцену, в Иерархии одинокую камеру, а больше — ничего. Это нормально. Сейчас мы это исправим. Прежде чем добавлять шарик и писать код, нужно подготовить место для игры. Как художник сначала грунтует холст, а потом начинает рисовать. Мы поступим так же. В этой подглаве мы сделаем три простые вещи. Во-первых, настроим камеру — чтобы наша игра выглядела аккуратно и не было чёрных полей по краям. Во-вторых, создадим
спрайт шарика — ту самую картинку, по которой игрок будет кликать. В-третьих, добавим фон — чтобы игра выглядела не как белый квадрат на сером поле, а как настоящая игра. Звучит просто. Так оно и есть. Поехали. Настраиваем камеру Камера в Unity — это глаза игрока. Если камера стоит криво или смотрит не туда, игрок либо ничего не увидит, либо увидит не то. Поэтому начнём с неё. Найдите в Иерархии объект с названием Main Camera. Нажмите на него один раз левой кнопкой мыши. Он выделится синим. Теперь посмотрите в правую панель — Инспектор. Там появились настройки камеры. Нас сейчас интересует раздел Transform — положение камеры в пространстве. Вы видите три цифры: Position X, Position Y, Position Z. По умолчанию там стоят нули, а по Z — минус десять. Это правильно, ничего менять не нужно. Камера стоит ровно по центру и смотрит прямо на сцену. Теперь найдите в Инспекторе раздел Camera. Это настройки того, как камера видит мир. Нам нужно
изменить всего один параметр — Size (на русском может быть написано «Размер»), Это размер камеры по вертикали. Чем больше цифра, тем больше пространства видит игрок. Чем меньше — тем крупнее объекты. По умолчанию там стоит пять. Давайте поставим три. Просто щёлкните по цифре пять, сотрите её и напишите три. Нажмите Enter. Посмотрите на Сцену. Она как будто приблизилась. Это нормально. Для нашей игры с шариками размер три подходит идеально — игрок будет видеть достаточно пространства, но шарик не будет слишком мелким. Вот и всё с камерой. Пока ничего сложного. Создаём спрайт шарика Спрайт — это просто картинка. В двухмерных играх все персонажи, враги, предметы и пули — это спрайты. Наш шарик — тоже спрайт. В Unity есть встроенные простые спрайты на случай, когда у вас под рукой нет своих картинок. Мы воспользуемся одним из них — кругом.
Посмотрите в левую верхнюю часть Иерархии. Нажмите правой кнопкой мыши на пустом месте внутри Иерархии (не на камере, а чуть ниже). Появится меню. В этом меню выберите 2D Object, потом Sprites, потом Circle. Да, не Square, a Circle. Square — это квадрат, a Circle — круг. Нам нужен круг, потому что мы делаем шарик. После этого в Иерархии появится новый объект — он будет называться «New Sprite» или просто «Circle». А на Сцене вы увидите белый круг. Поздравляю! Вы только что создали первый игровой объект. Это и есть наш шарик. Настраиваем шарик Сейчас шарик — просто белое пятно. Давайте сделаем его похожим на настоящий шарик. Добавим цвет и немного увеличим. Нажмите на ваш новый шарик в Иерархии. В Инспекторе появится куча настроек. Найдите раздел Sprite Renderer — он отвечает за то, как выглядит спрайт.
Внутри Sprite Renderer найдите строчку Color (цвет). Это белый прямоугольник. Нажмите на него. Откроется палитра цветов. Выберите любой яркий цвет — красный, синий, зелёный, жёлтый. Шарик должен быть заметным. Я выберу красный. Закройте палитру. Шарик на сцене поменял цвет. Отлично. Теперь давайте увеличим шарик. Найдите в Инспекторе раздел Transform (он самый первый). Внутри Transform есть строчка Scale — масштаб. Там три цифры: X, Y, Z. По умолчанию стоят единицы. Измените X на два. Просто сотрите единицу и напишите два. Сделайте то же самое с Y — тоже напишите два. Z оставьте как есть, он нам не нужен. Шарик стал крупнее. Теперь его хорошо видно. Мы почти закончили. Осталось переименовать шарик, чтобы в Иерархии было понятно, что есть что. Сейчас он называется Circle или New Sprite. Нажмите на этот объект в Иерархии один раз, потом нажмите клавишу F2 (или кликните медленно, с паузой) и напишите Ball. Нажмите Enter.
В Иерархии появилась строчка Ball. Теперь у нас есть камера и шарик. Уже похоже на игру, правда? Добавляем фон Игра с шариком на сером фоне выглядит уныло. Давайте добавим красивый фон — хотя бы просто цветной прямоугольник на заднем плане. Создадим фон. Нажмите правой кнопкой в Иерархии — как в прошлый раз. Выберите 2D Object — Sprites — Square. Появится квадрат. Он перекроет шарик, потому что создался поверх. Это не страшно — мы сейчас переместим его назад. В Иерархии появился новый объект — назовём его Background. Нажмите на него, нажмите F2 и переименуйте. Теперь нужно, чтобы этот квадрат был не белым, а, например, светло-голубым или тёмно-синим. Нажмите на Background, найдите в Инспекторе Sprite Renderer, нажмите на прямоугольник Color и выберите приятный цвет фона. Я выберу тёмно-синий, почти ночной.
Теперь квадрат фона перекрывает шарик, потому что он находится «перед» ним. В двухмерных играх порядок объектов зависит от их положения по оси Z (глубина). Чем меньше число, тем объект ближе к камере. Мы сделаем так, чтобы фон был далеко, а шарик — близко. В Иерархии нажмите на Background. В Инспекторе найдите Transform и строку Position Z. Там сейчас стоит ноль. Напишите десять (10). Теперь нажмите на Ball. В его Transform найдите Position Z и напишите ноль (0). Фон ушёл назад, шарик остался на месте. Теперь шарик виден поверх фона. Именно так и должно быть. Осталось растянуть фон на весь экран, чтобы не было видно серых краёв. Нажмите на Background. В Transform найдите Scale. По умолчанию там X = 1, Y = 1. Измените X на десять (10), a Y на десять (10). Квадрат фона стал огромным и покрыл всё поле. Проверьте: нажмите на вкладку Game (рядом со Scene). Вы видите яркий шарик на цветном фоне? Никаких серых полей по краям? Отлично.
Проверяем результат Нажмите на кнопку Play в верхней панели Unity. Вы увидите, как шарик и фон ожили. Игра запустилась. Но пока ничего не происходит. Шарик висит в воздухе, не двигается, не лопается. Это нормально — код мы напишем в следующей подглаве. Пока просто посмотрите, как выглядит ваша игра. Шарик на фоне. Никаких ошибок в Консоли (ну, кроме той шутки про звук — её игнорируйте). Нажмите Stop, чтобы выйти из режима игры. Всё работает. Вы только что подготовили сцену для вашей первой игры. Что вы теперь знаете и умеете (чек-лист подглавы 2.1) Перед тем как переходить к написанию кода, дава] 1те проверим, что вы успели сделать. Вы настроили камеру. Вы нашли Main Camera в Иерархии, перешли в Инспектор и изменили параметр Size
с пяти на три. Теперь игрок видит ровно с только пространства, сколько нужно. Вы создали спрайт шарика. Вы нажали правой кнопкой в Иерархии, выбрали 2D Object -> Sprites — Circle. На сцене появился белый круг. Вы изменили цвет шарика. Вы выбрали шарик, нашли в Инспекторе Sprite Renderer, нажали на прямоугольник Color и выбрали яркий цвет — красный, синий, зелёный или любой другой. Вы увеличили шарик. В разделе Transform у шарика вы изменили Scale X и Scale Y с единицы на двойку. Шарик стал крупнее и заметнее. Вы переименовали шарик. Вы нажали на объект в Иерархии, нажали F2 (или кликнули медленно) и назвали его Ball. Теперь в Иерархии порядок. Вы создали фон. Вы добавили ещё один спрайт — на этот раз Square — и назвали его Background. Вы покрасили фон. В Sprite Renderer у фона вы выбрали цвет, который вам нравится — голубой, синий, зелёный или даже чёрный.
Вы правильно расположили фон и шарик но глубине. Вы отодвинули фон назад, изменив его Position Z на десять, a Position Z шарика оставили на нуле. Шарик теперь виден поверх фона. Вы растянули фон на весь экран. Вы изменили Scale X и Scale Y у фона на десять. Фон теперь не оставляет серых краёв. Вы запустили игру кнопкой Play и увидели шарик на цветном фоне. Да, пока он не двигается и не лопается. Но это уже игра. Она работает. Вы не боитесь кнопки Play. Вы знаете, что она запускает игру, а кнопка Stop — останавливает. Вы помните, что в режиме Play ничего нельзя менять навсегда. От автора Посмотрите, как далеко вы продвинулись. В начале книги вы боялись даже слова «Unity». Потом вы установили программу, создали проект, освоились в интерфейсе. А теперь у вас на экране — цветной фон и яркий шарик. Это уже похоже на игру.
И это только начало. В следующей подглаве (2.2) мы напишем первый код на С#. Мы сделаем так, чтобы шарик реагировал на клики мыши. Вы увидите, как просто объяснить компьютеру: «Если игрок нажал на шарик — сделай так, чтобы он исчез, добавь очко и проиграй звук». Это не сложно. Это даже весело. Особенно в тот момент, когда код в первый раз работает. Отдохните минуту. Выпейте воды. И переходите к следующей подглаве.
2.2. Первый скрипт и реакция на клик Время выполнения: 20-25 минут. Цель: написать первый код на С#, который заставит шарик реагировать на нажатие мыши. Что такое скрипт и зачем он нужен До этого момента мы только расставляли объекты вручную — как конструктор «Лего». Но игра становится игрой только тогда, когда объекты начинают что-то делать. Шарик должен лопаться от клика. Счёт должен расти. Звук должен играть. Всё это — поведение. А поведением в Unity управляют скрипты. Скрипт — это просто текстовый файл с инструкциями на языке С#. Вы пишете: «когда игрок нажал на шарик — сделай то-то». Компьютер читает эти инструкции и выполняет их. Всё. Страшного ничего нет. Вы не станете программистом после этой подглавы, но вы напишете свой первый рабочий
код. И он будет делать именно то, ч то вы от него хотиге. Это очень приятное чувство. Создаём папку для скриптов Прежде чем писать код, давайте наведём порядок. В окне Project (внизу) у вас сейчас, скорее всего, одна папка — Assets. Внутри неё — несколько служебных папок, которые Unity создал сам. Мы добавим свою. В окне Project найдите пустое место и нажмите правой кнопкой мыши. В появившемся меню выберите Create, потом Folder. Появится новая папка с подсвеченным названием. Назовите её Scripts. Нажмите Enter. Теперь у вас есть папка для всех скриптов. Порядок в файлах — это не занудство, а способ не сойти с ума, когда проектов станет много. Привыкайте сразу.
Создаём первый скрипт Нажмите правой кнопкой на только что созданную папку Scripts. Выберите Create, потом C# Script. Можно просто нажать по папке правой кнопкой и в выпадающем меню найти этот пункт. Появится новый файл. Unity автоматически назовёт его «NexvBehaviourScript». Это некрасиво и непонятно. Поэтому сразу переименуйте. Нажмите на этот файл один раз, потом нажмите F2 (или кликните медленно, с паузой). Напишите Ball. Нажмите Enter. Название должно быть без пробелов, с большой буквы, на английском. Ball — идеально. Поздравляю. Вы только что создали свой первый скрипт. Пока он пустой, но сейчас мы его наполним.
Прикрепляем скрипт к шарику Скрипт сам по себе ничего не делает. Его нужно прикрепить к объекту, которым он должен управлять. Наш объект — шарик с именем Ball. В окне Project найдите панку Scripts, а в ней — файл Ball. Нажмите на него левой кнопкой мыши и, не отпуская, перетащите в Иерархию — прямо на объект Ball. Или на сам шарик в Сцене. И то и то работает. Когда вы отпустите кнопку мыши, ничего визуально не изменится. Но если вы нажмёте на шарик в Иерархии и посмотрите в Инспектор, вы увидите внизу новый раздел — Ball (Script). Скрипт прикрепился. Теперь шарик знает, что его поведение описывается вот этим файлом. Открываем скрипт для редактирования Сейчас нам нужно открыть скрипт и написать внутри него код. Самый простой способ — дважды кликнуть на файле Ball в окне Project (в папке Scripts). Откроется Visual Studio — та самая программа для написания кода, которую мы установили в Главе 1.
Вы увидите окно, где уже есть какой-то текст. Не пугайтесь. Unity создала шаблон скрипта автоматически. Выглядит он страшновато, но на самом деле там всего четыре важные части, а остальное можно пока игнорировать. Я объясню максимально просто. В самом верху есть строчки, начинающиеся с using — это подключения разных полезных инструментов. Их трогать не нужно. Дальше идёт строчка public class Ball : MonoBehaviour — здесь говорится, что наш скрипт называется Ball и он может взаимодействовать с Unity. Всё правильно. А потом идут два блока — void Start ( ) и void Update( ). Это два метода, два «режима работы». Start выполняется один раз в самом начале игры — при запуске или когда объект появляется на сцене. Update выполняется каждый кадр — примерно шестьдесят раз в секунду. Здесь обычно пишут то, что должно происходить постоянно: движение, проверки, реакции.
Нам сейчас не нужен ни Start, ни Update. Нам нужно кое- что другое. Пишем первый код Нам нужно, чтобы шарик реагировал на клик мыши. В Unity для этого есть специальная встроенная штука. Она называется OnMouseDown. Это метод, который Unity запускает автоматически, когда игрок нажимает на объект мышкой. Нам нужно внутри этого метода написать: что именно произойдёт при клике. Давайте сначала сделаем простейшую вещь — при клике шарик будет исчезать. Сотрите всё, что внутри скрипта, но оставьте первые две строчки с using и строчку public class Ball : MonoBehaviour. Я сейчас покажу, как должен выглядеть минимальный работающий скрипт. Вот весь код. text using System.Collections; using System.Collections.Generic;
using UnityEngine; public class Ball : MonoBehaviour { void OnMouseDown() { Destroy(gameObject); } } Разберём каждую строчку. Строчка void OnMouseDown() —это объявление метода. «Void» означает, что он ничего не возвращает (не волнуйтесь, это техническая деталь). «OnMouseDown» — это название, которое Unity узнаёт и понимает. Фигурные скобки { и } — это границы метода. Всё, что внутри, будет выполнено при клике. Строчка Destroy(gameObject); — самая важная. «Destroy» означает «уничтожить». «GameObject» — это тот объект, к которому прикреплён скрипт, то есть шарик. Точка с запятой в конце — это как точка в предложении. Код без точки с запятой не работает. Всё. Это полный рабочий скрипт.
Теперь сохраните его. Нажмите Ctrl + S (или Cmd + S на Мас). Или нажмите на иконку дискеты в Visual Studio. Вернитесь в Unity. Проверяем Unity должна заметить, что скрипт изменился. Обычно это происходит автоматически, но на всякий случай кликните на окне Unity один раз. Нажмите кнопку Play. Вы увидите шарик на фоне. Теперь нажмите на шарик мышкой. Он исчез. Поздравляю. Вы только что написали код, который работает. Ваша первая программа на С#. Она делает ровно то, что вы сказали: при клике уничтожить объект. Нажмите Stop. Шарик вернулся. Помните правило — в режиме Play изменения не сохраняются.
Проблема: шарик исчезает, но это не «лопание» Шарик исчезает, но это выглядит не как лопанье, а как магия — раз, и нет. Плюс, когда шарик уничтожен, в него больше нельзя попасть. А игра должна продолжаться. Нужен новый шарик. Но пока не будем усложнять. Сначала научимся делать так, чтобы клик не проходил сквозь другие объекты. Вы, возможно, заметили, что если нажать не прямо на шарик, а на фон — ничего не происходит. Это правильно. А если нажать на шарик — он исчезает. Всё работает. Но есть одна тонкость. Добавляем Collider— невидимую границу Чтобы Unity понимала, что в шарик можно кликнуть, у объекта должна быть специальная невидимая оболочка — коллайдер (от английского collide — сталкиваться).
У нашего шарика, который мы создали через 2D Object -» Sprite — Circle, коллайдер уже есть. Это Circle Collider 2D. Можете проверить: нажмите на шарик в Иерархии, посмотрите в Инспектор. Там есть раздел Circle Collider 2D. Если бы мы создавали объект по-другому, коллайдера бы не было, и клики не работали бы. Но нам повезло — Unity позаботилась о нас. Если вдруг по какой-то причине у вашего шарика нет коллайдера, вы можете добавить его вручную. Нажмите на шарик, в Инспекторе нажмите Add Component, в поиске напишите Circle Collider 2D и выберите его. Но скорее всего, он уже есть. Что мы сделали и что дальше Сейчас наша игра делает следующее: игрок нажимает на шарик — шарик исчезает. Дальше ничего не происходит. Нет счёта, нет звука, нет нового шарика. Это не игра, а игрушка. Но это уже работающий прототип. А от прототипа до игры — один шаг. В следующей подглаве мы добавим счёт, звук и сделаем так, чтобы после уничтожения шарика появлялся новый.
Но сначала — закрепим то, что сделали. Что вы теперь знаете и умеете (чек-лист подглавы 2.2) Вы знаете, что такое скрипт. Это текстовый файл с инструкциями на языке С#. Он управляет поведением объектов — говорит им, что делать. Вы создали папку Scripts в окне Project. Теперь все ваши скрипты будут лежать в одном месте, и вы не потеряете их. Вы создали свой первый скрипт и назвали его Ball. Вы знаете, что название должно быть без пробелов, с большой буквы, на английском. Вы прикрепили скрипт к шарику. Вы перетащили файл Ball из папки Scripts на объект Ball в Иерархии или на Сцене. Теперь в Инспекторе у шарика появился раздел Ball (Script). Вы открыли скрипт в Visual Studio — дважды кликнули на нём в окне Project. Вы написали свой первый код на С#. Вы не скопировали его из интернета, а написали (или хотя бы вбили)
строчку Destroy(gameObject); внутри метода OnMouseDown (). Вы понимаете, что делает каждая строчка кода. OnMouseDown — метод, который Unity вызывает при клике. Destroy — команда уничтожить. gameObject — сам объект, к которому прикреплён скрипт. Точка с запятой — конец команды. Вы сохранили скрипт в Visual Studio (Ctrl+S) и вернулись в Unity. Вы запустили игру кнопкой Play и кликнули по шарику. Шарик исчез. Вы увидели результат своей работы. Вы знаете, что для кликов нужен коллайдер. Вы проверили, что у шарика есть Circle Collider 2D, и понимаете, зачем он нужен — чтобы Unity понимала, куда именно нажал игрок. Вы не боитесь слова «код». Вы написали его, и он работает. Теперь вы знаете, что это просто набор понятных инструкций, а не магия.
От автора Стоп. Сделайте паузу. Вы только что сделали то, что останавливает большинство новичков. Вы написали код, который работает. С первого раза (ну, возможно, со второго — если забыли точку с запятой или закрывающую скобку). Помните это чувство — когда вы кликнули на шарик, и он исчез. Это маленькое чудо. Оно никогда не надоедает. В следующей подглаве (2.3) мы превратим это в настоящую игру. Добавим счёт, который растёт с каждым лопнутым шариком. Добавим звук «пуф». И сделаем так, чтобы вместо одного шарика появлялись новые — бесконечно. Отдохните минуту. Улыбнитесь. Вы — человек, который написал свой первый игровой код. Это серьёзное достижение. Переходите к 2.3.
2.3. Счёт, звук и возрождение шарика Время выполнения: 25-30 минут. Цель: добавить систему очков, звук лопанья и бесконечное появление новых шариков. Чти мы сделаем в этой подглаве Сейчас наша игра делает три вещи: игрок кликает по шарику, шарик исчезает, и всё. Ничего не запоминается, ничего не звучит, новых шариков нет. В этой подглаве мы добавим три важные штуки. Первое — счёт. Каждый раз, когда игрок лопает шарик, количество очков увеличивается на единицу. Эти очки будут отображаться на экране, чтобы игрок видел свой прогресс. Второе — звук. Когда шарик лопается, должен проигрываться короткий звук — «пуф» или «хлоп». Это сделает игру живой и приятной. Третье — возрождение. Вместо того чтобы исчезать навсегда, шарик будет появляться в новом случайном
месте. Игрок может лопать их бесконечно, а счёт будет расти и расти. Звучит сложно, но на самом деле каждая из этих задач решается тремя-четырьмя строчками кода. Вы уже написали свой первый скрипт в прошлый раз — теперь просто его расширим. Часть первая. Добавляем счет Для счёта нам понадобится специальный текстовый элемент на экране. В Unity для этого есть объект TextMeshPro — удобная система для отображения текста. Создадим его. Посмотрите в Иерархию. Нажмите правой кнопкой мыши на пустом месте. В появившемся меню выберите UI, потом Text — TextMeshPro. Если вы видите окошко с предложением импортировать дополнительные пакеты — соглашайтесь. Это стандартные шрифты для TextMeshPro, они нужны для работы. Нажмите «Import ТМР Essentials». Это займёт несколько секунд.
После этого в Иерархии появится новый объект — Text (ТМР). А на сцене вы увидите белую надпись «New Text». Это и есть наш будущий счёт. Давайте настроим этот текст. Нажмите на Text в Иерархии. В Инспекторе вы увидите кучу настроек. Нас интересуют несколько. Сначала переименуйте объект. Нажмите F2 и назовите его ScoreText. Так понятнее. Теперь найдите раздел TextMeshPro —Text (Script). Там есть поле Text. Сейчас там написано «New Text». Сотрите это и напишите Score: 0 (именно так, с большой буквы S, двоеточием и пробелом). Это то, что игрок увидит в начале игры. Теперь изменим размер шрифта. Чуть ниже найдите параметр Font Size. По умолчанию там стоит 36. Для нашей игры многовато — текст будет огромным. Поставьте 24. Теперь расположим текст в левом верхнем углу. Найдите в Инспекторе раздел Rect Transform — это настройки положения для элементов интерфейса. Там есть параметры Pos X и Pos Y. Поставьте Pos X на 100, Pos Y
на -50. Текст сместится в левый верхний угол. (Минус перед Y означает, что текст сдвигается вниз от верхнего края.) Теперь изменим цвет текста, чтобы он был заметнее. В разделе TextMeshPro найдите строчку Color (прямоугольник с цветом). Нажмите на него и выберите ярко-жёлтый или белый. Оставлю белый, но вы можете выбрать любой. Всё. Текст для счёта готов. Если нажать Play, вы увидите надпись «Score: 0» в левом верхнем углу. Пока ноль, потому что мы ещё не написали код, который увеличивает счёт. Часть вторая. Пишем код для счета Теперь откроем наш скрипт Ball и добавим в него переменную для счёта и код, который увеличивает счёт при клике. Закройте пока игру, если она запущена (кнопка Slop). Дважды кликните на скрипте Ball в папке Scripts, чтобы открыть его в Visual Studio.
Сейчас в скрипте у нас есть только метод OnMouseDown с одной строчкой — Destroy(gameObject);. Мы добавим сверху переменную для хранения количества очков. Переменная — это просто ячейка в памяти компьютера, где лежит какое-то число. В нашем случае — счёт. Добавьте эту строчку внутрь класса Ball, перед методом Start (или после открывающей фигурной скобки класса). Вот как должен выглядеть ваш скрипт после добавления. text using System.Collections; using System.Collections.Generic; using unityEngine; public class Ball : MonoBehaviour private int score = 0; void OnMouseDown() { Destroy(gameObject); } } Строчка private int score = 0; означает: создай переменную с именем score, она будет хранить целое число (int — от integer), начальное значение — ноль. Private значит, что другие объекты не могут её менять — только сам шарик.
Но это только переменная. Чтобы увеличить счёт при клике, нужно добавить в метод OnMouseDown ещё одну строчку — до уничтожения шарика. Измените метод OnMouseDown так: text void OnMouseDown() score = score + 1; Destroy(gameObject); Теперь при клике переменная score увеличивается на единицу. Мы это сделали. Но игрок не видит счёт, потому что мы не обновляем текст на экране. Нам нужно как-то обратиться к объекту ScoreText и сказать ему: «Измени свой текст на ’’Score: X”», где X — новое значение. Для этого нам нужно найти этот объект в коде. Добавим ещё одну переменную — ссылку на текст. В начало скрипта, под строчку private int score = 0;, добавьте ещё одну: text public TextMeshProUGUI ScoreText;
Обратите внимание: это public, а не private. Public означает, что мы сможем привязать нужный объект прямо в окне Unity, не вписывая его имя в код. Если Visual Studio подчеркнёт TextMeshProUGUI красным — значит, нужно добавить ссылку на библиотеку. В самом верху, среди других строчек с using, добавьте: text using TMPro; Эта строчка говорит Unity: «мы будем использовать TextMeshPro». Теперь изменим метод OnMouseDown ещё раз. Теперь он должен не только увеличивать счёт, но и обновлять текст на экране. Вот полный код скрипта Ball сейчас. text using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; public class Ball : MonoBehaviour { private int score = 0;
public TextMeshProUGUI scoreText; void OnMouseDown() { score = score + 1; scoreText.text = "Score: " + score; Destroy(gameObject); } } СтрочкаscoreText.text = "Score: " + score; означает: возьми текст объекта scoreText, измени его на фразу «Score: », а после пробела добавь текущее значение переменной score. Знак плюс здесь склеивает текст и число. Сохраните скрипт (Ctrl+S) и вернитесь в Unity. Теперь нужно привязать наш объект ScoreText к переменной scoreText в скрипте. Нажмите на шарик Ball в Иерархии. Посмотрите в Инспектор. Там в разделе Ball (Script) появилось поле Score Text. Сейчас там написано None. Возьмите мышкой объект ScoreText из Иерархии (тот самый, с белой надписью) и перетащите его в это поле. Готово. Теперь скрипт знает, какой текст ему обновлять. Запустите игру (Play). Кликните по шарику. Он исчезнет — и вы увидите, что надпись в левом верхнем углу стала
«Score: 1». Потом вы не можете больше кликнуть, потому что шарика нет. Но счёт работает! Это уже прогресс. Часть третья. Добавляем звук Теперь добавим звук лопанья. Это делается очень просто. Сначала нам нужен звуковой файл. Вы можете скачать любой короткий звук «пуф» или «хлоп» из бесплатных библиотек. Например, на сайте pixabay.com/music есть много бесплатных звуков. Ищите «рор» или «balloon pop». Скачайте короткий файл в формате .wav или .mp3. Когда файл скачан, вернитесь в Unity. Создайте папку для звуков: в окне Project нажмите правой кнопкой на папке Assets, выберите Create -> Folder, назовите Sounds. Перетащите скачанный звуковой файл из папки на компьютере в окно Project — прямо внутрь папки Sounds. Файл появился в Unity. Теперь откройте скрипт Ball снова. Нам нужно добавить переменную для звука и строчку, которая этот звук проигрывает.
Добавим переменную для аудиоисточника. В начало скрипта, под другие переменные, напишите: text public AudioSource popsound; Теперь в метод OnMouseDown добавьте строчку для проигрывания звука — перед уничтожением шарика. Вот как выглядит метод OnMouseDown теперь, text vo±d OnMouseDown() { score = score + 1; scoreText.text = ''Score: " + score; popsound.Play(); Destroy(gameObject); } Сохраните скрипт. Вернитесь в Unity. Нам нужно добавить на шарик компонент AudioSource — это штука, которая умеет проигрывать звуки. Нажмите на шарик Ball в Иерархии. В Инспекторе нажмите кнопку Add Component. В поиске напишите Audio Source и выберите его.
У шарика появился новый раздел Audio Source. Там есть поле AudioClip — это наш звуковой файл. Нажмите на маленький кружок справа от поля и выберите ваш звук из папки Sounds. Теперь вернитесь к скрипту в Инспекторе. Там появилось поле Pop Sound (потому что мы объявили public переменную). Нажмите на шарик Ball в Иерархии, найдите в Инспекторе раздел Ball (Script), поле Pop Sound. Сейчас там None. Нам нужно перетащить в это поле сам объект Ball. Да, странно: мы привязываем звук к тому же объекту, на котором висит скрипт. Возьмите мышкой шарик Ball из Иерархии и перетащите его в поле Pop Sound. Готово. Теперь при клике скрипт найдёт AudioSource на этом же объекте и скажет ему: «Play!» — проиграй звук. Запустите игру. Кликните на шарик. Он исчезнет, счёт увеличится — и вы услышите звук лопанья. Если звука нет — проверьте громкость в Windows и настройки Audio Source (там есть ползунок Volume).
Часть четвёртая. Возрождение шарика Теперь осталось самое интересное — сделать так, чтобы шарик не исчезал навсегда, а появлялся в новом месте. У нас есть проблема: когда мы уничтожаем шарик, его больше нет. Кликнуть не во что. Нужно создать новый шарик взамен старого. Но как создать объект из кода? В Unity есть команда Instantiate — она создаёт копию любого объекта. Мы сделаем так: при клике мы не уничтожаем шарик, а перемещаем его в новое место. Но это выглядит неестественно — шарик не лопается, а телепортируется. Лучше уничтожать старый и создавать новый. Таки сделаем. Для начала нам нужно иметь где-то «заготовку» шарика — префаб. Префаб — это шаблон объекта, сохранённый отдельно. Создадим его. В Иерархии нажмите на шарик Ball. Перетащите его мышкой в окно Project — прямо на папку Assets (или в папку Prefabs, которую мы сейчас создадим). Когда отпустите кнопку мыши, шарик в Иерархии станет синим. Это значит, что теперь это не просто объект, а ссылка на префаб. Префаб появился в окне Project — с синим квадратиком.
Теперь откройте скрипт Ball. Нам нужно добавить переменную для префаба. В начало скрипта, под другие переменные, добавьте: text public Gameobject ballPrefab; Теперь изменим метод OnMouseDown. Вместо Destroy(gameObj ect); мы напишем: сначала создать новый шарик в случайном месте, потом уничтожить старый. Вот весь метод OnMouseDown целиком. text void OnMouseDown() score = score + 1; scoreText.text - "Score: " + score; popsound.Play(); float randomx = Random.Range(-3f, 3f); float randomY = Random.Range(-2f, 2f); Vectors newPosition = new Vector3(randomx, randomY, 0); Instantiate(ballPrefab, newPosition, Quaternion.identity); Destroy(gameobject); }
Разберём новые строчки. float randomX = Random.Range(-3f, 3f);— генерируем случайное число от минус трёх до трёх. Это координата X нового шарика. Буква f означает, что число дробное (с плавающей точкой). float randomY = Random.Range(-2f, 2f);—to же самое для Y Почему от -2 до 2? Потому что по вертикали пространства чуть меньше. Vector3 newPosition = new Vector3(randomX, randomY, 0); — создаём точку (координату) с этими X и Y Z — ноль, потому что у нас 20-игра. Instantiate(ballPrefab, newPosition, Quaternion . identity); — создаём копию префаба шарика в новой позиции. Quaternion.identity — означает «без поворота». Сохраните скрипт. Вернитесь в Unity. Нажмите на шарик Ball в Иерархии. В Инспекторе в разделе Ball (Script) появилось поле Ball Prefab. Сейчас там None.
Возьмите из окна Project префаб шарика (синий квадратик с названием Ball) и перетащите его в это поле. Готово. Теперь последний штрих. Наш новый шарик, который создаётся через Instantiate, должен тоже иметь все настройки — скрипт, звук, коллайдер. Если вы сделали префаб из шарика, у которого уже был скрипт с привязанными ScoreText и PopSound, то всё будет работать. Но нужно убедиться. Нажмите на префаб Ball в окне Project. Посмотрите в Инспектор. Там должен быть компонент Ball (Script) с заполненными полями Score Text и Pop Sound. Если поля пустые — заполните их прямо в префабе (ScoreText перетащите из Иерархии, Pop Sound — сам префаб). Это важно, потому что новые шарики создаются именно из этого префаба и должны знать, какой текст обновлять. Запустите игру. Кликните на шарик. Он исчезнет, счёт увеличится, прозвучит звук — ив случайном месте появится новый шарик. Кликайте снова. Счёт растёт. Бесконечно. Поздравляю. Вы только что сделали полноценную, работающую игру.
Что у нас получилось Давайте перечислим, что делает ваша игра сейчас. При запуске на экране один шарик и надпись «Score: О». Игрок кликает на шарик. Счёт увеличивается на единицу, надпись обновляется. Проигрывается звук лопанья. Старый шарик исчезает. На его месте в случайном месте экрана появляется новый шарик. Игрок может кликать бесконечно. Счёт растёт до любых значений. Нет конца, нет поражения — просто бесконечное лопанье шариков. Это настоящая аркадная игра. Простая, но работающая. Что вы теперь знаете и умеете (чек-лист подглавы 2.3) Вы создали текстовый элемент для счёта. Вы добавили объект TextMeshPro, расположили его в левом верхнем углу, изменили размер и цвет, задали начальный текст «Score: О».
Вы добавили в скрипт переменную для счёта, private int score = 0;—теперь компьютер помнит, сколько очков набрал игрок. Вы научились обновлять текст из кода. Строчка ScoreText. text = "Score: " + score; — склеивает текст с числом и показывает результат на экране. Вы привязали объект ScoreText к переменной в скрипте. Через поле в Инспекторе, просто перетащив мышкой. Вы добавили в игру звук. Скачали файл, создали папку Sounds, добавили компонент Audio Source на шарик, привязали звук, написали строчку popSound . Play ( );. Вы создали префаб шарика. Перетащили объект из Иерархии в окно Project — теперь у вас есть шаблон, из которого можно создавать новые шарики. Вы написали код для создания новых шариков в случайном месте. Instantiate( ballPrefab, newPosition, Quaternion.identity);—одна строчка делает копию шарика где угодно.
Вы сгенерировали случайные координаты. Random. Range(-3f, 3f) —даёт случайное число между -3 и 3. Шарики появляются в разных местах, никогда не зная, где именно. У вас есть работающая бесконечная игра. Шарики лопаются, счёт растёт, звук играет, новые шарики появляются. Можно играть сколько угодно. От автора Остановитесь на минуту. Похлопайте себе. Вы только что сделали то, за чем пришли в эту книгу. Вы написали игру. Не пример из учебника, не демонстрацию возможностей — а настоящую, работающую игру, в которую можно играть. Она, конечно, простая. Но каждая сложная игра когда-то начиналась с такой же простой. У вас есть всё, чтобы двигаться дальше. Вы знаете, как создавать объекты, как писать скрипты, как реагировать на клики, как работать со счётом и звуком, как создавать новые объекты из кода. В следующей главе мы превратим эту игру в нечто более серьёзное. Добавим врагов, которые движутся к игроку.
Добавим несколько жизней. Сделаем игру по-настоящему сложной и интересной. Но сейчас — просто насладитесь моментом. Вы — разработчик игр. Конец Главы 2. Поехали дальше, к Главе 3?
Глава 3. Враги, движение и жизни (День пятый) 3.1. Создаём врага и учим его летать Время выполнения: 20-25 минут. Цель: создать объект врага, написать скрипт для его движения и заставить его преследовать игрока. Что изменится в нашей игре До этого момента в игре был только один активный объект — шарик, по которому нужно кликать. Игроку ничто не мешало, ничто не угрожало. Это как стрельба по мишеням в тире, где мишени не двигаются и не стреляют в ответ. Теперь мы добавим врага. Это будет чёрный (или красный, на ваш вкус) квадрат или круг, который появляется на экране и начинает двигаться к шарику. Если враг касается шарика — игрок теряет жизнь. Игра станет динамичной. Игроку нужно не только лопать шарики, но и уворачиваться от врагов — или лопать шарики быстрее, чем враги до них доберутся.
В этой подглаве мы создадим врага, настроим его внешний вид и, самое главное, научим его двигаться. Создаём спрайт врага Враг — это такой же объект, как и шарик. Только выглядеть он будет иначе и вести себя иначе. Начнем с внешности. Нажмите правой кнопкой мыши в пустом месте Иерархии. Выберите 2D Object, потом Sprites, потом Square. Квадрат — самая простая форма, но вы можете сделать и круг, если хотите. Разницы нет. На сцене появился белый квадрат. Давайте сделаем его похожим на врага — тёмным и зловещим. Нажмите на новый объект в Иерархии. Найдите в Инспекторе раздел Sprite Renderer, а в нём — поле Color. Нажмите на белый прямоугольник и выберите чёрный цвет. Или тёмно-красный. Или фиолетовый. Главное, чтобы враг отличался от шарика и от фона. Теперь переименуйте объект. Нажмите F2 и назовите его Enemy.
Увеличим врага, чтобы он был заметнее. В разделе Transform найдите Scale и измените X и Y на 1.5 (не на два, как у шарика, а чуть меньше — пусть враг будет поменьше шарика, так интереснее). Расположим врага в случайном месте, не на том же месте, где шарик. Вы можете просто перетащить его мышкой в любой угол сцены. Например, в правый верхний угол. Главное — чтобы он не касался шарика при старте игры. Вот и всё. Враг создан. Но пока он просто стоит на месте и ничего не делает. Эту неподвижность мы сейчас исправим. Создаём скрипт для врага Как и у шарика, у врага должно быть поведение. Поведение задаётся скриптом. Создадим новый скрипт для врага. В окне Project откройте папку Scripts. Нажмите правой кнопкой мыши внутри папки, выберите Create -> C# Script. Назовите его EnemyMovement (без пробелов, с большой буквы). Теперь прикрепите этот скрипт к врагу. Перетащите файл EnemyMovement из окна Project на объект Enemy в
Иерархии (или на самого врага на сцене). Проверьте: нажмите на Enemy в Иерархии, в Инспекторе должен появиться раздел EnemyMovement (Script). Откройте скрипт. Дважды кликните на файле EnemyMovement в папке Scripts. Откроется Visual Studio. Unity создала шаблон скрипта с пустыми методами Start и Update. Нам нужен Update — он выполняется каждый кадр, примерно шестьдесят раз в секунду. Именно здесь мы будем менять положение врага, чтобы он двигался. Как заставить объект двигаться к другому объекту Чтобы враг двигался, нам нужно в каждом кадре немного сдвигать его в сторону шарика. Представьте, что вы каждую секунду делаете маленький шаг в сторону своей цели. Через минуту вы будете рядом. То же самое делает компьютер — только не одну секунду, а одну шестидесятую секунды. Для движения нам понадобятся три вещи. Первое — скорость. Скажем, враг двигается со скоростью 3 единицы в секунду. Это значение мы сделаем публичным, чтобы можно было менять его в Инспекторе.
Второе — направление. Нужно вычислить вектор от врага к шарику: «шарик находится правее меня? Тогда двигаюсь вправо. Шарик выше? Двигаюсь вверх». Третье — само перемещение. Добавим к текущей позиции врага маленькое смещение в нужном направлении, умноженное на скорость и на время, прошедшее с прошлого кадра. Звучит сложно, но на C# это пишется в три строчки. Сейчас покажу. Вот весь код скрипта EnemyMovement. text using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyMovement : MonoBehaviour { public float speed = 3f; private Transform ball; void Start() { ball = Gameobject.Find("Ball").transform; } void Update() { if (ball 1 = null)
Vector2 direction = (ball.position - transform.position).normalized; transform.Translate(direction * speed * Time.deltaTime); } } } Разберём каждую строчку. public float speed = 3f;—объявляем переменную для скорости. Public означает, что мы сможем менять её в Инспекторе, прямо в Unity, не открывая код. 3f — это три с буквой f, которая говорит, что число дробное. private Transform ball;—объявляем переменную для хранения ссылки на шарик. Transform — это не сам объект, а его положение, поворот и масштаб. Нам нужно именно положение. В методе Start () мы находим шарик. GameObject. Find( "Ball" ) — ищет объект с именем Ball на всей сцене. . transform — берёт у этого объекта его Transform. Всё это сохраняется в переменную ball. Почему в Start, а не в Update? Потому что найти шарик достаточно один раз в начале игры. Если искать его
шестьдесят раз в секунду, компьютер будет делать лишнюю работу. В методе Update () происходит самое интересное. Сначала проверка: if (ball != null)—если шарик существует (не уничтожен), то двигаемся. Если шарика нет — ничего не делаем, чтобы не было ошибки. Vector2 direction - (ball.position - transform.position).normalized;— вычисляем направление. Вычитаем позицию врага из позиции шарика, получаем вектор, .normalized превращает его в единичный вектор — направление без длины. Нам не важно, далеко ли шарик, важно, в какую сторону идти. transform,Translate(direction * speed * Time. deltaTime); —перемещаем врага, direction — направление, speed — скорость, Time.deltaTime — время, прошедшее с прошлого кадра (чтобы движение не зависело от частоты кадров). Умножаем всё это и сдвигаем врага. Сохраните скрипт (Ctrl+S) и вернитесь в Unity.
Проверяем движение Запустите игру (Play). Шарик на месте. Враг начинает медленно (или не очень медленно — зависит от скорости 3) двигаться к шарику. Если скорость вам кажется слишком высокой или слишком низкой, остановите игру (Slop), нажмите на врага Enemy в Иерархии, найдите в Инспекторе раздел EnemyMovement (Script) и измените значение Speed прямо в поле. Поставьте 2 — будет медленнее. Поставьте 5 — будет быстро. Подберите на свой вкус. Враг движется? Отлично. Идём дальше. Проблема: враг настигает шарик и... ничего не происходит Если враг касается шарика, он просто проходит сквозь него. Потому что мы не запрограммировали, что должно произойти при столкновении. В реальной игре при касании врага игрок должен терять жизнь, а враг, возможно, исчезать или отскакивать. Это мы сделаем в следующей подглаве.
А пока — пусть враг просго движется. Вы и так сделали большой шаг: создали движущийся объект, который самостоятельно находит цель и идёт к ней. Это основа любой игры с преследованием. Небольшая проблема: поиск объекта по имени В скрипте мы написали Gameobject. Find( "Ball"). Это работает, но только если шарик называется именно «Ball», с большой буквы. Если вы назвали шарик по- другому — исправьте имя в скрипте. Кроме того, Find ищет объект по всей сцене, но делает это не очень быстро. Для одного врага это нормально. Но если у вас будет сто врагов, каждый из них будет искать шарик в момент запуска — компьютер может задуматься. Пока нас это не волнует, но имейте в виду: позже мы найдём способ лучше. Что вы теперь знаете и умеете (чек-лист подглавы 3.1) Вы создали врага. Вы добавили на сцену квадрат (или круг), покрасили его в тёмный цвет, переименовали в Enemy и увеличили до подходящего размера.
Вы создали скрипт для врага. Вы назвали его EnemyMovement и прикрепили к объекту Enemy. Вы научились находить другой объект из кода. Строчка GameObject. Find( “Ball" ) находит шарик на сцене по его имени. Вы вычислили направление от врага к шарику. (ball. position - transform, position). normalized — эта формула даёт единичный вектор, указывающий, куда нужно двигаться. Вы заставили врага двигаться, transform.Translate(direction * speed * Time . deltalime)—каждая строчка кода в методе Update сдвигает врага на маленькое расстояние к цели. Вы можете менять скорость врага прямо в Инспекторе. Потому что переменная speed объявлена как public. У вас есть движущийся враг, который преследует шарик. Да, пока он просто проходит сквозь него. Но это уже выглядит как настоящая игра — опасность, от которой нужно убегать или которую нужно избегать.
От автора Посмотрите, как выросла сложность игры всего за одну подглаву. Ещё минуту назад был просто неподвижный квадрат. Теперь это разумное существо, которое видит цель и идёт к ней. Это основа любого врага в любой игре — от простой аркады до сложного шутера. В следующей подглаве (3.2) мы добавим столкновения. Когда враг касается шарика, шарик будет терять жизнь (или игрок — здоровье). А чтобы игра не закончилась после первого же касания, мы добавим систему жизней и экран «Game Over». Сейчас у врага нет своей цели, кроме как коснуться шарика. В следующей подглаве это касашение будет иметь последствия. Отдохните немного и переходите к 3.2.
3.2. Столкновения, жизни и конец игры Время выполнения: 25-30 минут. Цель: добавить обработку столкновений, систему жизней для шарика, исчезновение врага при касании и экран «Game Over». Что мы сделаем в этой подглаве Сейчас враг и шарик не замечают друг друга. Для них не существует столкновений. Мы это исправим. В Unity есть встроенная система физики. Если у двух объектов есть специальные компоненты — коллайдеры, — они могут сталкиваться. А если мы добавим на шарик компонент Rigidbody2D, то сможем отслеживать эти столкновения в коде и решать, что делать: уменьшить количество жизней, уничтожить врага, воспроизвести звук. Вот план на эту подглаву. Первое. Мы добавим на шарик компонент Rigidbody2D, чтобы Unity начала отслеживать его столкновения с другими объектами.
Второе. Мы напишем код в скрипте Ball, который будет срабатывать при столкновении с врагом — уменьшать счётчик жизней и уничтожать врага. Третье. Мы добавим в игру жизни. Игрок начинает с тремя жизнями. При каждом столкновении с врагом жизнь отнимается. Четвёртое. Мы создадим экран проигрыша — текстовую надпись «Game Over», которая появляется, когда жизни кончаются. И игра останавливается. Звучит много, но на деле — пара новых переменных и один новый метод в скрипте Ball. Поехали. Часть первая. Добавляем на шарик физическое тело Чтобы шарик мог сталкиваться и мы могли отследить эти столкновения, ему нужен компонент Rigidbody2D (твердое тело для двухмерной физики). Он сообщает Unity: «Этот обьект подчиняется законам физики — он может сталкиваться, на него может действовать гравитация, его можно толкать».
Нам не нужна гравитация — мы не хотим, чтобы шарик падал вниз. Но нам нужно, чтобы Unity вызывала специальный метод при столкновении. Нажмите на шарик Ball в Иерархии. В Инспекторе нажмите кнопку Add Component. В поиске напишите Rigidbody 2D и выберите его. У шарика появился новый раздел — Rigidbody 2D. Там много настроек. Нам нужно изменить одну. Найдите параметр Gravity Scale (масштаб гравитации). По умолчанию там стоит единица. Это значит, что шарик будет падать вниз, как настоящий шар. Нам это не нужно. Поставьте там ноль. Теперь шарик не будет падать, но останется способным сталкиваться и сообщать нам об этих столкновениях. Всё. Физическое тело добавлено. Часть вторая. Добавляем врагу коллайдер У врага, скорее всего, уже есть коллайдер. Помните, когда мы создавали квадрат через 2D Object — Sprite — Square, Unity автоматически добавила к нему Box Collider 2D — квадратную невидимую оболочку. Проверьте: нажмите на
врага Enemy в Иерархии, в Инспекторе найдите раздел Box Collider 2D. Если он есть — всё хорошо. Если нет — нажмите Add Component и добавьте Box Collider 2D вручную. Коллайдер нужен, чтобы Unity понимала, где заканчивается враг. Без коллайдера объекты проходят сквозь друг друга как призраки. У врага тоже было бы неплохо добавить Rigidbody2D, но необязательно. Для простого столкновения достаточно коллайдера. Если вы хотите, чтобы враг отскакивал от шарика, добавьте ему Rigidbody2D и поставьте Gravity Scale на ноль. Но пока оставим как есть — враг будет просто исчезать при столкновении. Часть третья. Пишем код для столкновений Теперь откроем скрипт шарика — Ball — в Visual Studio. Дважды кликните на нём в папке Scripts. Мы добавим новый метод. В Unity есть специальный метод, который автоматически вызывается, когда объект с Rigidbody2D сталкивается с другим объектом. Называется он 0nCollisionEnter2D. Внутри этого метода мы
напишем, что должно произойти: уменьшить жизни, уничтожить врага, проверить, не закончилась ли игра. Но сначала добавим переменную для жизней. В начало скрипта, туда, где у нас уже есть переменные score, scoreText, popSound, ball Prefab, добавим новую. text public int lives = 3; public TextMeshProUGUI livesText; Первая строчка — количество жизнен. Начинаем с трёх. Public, чтобы мы могли видеть это значение в Инспекторе (и, если захотим, менять). Вторая строчка — ссылка на текстовый объект, который будет показывать жизни. Как и со счётом, мы создадим текстовую надпись для жизней. Но сначала давайте напишем метод OnCollisionEnter2D. Вставьте его куда-нибудь внутрь класса Ball, например, после метода OnMouseDown. text void OnCollisionEnter2D(Collision2D collision) { if (collision.gameobject.CompareTag("Enemy")) { lives = lives - 1; UpdateLivesText();
Destroy(collision.gameobject); if (lives <= 0) { GameOver(); } } } Разберём каждую строчку. void OnCollisionEnter2D(Collision2D collision) — метод, который Unity вызывает при столкновении. В параметр collision попадает информация о том, с кем столкнулся наш объект. if (collision.gameobject.CompareTag("Enemy")) — проверяем, что столкновение произошло именно с врагом, collision. gameObject — это объект, с которым мы столкнулись. CompareTag( "Enemy") — сравнивает его тег с текстом «Enemy». Что такое тег? Это метка, которую мы повесим на врага, чтобы отличать его от других объектов. Если это действительно враг, то выполняем следующие действия.
lives = lives - 1;—уменьшаем количество жизней на единицу. UpdateLivesText (); — вызываем метод, который обновит текст на экране. Этот метод мы напишем чуть позже. Destroy(collision.gameobject);—уничтожаем врага, с которым столкнулись. if (lives <= 0)—проверяем, не закончились ли жизни. GameOver(); —вызываем метод, который завершит игру. Его мы тоже напишем. Теперь нам нужно написать метод UpdateLivesText ( ) и GameOver (), а также добавить переменную для текста жизней. Добавьте эти методы внутрь класса Ball, после OnConisionEnter2D. text void UpdateLivesText() { LivesText.text "Lives: " + lives;
void GameOver() { Time.timescale - Of; Debug.Log("Game Over!"); Метод Update Live sText просто обновляет текст жизней — склеивает слово «Lives: » с текущим количеством жизней. Метод GameOver пока делает две вещи. Time. timeScale = 0f;—останавливает время в игре. Всё замирает: враги не двигаются, шарики не реагируют на клики. И Debug. Log ("Game Over ! ’’); — выводит сообщение в Консоль, чтобы мы знали, что метод сработал. Позже мы заменим это на показ красивой надписи «Game Over» на экране. Вот как выглядит полный скрипт Ball после всех добавлений (покажу целиком, чтобы вы не запутались). text using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; public class Ball : MonoBehaviour private int score = 0;
public TextMeshProllGUI scoreText; public AudioSource popsound; public Gameobject ballPrefab; public int lives - 3; public TextMeshProllGUI livesText; void OnMouseDown() { score = score + 1; scoreText. text = ''Score: " + score; popSound.Play(); float randomx = Random.Range(-3f, 3f); float randomY = Random.Range(-2f, 2f); Vectors newPosition = new Vector3(randomx, randomY, 0); Instantiate(ballPrefab, newPosition, Quaternion.identity); Destroy(gameobject); } void 0nCollisionEnter2D(Collision2D collision) { if (collision.gameobject.CompareTag("Enemy")) { lives = lives - 1; UpdateLivesText(); Destroy(collision.gameobject); if (lives <= 0) { GameOver(); } } } void UpdateLivesText() {
livesText.text "Lives: " + lives; } void GameOver() { Time.timescale = Of; Debug.Log("Game Over!"); } } Сохраните скрипт (Ctrl+S). Часть четвёртая. Создаём текстовую надпись для жизней Вернитесь в Unity. Теперь нам нужно создать текст для отображения жизней — точно так же, как мы создавали текст для счёта. Нажмите правой кнопкой в Иерархии, выберите UI -> Text — TextMeshPro. На сцене появится новый текст. Переименуйте его в LivesText (нажмите F2). Расположите его в правом верхнем углу. В Инспекторе найдите Rect Transform, параметры Pos X и Pos Y. Поставьте Pos X на -100 (отрицательное число смещает текст вправо), Pos Y на -50.
Измените выравнивание текста. В разделе TextMeshPro найдите параметр Alignment (иконка с квадратиками) и выберите выравнивание по правому краю (правый верхний угол). Чтобы текст прижался к правому краю. Измените текст. В поле Text (где сейчас написано «New Text») напишите Lives: 3. Измените размер шрифта на 24 (как у счёта). Теперь привяжите этот текст к скрипту шарика. Нажмите на шарик Ball в Иерархии. В Инспекторе в разделе Ball (Script) найдите поле Lives Text. Сейчас там None. Перетащите в него объект LivesText из Иерархии. Готово. Часть пятая. Настраиваем теги для врага В коде мы написали collision.gameObject.CompareTag("En emy " ). Это значит, что у врага должен быть тег Enemy. Сейчас у него нет никакого тега. Давайте назначим.
Нажмите на врага Enemy в Иерархии. В верхней части Инспектора, сразу под именем объекта, есть выпадающий список Tag. Сейчас там написано «Untagged». Нажмите на него. В выпадающем меню выберите Add Tag... (добавить тег). Откроется окно с настройками тегов. В этом окне нажмите на плюсик (+) под списком Tags. Появится новое поле. Напишите там Enemy (с большой буквы) и нажмите Enter. Теперь закройте это окно (можно нажать на крестик или на сам Unity Editor). Снова нажмите на врага Enemy в Иерархии. В выпадающем списке Tag теперь появился пункт Enemy. Выберите его. Всё. Тег назначен. Теперь Unity знает, что этот объект — враг. Часть шестая. Проверяем Запустите игру (Play).
В левом верхнем углу — счёт. В правом верхнем — жизни: «Lives: 3». Шарик на месте. Враг движется к нему. Когда враг касается шарика, происходит несколько вещей. Враг исчезает — его уничтожил код в методе OnCollisionEnter2D. Количество жизней уменьшается на единицу. Теперь в правом верхнем углу «Lives: 2». В Консоли (окно внизу) появляется сообщение «Game Over!»? Нет, пока не появляется, потому что жизни ещё не закончились. Если враг коснётся шарика ещё два раза (всего три раза), жизни станут нулём. Тогда сработает метод GameOver. Время остановится (Time. timeScale = 0f). Враги замирают (если успели появиться новые). Шарик больше нельзя кликнуть. В Консоли появится «Game Over!». Игра закончена.
Что пока не идеально У нас есть несколько проблем, которые мы решим в следующих подглавах. Первая проблема. После того как враг коснулся шарика и исчез, больше врагов нет. Игра становится безопасной. Игрок может бесконечно лопать шарики, и никто ему не угрожает. Нужно, чтобы враги появлялись снова и снова — как и шарики. Вторая проблема. Когда жизни кончаются, игра останавливается, но нет никакой надписи «Game Over» на экране. Только сообщение в Консоли, которое игрок не видит. Нужно создать красивый текст «Game Over» и кнопку «Restart». Третья проблема. У нас только один враг. А в хорошей игре врагов должно быть много, и появляться они должны постоянно, чтобы игроку было всё время страшно. Все это мы добавим в подглавах 3.3 и 3.4. А пока — радуйтесь тому, что уже есть: столкновения работают, жизни уменьшаются, игра заканчивается.
Что вы теперь знаете и умеете (чек-лист подглавы 3.2) Вы добавили на шарик компонент Rigidbody2D. И поставили Gravity Scale на ноль, чтобы шарик не падал, но мог сталкиваться. Вы написали метод OnCollisionEnter2D. Этот метод автоматически вызывается при каждом столкновении шарика с другим объектом. Вы научились проверять, с кем именно произошло столкновение, collision. gameobject.CompareTag ( "Enemy" ) отличает врага от всего остального. Вы создали систему жизней. Переменная lives хранит количество жизней, начинается с трёх, уменьшается при каждом столкновении с врагом. Вы создали текстовую надпись для жизней. Добавили объект LivesText, расположили его в правом верхнем углу, привязали к скрипту шарика. Вы создали метод GameOver, который останавливает игру. Time. timeScale = Of — всё замирает. Игрок больше не может кликать по шарикам, враги не двигаются.
Вы настроили теги. Назначили врагу тег Enemy, чтобы код мог его распознать. У вас есть работающее столкновение. Враг касается шарика — исчезает -> жизни уменьшаются - когда жизни кончаются, игра останавливается. От автора Столкновения — это сердце любой игры. Всё, что происходит в играх, — это постоянные проверки: «А не коснулся ли игрок врага?», «А не подобрал ли игрок аптечку?», «А не вылетела ли пуля за пределы экрана?». Вы только что реализовали одну из самых главных механик. Теперь игра стала сложной. Игрок не может просто сидеть и кликать по шарикам — ему нужно следить, чтобы враг не добрался до шарика. Но после того как враг коснулся шарика, он исчезает — и опасность уходит. Нужно, чтобы враги появлялись снова и снова. Этим мы займёмся в следующей подглаве. В подглаве 3.3 мы создадим систему спавна врагов — чтобы они появлялись бесконечно, с нарастающей сложностью. Игра станет по-настоящему динамичной.
/\ пока — запустите игру ещё раз. Почувствуйте, как меняется напряжение, когда враг приближается к шарику. Постарайтесь лопнуть шарик до того, как враг его коснётся. Это уже похоже на настоящий вызов. Переходите к 3.3.
3.3. Бесконечные враги и нарастающая сложность Время выполнения: 20-25 минут. Цель: создать систему, которая постоянно создаёт новых врагов в случайных местах, и сделать игру сложнее с течением времени. Что мы сделаем в этой подглаве Сейчас в игре есть только один враг, который появляется один раз в начале игры. После того как он коснулся шарика и исчез, больше врагов нет. Это неправильно. В хорошей аркадной игре враги должны появляться бесконечно, и чем дольше играет игрок, тем их должно становиться больше или они должны двигаться быстрее. Вот план на эту подглаву. Первое. Мы создадим систему спавна врагов — специальный объект (менеджер), который будет создавать новых врагов через определённые промежутки времени. Второе. Мы сделаем так, чтобы враги появлялись в случайных местах за пределами экрана и двигались к шарику.
Третье. Мы добавим нарастающую сложность: чем больше очков набрал игрок, тем быстрее двигаются враги и тем чаще они появляются. Четвёртое. Мы создадим префаб врага, чтобы менеджер мог создавать его копии. Звучиз сложно, но на деле — один новый скрипт, несколько переменных и один объект на сцене. Поехали. Часть первая. Создаём префаб врага Сейчас враг Enemy есть на сцене — это конкретный объект. Чтобы мы могли создавать его копии из кода, нам нужно превратить его в префаб — шаблон, заготовку. Точно так же, как мы делали с шариком. В Иерархии нажмите на врага Enemy. Перетащите его мышкой в окно Project — прямо на папку Assets (или в папку Prefabs, если вы её создали). Когда отпустите кнопку мыши, враг в Иерархии станет синим. Это значит, что теперь это не просто объект, а ссылка на префаб. В окне Project появился синий квадратик с названием Enemy. Теперь исходного врага на сцене можно удалить. Мы не будем создавать врага вручную в начале игры — пусть
менеджер славна создаёт их сам. Нажмите на Enemy в Иерархии и нажмите Delete. Врага на сцене больше нет. Но его префаб сохранён, и мы можем создавать его копии в любом количестве. Часть вторая. Создаём менеджер спавна Менеджер спавна — это специальный объект, который будет управлять появлением врагов. У него не будет графики — только скрипт. Создадим пустой объект. В Иерархии нажмите правой кнопкой мыши и выберите Create Empty. Появится объект с названием GameObject. Переименуйте его в SpawnManager (нажмите F2). Теперь создадим для него скрипт. В окне Project, в папке Scripts, нажмите правой кнопкой -> Create -> C# Script. Назовите его EnemySpawner. Прикрепите скрипт к объекту SpawnManager: перетащите файл EnemySpawner из окна Project на объект SpawnManager в Иерархии.
Откройте скрипт (дважды кликните на нём в папке Scripts). Откроется Visual Studio. Напишем код для спавна врагов. Вот весь скрипт EnemySpawner. text using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemySpawner : MonoBehaviour { public GameObject enemyprefab; public float spawninterval = 2f; public float spawnRadius = 5f; private float timer; void Start() { timer = spawninterval; } void Update() { timer = timer - Time.deltaTime; if (timer <= Of) { SpawnEnemy(); timer = spawninterval; } } void SpawnEnemy() {
Vectors spawnPosition = GetRandomPosition(); Instantiate^enemyprefab, spawnPosition, Quaternion.identity); } Vectors GetRandomPosition() { float randomx = Random.Range(-spawnRadius, spawnRadius); float randomY = Random.Range(-spawnRadius, spawnRadius); return new Vector3(randomx, randomY, 0f); } } Разберем каждую часть. public Gameobject enemyPrefab;—переменная для префаба врага. Мы привяжем к ней наш синий префаб Enemy из окна Project. public float spawninterval = 2f; —интервал между появлениями врагов. По умолчанию — каждые две секунды. public float spawnRadius = 5f;—радиус, в котором могут появляться враги. Координаты от -5 до 5 по
private float timer;—внутренний счётчик. Он отсчитывает время от spawninterval до нуля, а когда достигает нуля — создаёт врага и сбрасывается. В методе Start () мы устанавливаем начальное значение таймера равным интервалу. Это значит, что первый враг появится через две секунды после начала игры, а не сразу. В методе Update() мы каждую секунду (точнее, каждый кадр) вычитаем из таймера время, прошедшее с прошлого кадра — Time . deltaTime. Когда таймер становится меньше или равен нулю, мы вызываем SpawnEnemy () и сбрасываем таймер обратно на spawninterval. Метод SpawnEnemy () получает случайную позицию через GetRandomPosition () и создаёт копию врага в этой позиции. Метод GetRandomPosition() генерирует случайные X и Y в диапазоне от -spawnRadius до spawnRadius и возвращает их в виде точки (Vector3). Сохраните скрипт (Ctrl+S) и вернитесь в Unity.
Часть третья. Настраиваем спавнер Теперь привяжем префаб врага к скрипту: Нажмите на объект SpawnManager в Иерархии. В Инспекторе в разделе EnemySpawner (Script) найдите поле Enemy Prefab. Сейчас там None. Перетащите в это поле префаб врага — синий квадратик с названием Enemy из окна Project. Готово. Теперь запустите игру (Play). Шарик на месте. Через две секунды в случайном месте появится враг. Еще через две секунды — ещё один враг. И ещё. Они появляются бесконечно, каждые две секунды. Враги движутся к шарику (благодаря скрипту EnemyMovement, который у них есть). Шарик лопается, счёт растёт. Если враг касается шарика, он исчезает, жизни уменьшаются. Но враги продолжают появляться снова и снова. Игра стала бесконечной. Теперь в ней есть настоящий вызов.
Часть четвёртая. Нарастающая сложность Пока враги появляются с фиксированной скоростью — раз в две секунды. И двигаются с фиксированной скоростью — 3 единицы в секунду. Это быстро надоедает. Нужно, чтобы игра становилась сложнее по мере того, как игрок набирает очки. Сделаем так: чем больше счёт, тем чаще появляются враги и тем быстрее они двигаются. Для этого нам нужно, чтобы спавнер и враги знали текущий счёт. Но счёт хранится в скрипте Ball. Как одному скрипту узнать переменную из другого скрипта? Есть несколько способов. Мы воспользуемся самым простым — найдём объект Ball на сцене и прочитаем его переменную score. Откроем скрипт EnemyMovement (движение врага) и добавим в него зависимость от счёта. Сейчас скрипт EnemyMovement выглядит так. text using System.Collections; using System.Collections.Generic;
using UnityEngine; public class EnemyMovement : MonoBehaviour public float speed = 3f; private Transform ball; void Start() { ball = GameObject. Find('‘Ball"). transform; } void Update() { if (ball i= null) { Vector? direction = (ball.position - transform.position).normalized; transform.Translate(direction * speed * Time.deltaTime); } } } Мы изменим его. Добавим метод, который будет вычислять скорость в зависимости от счёта. Но сначала нам нужно узнать счёт. Вот новый скрипт EnemyMovement. text using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyMovement : MonoBehaviour
public float baseSpeed = 2f; public float speedMultiplier = 0.05f; private Transform ball; private Ball ballscript; void Start() { ball = GameObject.Find("Ball").transform; ballscript = GameObject.Find("Ball").GetComponent<Ball>(); } void update() { if (ball != null) { float currentspeed = baseSpeed + (ballscript.GetScore() * speedMultiplier); Vector2 direction = (ball.position - transform.position).normalized; transform.Translate(direction * currentspeed * Time.deltaTime); } } } Разберём изменения. public float baseSpeed - 2f;—базовая скорость врага (начальная). public float speedMultiplier = 0.O5f;— множитель: за каждое очко скорость увеличивается на 0.05. То есть при десяти очках скорость вырастет на 0.5, при ста — на 5.
private Ball ballscript;—переменная, в которую мы сохраним ссылку на скрипт Ball. В методе Start () мы добавили строчку ballscript = Gameobject. Find(’’Ball"). GetComponent<Ball> (); — находим объект Ball, берём у него компонент (скрипт) Ball и сохраняем в переменную ballScript. В методе Update() мы вычисляем currentspeed — текущую скорость = базовая + (счёт * множитель). Остальное без изменений. Но этот код не заработает, потому что в скрипте Ball нет публичного метода GetScore(). Нужно его добавить. Откройте скрипт Ball. Добавьте в него вот этот метод (куда-нибудь внутрь класса, например, после GameOver). text public int GetScore() { return score; } Этот метод просто возвращает значение переменной score. Он публичный, то есть другие скрипты могут его вызвать.
Сохраните оба скрипта (Ball и EnemyMovement). Теперь сделаем то же самое для спавнера — пусть враги появляются тем чаще, чем больше счёт. Откройте скрипт EnemySpawner. Изменим его. text using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemySpawner : MonoBehaviour { public GameObject enemyPrefab, public float baseSpawninterval = 2f; public float minSpawnlnterval = 0.5f; public float intervalMultiplier = O.Olf; private float timer; private Ball ballscript; void Start() { timer = baseSpawninterval; ballscript = GameObject.Find("Ball").GetComponent<Ball>(); } void Update() { timer = timer - Time.deltaTime; if (timer <= Of) { SpawnEnemy();
float currentinterval = CalculateSpawnlnterval(); timer = currentinterval; } } float CalculateSpawnInterval() { if (ballscript == null) return baseSpawninterval; int score = ballscript.GetScore(); float newlnterval = baseSpawninterval - (score * intervalMultiplier); if (newlnterval < minSpawnlnterval) newlnterval = minSpawnlnterval; return newlnterval; } void SpawnEnemy() { Vectors spawnPosition - GetRandomPosition(); Instantiate(enemyPrefab, spawnPosition, Quaternion.identity); } Vectors GetRandomPosition() { float randomX = Random.Range(-5f, 5f); float randomY = Random.Range(-4f, 4f); return new Vector3(randomX, randomY, 0f); } } Разберём новые части.
public float baseSpawninterval = 2f; — начальный интервал (две секунды). public float minSpawnlnterval = 0.5f;— минимальный интервал (чаще чем раз в полсекунды враги не появляются, чтобы игра не стала невозможной). public float intervalMultiplier = 0.01f;— множитель: за каждое очко интервал уменьшается на 0.01 секунды. private Ball ballscript;—ссылка на скрипт шарика. В St art () мы находим шарик и сохраняем ссылку. В Update() после спавна мы вызываем CalculateSpawnInterval()и устанавливаем таймер на новое значение. Метод Calculat eSpawninterval() вычисляет новый интервал: базовый минус счёт, умноженный на множитель. Если получилось меньше минимального интервала — берём минимальный. Сохраните скрипт EnemySpawner.
Часть пятая.. Настраиваем публичные переменные в Инспекторе Вернитесь в Unity. Нажмите на объект SpawnManager в Иерархии. В Инспекторе в разделе EnemySpawner (Script) теперь есть новые поля: Base Spawn Interval, Min Spawn Interval, Interval Multiplier. Вы можете поиграть с ними прямо в Инспекторе, не залезая в код. Например, поставьте Base Spawn Interval на 3 (враги появляются реже) или на 1 (чаще). Min Spawn Interval оставьте 0.5 — чаще полсекунды не нужно, иначе игра станет невозможной. Interval Multiplier— 0.01 подойдёт, но вы можете сделать 0.02 для более быстрого усложнения. Теперь нажмите на префаб Enemy в окне Project (синий квадратик). В Инспекторе вы увидите компонент EnemyMovement (Script). Там есть поля Base Speed и Speed Multiplier. Base Speed оставьте 2. Speed Multiplier оставьте 0.05 — при ста очках скорость вырастет на 5 (станет 7), что очень быстро. Игра станет сложной.
Если хотите полегче — поставьте Speed Multiplier на 0.02 или 0.03. Часть шестая. Проверяем Запустите игру (Play). В начале игры враги появляются каждые две секунды и двигаются со скоростью 2. Лопайте шарики, набирайте очки. Чем больше очков, тем быстрее двигаются враги — вы это заметите. Они становятся всё более опасными. И тем чаще они появляются — интервал между спавнами сокращается. При пятидесяти очках интервал станет примерно полторы секунды. При ста — полсекунды (минимальный). Игра становится всё сложнее и сложнее. Вы держитесь, пока не закончатся жизни. Потом — Game Over.
Что пока не идеально Враги появляются в случайных местах, но иногда прямо на шарике. Если враг появляется прямо на шарике, он сразу же сталкивается с ним, и игрок теряет жизнь, даже не успев среагировать. Это нечестно. В следующей подглаве (3.4) мы исправим это: будем проверять, чтобы враг не появлялся слишком близко к шарику. Кроме того, нет никакого визуального эффекта при потере жизни — просто цифра уменьшается. Хорошо бы добавить анимацию или звук. И ещё: когда игра заканчивается, нет кнопки «Restart», чтобы начать заново. Нужно перезапускать игру вручную. Это мы тоже добавим. Но то, что уже есть — бесконечные враги, нарастающая скорость и частота появления — превращает нашу игру в настоящую аркадную классику. Чем дольше играешь, тем сложнее. Попробуйте набрать сто очков. Это уже вызов.
Что вы теперь знаете и умеете (чек-лист подглавы 3.3) Вы создали префаб врага. Вы превратили объект Enemy в синий префаб в окне Project и удалили его со сцены. Вы создали менеджер спавна — пустой объект SpawnManager со скриптом EnemySpawner. Он управляет появлением врагов. Вы написали код для бесконечного спавна врагов. Используя таймер, который отсчитывает интервал и создаёт нового врага через Instantiate. Вы добавили нарастающую сложность для движения врагов. Скорость врага теперь зависит от счета: чем больше очков, тем быстрее враги. Вы добавили метод GetScore() в скрипт Ball, чтобы другие скрипты могли узнать текущий счет. Вы добавили нарастающую сложность для спавна врагов. Чем больше очков, тем чаще появляются враги (но не чаще чем раз в полсекунды). Вы научились настраивать параметры сложности прямо в Инспекторе. Базовая скорость, множители,
минимальный интервал — всё это можно менять, не залезая в код. У вас есть бесконечная игра с нарастающей сложностью. Враги появляются снова и снова, становятся быстрее и чаще, а игрок пытается продержаться как можно дольше. От автора Остановитесь на минуту. Посмотрите, что вы создали. В начале этой главы была простая игрушка: шарик, который лопается, и один неподвижный враг. Теперь это полноценная аркадная игра с бесконечным геймплеем, нарастающей сложностью и системой жизней. Вы реализовали то, ради чего люди играют в аркадные игры часами — «ещё одну попытку», «побить свой рекорд», «продержаться чуть дольше». Это настоящий геймдизайн. В следующей подглаве (3.4) мы добавим последние штрихи: кнопку перезапуска, экран Game Over с красивой надписью и защиту от появления врагов прямо на шарике.
А сейчас — поиграйте в свою игру. Попробуйте набрать как можно больше очков. Увидите, как растёт сложность. Почувствуйте, как это весело — и как приятно, когда игра сделана вашими руками. Переходите к 3.4.
3.4. Экран Game Over, кнопка Restart и защита от спавна на игроке Время выполнения: 25-30 минут. Цель: добавить красивый экран проигрыша, кнопку перезапуска игры и сделать спавн врагов честным — не на игроке. Что мы сделаем в этой подглаве Сейчас, когда жизни заканчиваются, игра просто замирает. В Консоли появляется сообщение «Game Over!», но игрок его не видит. Нет никакой надписи на экране, нет кнопки «Сыграть еще раз». Нужно перезапускать игру вручную, что неудобно. Кроме того, враги иногда появляются прямо на шарике, и игрок мгновенно теряет жизнь, даже не успев моргнуть. Это нечестно. Вот что мы исправим в этой подглаве. Первое. Создадим красивую панель Game Over — с надписью, финальным счётом и кнопкой перезапуска.
Второе. Напишем код для перезапуска игры — чтобы можно было начать заново, не выходя из Unity. Третье. Добавим защиту от спавна врагов на игроке — будем проверять расстояние до шарика и, если враг появляется слишком близко, выбирать другое место. Четвёртое. Добавим небольшой звук при потере жизни (по желанию) и визуальный эффект. Это последняя подглава Главы 3. После неё у вас будет полностью готовая, полированная игра, которую можно показывать друзьям. Часть первая. Создаём панель Game Over Панель Game Over — это набор объектов интерфейса: текст «Game Over», текст с финальным счётом, кнопка «Restart». Все они будут сгруппированы внутри одного родительского объекта, который мы назовём GameOverPanel. Изначально эта панель будет скрыта, а появится только когда жизни закончатся. Начнём.
В Иерархии нажмите правой кнопкой мыши и выберите UT -> Panel. Появится серый прямоугольник, который перекроет всю сцену. Переименуйте его в GameOverPanel. Теперь нам нужно, чтобы эта панель была прозрачной, но с тёмным полупрозрачным фоном, чтобы текст на ней читался. Нажмите на GameOverPanel в Иерархии, найдите в Инспекторе раздел Image. Там есть параметр Color. Нажмите на прямоугольник цвета. Выберите чёрный цвет, а ползунок Alpha (прозрачность) поставьте на 150 (или на 0.6, если в виде десятичной дроби). Теперь фон стал тёмным и полупрозрачным. Теперь создадим заголовок «Game Over». Нажмите правой кнопкой на GameOverPanel в Иерархии (именно на панели, а не на пустом месте), выберите UI -> Text — TextMeshPro. Появится текст внутри панели. Переименуйте его в GameOverTitle. В Инспекторе найдите поле Text и напишите GAME OVER (или «Игра окончена», но для аркадного стиля лучше по-английски). Размер шрифта поставьте 48.
Выравнивание — по центру (иконка с квадратиками, выберите центр). Цвет — белый или красный. Расположите заголовок по центру. В разделе Rect Transform поставьте Pos X на 0, Pos У на 100. Текст поднимется выше середины. Теперь создадим текст для финального счёта. Нажмите правой кнопкой на GameOverPanel -> UI -> Text — TextMeshPro. Переименуйте в FinalScoreText. В поле Text напишите Score: 0. Размер шрифта — 36. Выравнивание — по центру. Pos X — 0, Pos У — 0 (чуть ниже заголовка). Теперь создадим кнопку Restart. Нажмите правой кнопкой на GameOverPanel UI - Button—TextMeshPro. Появится кнопка с текстом внутри. Переименуйте кнопку в RestartButton. Внутри кнопки есть дочерний объект Text (ТМР) — нажмите на него и измените текст на RESTART или СЫГРАТЬ СНОВА. Размер шрифта — 24. Расположите кнопку по центру, чуть ниже. Pos X — 0, Pos У —-100.
Теперь панель готова, но она видна всё время. Нам нужно, чтобы она появлялась только при Game Over. Сделаем её скрытой по умолчанию. В Иерархии нажмите на GameOverPanel. Слева от названия есть небольшой чекбокс — он показывает, активен ли объект. Снимите галочку. Панель исчезла. При запуске игры её не будет видно. Мы будем включать её из кода, когда жизни закончатся. Часть вторая. Программируем появление панели Game Over Теперь откроем скрипт Ball и изменим метод GameOver. Сейчас он выглядит так. text void GameOver() { Time.timescale = Of; Debug.Log("Game Over!"); Мы добавим в него активацию панели и отображение финального счёта.
Сначала добавим в начало скрипта (где другие переменные) ссылку на панель и на текст с финальным счётом. text public Gameobject gameOverPanel; public TextMeshProUGUI finalScoreText; Теперь изменим метод GameOver. text void GameOver() { Time.timescale - Of; finalScoreText.text = "Score: " + score; gameOverPanel.SetActive(true); Теперь, когда жизни кончаются, игра останавливается, текст финального счёта получает значение текущего счёта, и панель Game Over становится видимой. Сохраните скрипт. Вернитесь в Unity. Нажмите на шарик Ball в Иерархии. В Инспекторе в разделе Ball (Script) появились два новых поля: Game Over Panel и Final Score Text.
Перетащите в них соответствующие объемы: в Game Over Panel — объект GameOverPanel из Иерархии, в Final Score Text — объект FinalScoreText (дочерний объект панели). Готово. Часть третья. Кнопка Restart Теперь нам нужно, чтобы кнопка перезапускала игру. Нажатие на кнопку должно очистить счёт, сбросить жизни, уничтожить всех врагов, создать новый шарик и спрятать панель Game Over. Это самый сложный кусок кода в этой книге. Но мы справимся. Напишем метод ResianGame в скрипте Ball. Добавьте его внутрь класса Ball, например, после GameOver. text public void RestartGame() { Time.timescale = If; score o;
scoreText.text "Score: 0"; lives = 3; UpdateLivesText(); gameOverPanel.SetActive(false); Enemyf] allEnemies = FindObjectsOfType<Enemy>(); foreach (Enemy enemy in allEnemies) { Destroy(enemy.gameobject); } Ball currentBall = FindObjectOfType<Ball>(); if (currentBall != null && currentBall.gameobject ’ = gameobject) { Destroy(currentBall.gameobject); } float randomx = Random.Range(-3f, 3f); float randomY = Random.Range(-2f, 2f); Vectors newPosition = new Vector3(randomx, randomY, 0); Instantiate(ballPrefab, newPosition, Quaternion.identity); Destroy(gameObject); } Разберём, что здесь происходит. Time. timeScale = If;—возвращаем время в обычный режим (оно было остановлено на нуле).
score = 0; и scoreText. text = ‘'Score: 0"; — обнуляем счёт и обновляем текст. lives = 3; и UpdateLivesText ();—возвращаем три жизни и обновляем текст. gameOverPanel.SetActive(false); —прячем панель Game Over. Enemy[] allEnemies = FindObjectsOfType<Enemy>(); —находим всех врагов на сцене. FindObj ectsOfType ищет все объекты с компонентом Enemy. foreach (Enemy enemy in allEnemies)— проходим по каждому найденному врагу и уничтожаем его. Ball currentBall = FindObj ectOfType<Bal l>(); — находим текущий шарик на сцене (если он ещё не уничтожен). if (currentBall != null && currentBall.gameObject !- gameobject)— если нашелся шарик и это не наш текущий шарик (потому что наш шарик — тот, на котором висит скрипт, и он скоро уничтожится) — уничтожаем его.
float randomX и float randomY — генерируем случайную позицию для нового шарика. Instantiate(ballPrefab, newPosition, Quaternion . identity); — создаём новый шарик. Dest г оу (gameOb j ес t); —уничтожаем старый шарик (тот, на котором мы вызываем RestartGame). Важное замечание: метод RestartGame будет вызываться по нажатию на кнопку. Но кнопка находится на панели GameOverPanel, которая в момент нажатия уже активна. Нам нужно привязать этот метод к кнопке. Сохраните скрипт Ball. Часть четвёртая. Привязываем кнопку Вернитесь в Unity. Нажмите на кнопку RestartButton в Иерархии (она внутри GameOverPanel). В Инспекторе найдите раздел Button. Там есть пустое поле OnClick ()• Нажмите на плюсик (+) внизу этого раздела. Появится новый элемент.
Перетащите в это иоле объект Ball из Иерархии (наш шарик). Справа откроется выпадающий список. Выберите в нём Ball — RestartGame. Всё. Теперь при нажатии на кнопку Unity вызовет метод RestartGame на объекте Ball. Часть пятая. Защита от спавна на игроке Сейчас враги могут появиться прямо на шарике. Это нечестно. Давайте добавим проверку в скрипт EnemySpawner. Откройте скрипт EnemySpawner. Найдём метод GetRandomPosition (). Сейчас он просто возвращает случайные координаты. Мы изменим его так, чтобы он проверял расстояние до шарика. Если враг появляется слишком близко — попробуем другую позицию. Повторяем несколько раз, пока не найдем безопасное место. Вот новый метод GetRandomPosition( ). Замените старый метод этим. text
Vectors GetRandomPosition() { Transform ballTransform = null; if (ballscript != null) { ballTransform = ballscript.transform; } for (int attempts = 0; attempts < 10; attempts+ + ) { float randomX = Random,Range(-spawnRadius, spawnRadius); float randomY = Random.Range(-spawnRadius, spawnRadius); Vectors candidate = new Vector3(randomX, randomY, 0f); if (ballTransform != null) { float distance = Vector2.Distance(candidate, ballTransform.position); if (distance > 1.5f) { return candidate; } } else { return candidate; } } return Vectors.zero; } Разберём, что здесь происходит.
Transform ballTransform = null; —создаём переменную для хранения позиции шарика. if (ballscript != null)—если у нас есть ссылка на скрипт шарика, берём его Transform. for (int attempts = 0; attempts < IO; attempts++) —пробуем найти подходящую позицию максимум десять раз. Внутри цикла генерируем случайную позицию. float distance = Vector2.Distance(candidate, ballTransform. position); —вычисляем расстояние между кандидатом и шариком. if (distance > l,5f)—если расстояние больше полутора единиц (это примерно полтора размера шарика), то позиция безопасна — возвращаем её. Если за десять попыток не нашли безопасную позицию, возвращаем Vectors .zero — центр сцены. Это крайний случай, но лучше, чем враг на шарике. Сохраните скрипт EnemySpawner.
Теперь враги больше не будут появляться прямо на игроке. Часть шестая. Финальная проверка Запустите игру. Лопайте шарики, набирайте очки. Враги появляются каждые несколько секунд, становятся быстрее с ростом счёта. Когда жизни кончаются (три столкновения с врагами), игра останавливается. Появляется темная панель с надписью GAME OVER, вашим финальным счётом и кнопкой RESTART. Нажмите на кнопку. Игра перезапускается: счёт ноль, жизни три, враги исчезают, новый шарик появляется в случайном месте. Можно играть снова. Враги больше не появляются прямо на шарике — у вас есть время среагировать. Игра готова.
Бонус: добавляем звук потери жизни (ио желанию) Если хотите, чтобы при столкновении с врагом проигрывался не только звук исчезновения врага, но и отдельный звук потери жизни, сделайте следующее. Скачайте короткий звук «удар» или «ой». Импортируйте его в папку Sounds, как делали раньше. В скрипте Ball добавьте переменную: text public AudioSource damagesound; В методе OnCollisionEnter2D, внутри проверки на врага, добавьте строчку: text damagesound.Play(); В Unity добавьте на шарик второй компонент Audio Source (или используйте существующий, но тогда звуки будут накладываться). Проще создать второй Audio Source на шарике, назвать его DamageSound, привязать к нему звук потери жизни. И перетащить этот компонент в поле Damage Sound в скрипте Ball.
Теперь при каждом столкновении будет проигрываться неприятный звук. Игрок будет знать, что жизнь уменьшилась. Чти у нас получилось Давайте перечислим всё, что умеет игра сейчас. При запуске на экране шарик, счётчик очков (ноль), счётчик жизней (три). Нет врагов — они начинают появляться через две секунды. Игрок кликает по шарику. Шарик лопается со звуком, счёт увеличивается на единицу, новый шарик появляется в случайном месте. Враги появляются в случайных местах за пределами шарика каждые несколько секунд. Они движутся к шарику. Скорость врагов и частота их появления зависят от счёта. Чем больше очков, тем сложнее. Если враг касается шарика, он исчезает, жизни уменьшаются на единицу, проигрывается звук потери жизни (если добавили). Если жизни кончаются, игра
останавливается, появляется панель Game Over с финальным счётом. Игрок нажимает кнопку Restart — игра перезапускается полностью: счёт и жизни сброшены, все враги уничтожены, новый шарик создан. Это полноценная, законченная аркадная игра. Чти вы теперь знаете и умеете (чек-лист подглавы 3.4) Вы создали панель Gaine Over. С темным полупрозрачным фоном, заголовком, текстом для финального счёта и кнопкой Restart. Вы научились скрывать и показывать объекты интерфейса из кода, gameOverPanel. SetActive( true) включает панель, SetActive(false) —выключает. Вы написали метод RestartGame. Он возвращает время в обычный режим, обнуляет счёт и жизни, прячет панель Game Over, уничтожает всех врагов и старый шарик, создаёт новый шарик.
Вы привязали кнопку к методу RestartGame. Через окно Инспектора в разделе Button -> OnClick. Вы добавили защиту от славна врагов на игроке. Метод GctRandomPosition теперь проверяет расстояние до шарика и, если враг появляется слишком близко, пробует другие позиции до десяти раз. Вы научились находить все объекты определённого типа на сцене. FindObj ectsOfType<Enemy>() находит всех врагов, FindObjectOfType<Batl>() —шарик. Вы научились уничтожать все объекты в цикле, for each проходит по каждому врагу и вызывает Destroy. У вас есть полностью готовая игра. В неё можно играть, её можно показывать друзьям, она бесконечная, сложность нарастает, есть проигрыш и перезапуск. От автора Поздравляю. Вы только что прошли путь от человека, который боялся слова «Unity», до создателя полноценной аркадной игры. Это огромный шаг.
Вы написали код на С#, разобрались с физикой, столкновениями, интерфейсом, спавном объектов, нарастающей сложностью, перезапуском игры. Всё это — те же самые механики, которые используют профессиональные разработчики в больших играх. Разница только в масштабе. Теперь у вас есть фундамент. Вы можете добавлять в эту игру что угодно: новые виды врагов, бонусы, уровни, рекорды, анимации. Вы сами решаете, куда двигаться дальше. Сделайте паузу. Поиграйте в свою игру. Похвалите себя. А когда будете головы — переходите к следующим главам, где мы будем полировать игру, добавлять меню, сохранять рекорды и готовить проект к публикации. Но это уже совсем другая история. Конец Главы 3.
Глава 4. Публикация, полировка и что дальше (День седьмой) 4.1. Настройка иконки и названия игры Время выполнения: 10-15 минут. Цель: сделать игру узнаваемой — задать ей название, иконку, настроить разрешение экрана. Почему это важно Сейчас, если вы соберёте игру, у неё будет стандартная иконка Unity — серо-синий кубик. И в заголовке окна будет написано что-то вроде «MyFirstGanrie» или название вашего проекта. Это выглядит непрофессионально. Игрок, скачав вашу игру, увидит на рабочем столе серый кубик среди других файлов. Ему будет трудно её найти. А когда он запустит игру, в верхней части окна будет скучное техническое название.
Хорошая игра начинается с внимания к деталям. Своя иконка и красивое название — это первое, что видит игрок. Это создаёт впечатление законченного продукта, а не студенческой поделки. В этой подглаве мы сделаем три простые вещи. Первое. Настроим название игры, которое будет отображаться в заголовке окна и в исполнительном фай ле. Второе. Подготовим иконку для игры — квадратную картинку, которая будет видна на рабочем столе и в панели задач. Третье. Настроим разрешение экрана и масштабирование, чтобы игра выглядела хорошо на любом мониторе. Всё это делается в настройках проекта, без единой строчки кода. Часть первая. Настройки проекта Настройки проекта хранятся в специальном окне Unity. Чтобы его открыть, нажмите в верхнем меню Edit (Правка), потом Project Settings (Настройки
проекта). Или просто нажмите Ctrl + Shift + Р на Windows (Cmd + Shift + Р на Мас). Откроется большое окно с множеством разделов. Нас интересуют три раздела: Player (Плеер), Resolution and Presentation (Разрешение и представление) и Icon (Иконка). Но в версиях Unity они могут быть объединены. Сейчас разберёмся по порядку. В левой части окна Project Settings найдите раздел Player. Нажмите на него. Справа откроются настройки для разных платформ — Windows, Mac, Linux, WebGL, Android, iOS. Нас сейчас интересует Windows (или ваша операционная система). Убедитесь, что вы выбрали вкладку с иконкой монитора — это настройки для компьютера. Часть втирая. Название игры В настройках Player найдите поле Product Name (Название продукта). Сейчас там, скорее всего, написано название вашего проекта — например, «MyFirstGame» или то, что вы ввели при создании проекта.
Сотрите это и напишите красивое название для вашей игры. Например: Bubble Popper (Лопалка пузырей) Balloon Breaker (Разрушитель шариков) Pop! Pop! Pop! (Лоп! Лоп! Лоп!) Ckkr (с намёком на кликер) Или придумайте своё. Название должно быть коротким, запоминающимся и отражать суть игры — нужно лопать шарики и уворачиваться от врагов. Чуть ниже есть поле Company Name (Название компании). Можете написать там своё имя или псевдоним, например, Nick GameDev Productions. Или оставить пустым — это необязательно. Теперь найдите поле Version (Версия). Там стоит «0.1» или «1.0». Оставьте 1.0 — это первая версия вашей игры.
Часть третья. Настройка разрешения экрана Теперь в тех же настройках Player найдите раздел Resolution and Presentation (Разрешение и представление). Возможно, для этого нужно раскрыть вкладку с плюсиком или просто прокрутить страницу вниз. В этом разделе есть параметр Default Is Full Screen (По умолчанию — полноэкранный режим). Снимите эту галочку. Наша игра небольшая, и полноэкранный режим будет выглядеть странно — шарик будет слишком маленьким, а враги — растянутыми. Лучше, чтобы игра запускалась в окне. Ниже найдите Default Screen Width (Ширина окна по умолчанию) и Default Screen Height (Высота окна по умолчанию). Поставьте ширину 1024 и высоту 768. Это стандартное квадратное окно, которое поместится на любом мониторе. Ещё ниже есть параметр Resizable Window (Окно можно изменять). Оставьте галочку — пусть игрок может растянуть окно, если захочет. Теперь найдите параметр Supported Aspect Ratios (Поддерживаемые соотношения сторон). Снимите все галочки, кроме 16:10 и 16:9. Это самые распространённые пропорции экранов.
Часть четвёртая. Иконка игры Иконка — это квадратная картинка, которая будет отображаться как значок вашего . ехе-файла на рабочем столе и в панели задач. Вам нужна картинка в формате PNG, квадратная, с разрешением хотя бы 256*256 пикселей. Лучше — 512*512. Что на ней нарисовать? Что-то связанное с игрой: шарик, лопающийся пузырь, или просто букву Р. Не нужно ничего сложного — простая, яркая иконка запоминается лучше. Если у вас нет навыков рисования, вот что можно сделать. Вариант первый. Откройте любой бесплатный онлайн- редактор, например Photopea (прямо в браузере). Создайте квадратное полотно. Нарисуйте яркий круг (инструмент «Эллипс»), залейте красным цветом, добавьте блик белым пятном. Сохраните как PNG. Вариант второй. Скачайте бесплатную иконку с сайта типа Haiicon.coin или icons8.com . Только проверьте лицензию — для личного использования обычно можно, для коммерческого — нужно указывать автора.
Вариант третий. Используйте эмодзи. Да, серьёзно. Откройте любой текстовый редактор, найдите эмодзи шарика или , сделайте скриншот, обрежьте. Получится пиксельно, но для учебной игры сойдёт. Сохраните иконку где-нибудь, где вы ее найдёте. Лучше всего — прямо в папке вашего проекта Unity, например, Assets/Icon/icon. png. Теперь вернитесь в Unity. В окне Project найдите свою иконку (она появилась в папке Assets, куда вы её сохранили). Нажмите на неё. В Инспекторе убедитесь, что Texture Туре стоит Sprite (2D and UI). Если нет — выберите это из выпадающего списка. Теперь в настройках Player (всё в том же окне Project Settings) найдите поле Default Icon (Иконка по умолчанию). Нажмите на маленький кружок справа от поля. Откроется окно выбора. Найдите в нём вашу иконку (вы можете ввести её имя в поиск) и нажмите на неё. Иконка назначена. Ниже есть поля для иконок разных размеров (128x128, 64x64, 32x32). Unity автоматически создаст их из вашей большой иконки, но если хотите, можете загрузить отдельные картинки для каждого размера. Не обязательно.
Часть пятая. Дополнительные настройки (по желанию) В настройках Player есть ещё несколько интересных параметров. Cursor Hotspot — точка, в которой находится «носик» курсора. Обычно не трогают. Run In Background — если поставить галочку, игра будет продолжать работать, даже когда окно не активно. Нашей игре это не нужно — оставьте пустым. Visible In Background — если игрок переключится на другое окно, наша игра должна остановиться? Лучше остановить, чтобы враги не убивали шарик за спиной. Оставьте пустым. В разделе Splash Image (Заставка) есть настройка Show Unity Splash Screen (Показывать заставку Unity). Снимите галочку, если не хотите, чтобы при запуске игры мелькал логотип Unity. В бесплатной версии вы всё равно не можете его полностью убрать, но хотя бы уменьшите время показа.
Всё. Настройки завершены. Нажмите на крестик в правом верхнем углу окна Project Settings, чтобы закрыть его. Что вы теперь знаете и умеете (чек-лист подглавы 4.1) Вы знаете, где находятся настройки проекта. Edit Project Settings -> Player. Вы изменили название игры. В поле Product Name написали красивое, запоминающееся имя — Bubble Popper, Pop Master или любое другое. Вы настроили разрешение экрана. Убрали полноэкранный режим, поставили ширину 1024 и высоту 768, оставили возможность изменять размер окна. Вы подготовили иконку для игры. Нарисовали или скачали квадратную картинку, сохранили в папке проекта. Вы назначили иконку в настройках Player. Через поле Default Icon загрузили свою картинку. Вы знаете, какие дополнительные настройки можно изменить. Заставку Unity, поведение игры на заднем плане и другие.
От автора Теперь ваша игра стала выглядеть как настоящий продукт. У нее есть имя, красивая иконка и удобное окно. Это мелочи, но именно из таких мелочей складывается впечатление. В следующей подглаве (4.2) мы научимся собирать игру — превращать её в . ехе-файл для Windows и в веб-версию для браузера. Вы сможете отправить игру другу, и он запустит её без Unity. А пока — сохраните проект. Ctrl + S никогда не помешает. Переходите к 4.2.
4.2. Сборка игры для Windows и WebGL * Время выполнения: 10-15 минут. Цель: собрать игру в исполняемый файл (.ехе) для Windows и в веб-версию для браузера.* Что такое сборка и зачем она нужна Всё, что вы делали до этого, существовало только внутри Unity Editor. Вы нажимали кнопку Play, игра работала, но только пока открыт редактор. Закройте Unity — и игра исчезнет. Сборка (Build) — это процесс, который превращает ваш проект в самостоятельную программу. Unity берёт все ваши сцены, скрипты, картинки, звуки и упаковывает их в один или несколько файлов, которые можно запустить на любом компьютере (даже без установленного Unity). Мы сделаем две сборки. Первая — для Windows. Это будет папка с файлом . ехе. Вы скопируете эту папку на флешку, отправите другу в архиве, и он сможет запустить игру двойным щелчком.
Вторая — для WebGL. Это будет набор файлов, которые можно выложить на любой хостинг или на платформу itch.io . Друг откроет ссылку в браузере и начнет играть, даже ничего не скачивая. Это самый удобный способ поделиться игрой. Начнём. Часть первая. Подготовка к сборке Прежде чем собирать игру, нужно убедиться, что все ваши сцены сохранены и добавлены в список сборки. Откройте окно Build Settings. Нажмите в верхнем меню File Build Settings. Или нажмите Ctrl + Shift + В на Windows (Cmd + Shift + В на Mac). Перед вами откроется окно Build Settings. В верхней части есть список Scenes In Build (Сцены в сборке). Сейчас там, скорее всего, пусто или одна сцена с пометкой «Scenes/SampleScene». Нам нужно добавить нашу сцену. Убедитесь, что ваша главная сцена (та, где игра) открыта и сохранена. Нажмите Ctrl + S, чтобы сохранить её в последний раз.
Теперь в окне Build Settings нажмите кнопку Add Open Scenes. Текущая открытая сцена добавится в список. Справа от её названия появится номер — «О». Это значит, что игра будет начинаться именно с этой сцены. Если в списке есть другие сцены (например, старая Samp!eScene), выделите их и нажмите на минус справа, чтобы удалить. Оставьте только вашу сцену. Теперь внизу окна обратите внимание на кнопку Player Settings — это те самые настройки, которые мы меняли в прошлой подглаве. Если захотите что-то поправить (название, иконку), нажмите туда. Всё готово. Теперь выберем платформу для сборки. Часть вторая. Сборка для Windows В левом нижнем углу окна Build Settings есть список платформ. Найдите PC, Мас & Linux Standalone. Нажмите на него. Справа появится кнопка Switch Platform (Сменить платформу). Нажмите на неё. Unity переключит проект на сборку для компьютеров. Это может занять минуту-другую — Unity перекомпилирует
некоторые файлы. В правом нижнем углу будет полоска прогресса. Подождите. После того как платформа переключена, обратите внимание на выпадающий список Target Platform (Целевая платформа) — он появился чуть выше списка платформ. Выберите Windows. Чуть ниже есть список Architecture (Архитектура). Оставьте х86_64 — это стандартная 64-битная версия Windows, которая работает на всех современных компьютерах. Теперь нажмите большую кнопку Build. Unity попросит вас выбрать папку, куда сохранить сборку. Создайте новую папку на рабочем столе или в любом удобном месте и назовите её Build_Windows. Нажмите Выбрать папку (Select Folder). Unity начнёт сборку. Это займёт одну-две минуты. Когда процесс завершится, Unity откроет папку со сборкой. Внутри вы увидите: Файл с названием вашей игры и расширением . ехе — это исполняемый файл. Дважды кликните на нём — игра запустится.
Панка с названием игры и приставкой _Data — там лежат все ресурсы: картинки, звуки, скрипты в скомпилированном виде. Не удаляйте эту папку и не перемещайте её отдельно от . ехе. Без неё игра не запустится. Два файла .dll (иногда) — библиотеки Unity. Тоже нужны. Чтобы отправить игру другу, запакуйте всю папку (включая . ехе и папку _Data) в ZIP-архив. Друг распакует архив и запустит . ехе. Всё. Никакой Unity ему не нужен. Поздравляю. Вы только что создали настоящую компьютерную игру. Часть третья. Сборка для WebGL Веб-версия — это игра, которая работает в браузере. Друг переходит по ссылке и сразу начинает играть, ничего не скачивая и не устанавливая. Это самый простой способ поделиться своим творением. Вернитесь в окно Build Settings. Если вы его закрыли, откройте снова: File — Build Settings.
В левом списке платформ найдите WebGL. Нажмите на него. Нажмите кнопку Switch Platform. Unity снова переключит проект — это ещё минута ожидания. После переключения в правой части окна появятся настройки WebGL. Нас интересует только одна: Compression Format (Формат сжатия). Там обычно стоит Gzip. Оставьте как есть. Теперь нажмите кнопку Build. Unity попросит выбрать папку для сборки. Создайте новую папку, например, Buiid_WebGL. Нажмите «Выбрать папку». Unity соберёт игру. Это займёт немного больше времени, чем сборка для Windows, потому что движок транслирует ваш код в JavaScript. Когда сборка завершится, Unity откроет папку. Внутри вы увидите несколько файлов. index.html — это главная страница. Дважды кликните на ней. Откроется браузер и запустится ваша игра. Если игра не запускается (чёрный экран или ошибка), не пугайтесь. Веб-версии Unity не всегда работают локально — браузеры блокируют некоторые файлы из соображений
безопасности. Но когда вы выложите эти файлы на хостинг, всё заработает. Чтобы поделиться игрой, вам нужно выложить ВСЕ файлы из папки Build—WebGL на любой веб-хостинг. Самый простой и бесплатный способ — itch.io . Об этом мы поговорим в следующей подглаве. А пока просто знайте: ваша игра работает в браузере. Часть четвёртая. Возвращаемся в редактор Вы закончили со сборкой. Теперь можно вернуться в обычный режим работы — разработку в редакторе. Unity, скорее всего, осталась в режиме WebGL (об этом говорит синяя плашка с надписью WebGL в правом нижнем углу экрана). Это не страшно, но лучше вернуть проект в режим Windows, чтобы снова можно было нажимать Play в редакторе. Откройте Build Settings снова. В списке платформ нажмите PC, Мас & Linux Standalone, затем Switch Platform. Подождите минуту. Готово. Теперь плашка говорит «Windows».
Что вы теперь знаете и умеете (чек-лист подглавы 4.2) Вы знаете, как открыть окно Build Settings. File -> Build Settings, или Ctrl+Shift+B. Вы научились добавлять сцены в сборку. Кнопка Add Open Scenes добавляет текущую открытую сцену. Вы собрали игру для Windows. Файл .ехе и папка с данными. Игра запускается на любом компьютере без Unity. Вы знаете, что папку _Data нельзя отделять от .ехе. Без неё игра не работает. Вы собрали игру для WebGL. Набор файлов, который работает в браузере, index.html — входная точка. Вы умеете переключать платформы в Build Settings. Windows -> WebGL -> обратно в Windows. У вас есть готовая игра в двух форматах, .ехе для компьютера и веб-версия для публикации в интернете.
От автора Поздравляю ещё раз. Сборка игры — это как упаковка подарка. Вы создали нечто ценное, и теперь можете передать это другим людям. Ваша игра перестала быть просто файлами на вашем компьютере — она стала продуктом. В следующей подглаве (4.3) мы выложим игру на itch.io — самую популярную платформу для инди- разработчиков. Вы получите ссылку, которую можно отправить другу, и он сыграет в вашу игру в браузере, даже не скачивая её. А пока — запустите собранный .ехе файл. Увидеть свою игру в отдельном окне, без интерфейса Unity — это особое чувство. Гордитесь собой. Переходите к 4.3.
4.3. Публикация на itch.io и финальная проверка Время выполнения: 15-20 минут. Цель: выложить игру на itch.io , получить рабочую ссылку и убедиться, что всё работает. Почему именно itch.io Есть много способов поделиться игрой. Можно отправить другу ZIP-архив с . ехе-файлом. Можно загрузить игру на Google Диск и дать ссылку на скачивание. Но есть платформа, которая создана специально для инди- разработчиков— itch.io . Вот почему itch.io — лучший выбор. Первое. Это бесплатно. Вы можете загрузить сколько угодно игр, и вам ничего не будет стоить. Второе. Игра запускается прямо в браузере. Друг переходит по ссылке и сразу начинает играть — ничего не скачивает, не устанавливает, не настраивает.
Третье. Там большое сообщество. Люди заходят на itch.io , ищут новые игры, оставляют комментарии. Вашу игру могут найти совершенно незнакомые люди — это очень вдохновляет. Четвёртое. Это просто. Процесс публикации занимает пять минут. В этой подглаве мы пройдём весь путь: зарегистрируемся на itch.io , загрузим нашу веб-сборку, настроим страницу игры и получим ссылку, которой можно делиться. Часть первая. Регистрация на itch.io Откройте браузер и перейдите на сайт https://itch.io . В правом верхнем углу нажмите кнопку Sign up (Зарегистрироваться). Вас попросят придумать имя пользователя, указать электронную почту и пароль. Имя пользователя — это то, как вас будут видеть другие. Можете использовать свой псевдоним Nick GameDev или что-то более личное.
После регистрации на указанную почту придёт письмо с подтверждением. Перейдите по ссылке в письме — и ваш аккаунт активирован. Теперь вы можете загружать игры. Часть вторая. Подготовка веб-сборки к загрузке Перед загрузкой нужно упаковать файлы игры в ZIP-архив. Это стандартный формат для публикации на itch.io . Найдите папку, в которую вы собирали WebGL-версию в прошлой подглаве. Назовём её Bu ild_ WebGL. Внутри этой папки лежат несколько файлов: index, html, файл с расширением . wasm (или . mem), файл с расширением . data, файл с расширением . j S, и, возможно, другие. Теперь сделайте следующее. На Windows: нажмите правой кнопкой мыши на папке Build_WebGL (или выделите все файлы внутри неё), выберите Отправить -> Сжатая ZIP папка. На Мас: нажмите правой кнопкой на папку и выберите Сжать.
В результате у вас появится файл Build—WebGL .zip. Это архив, который мы загрузим на itch.io . Часть третья. Создание новой игры на itch.io Войдите в свой аккаунт на itch.io . В правом верхнем углу нажмите на своё имя, затем выберите Dashboard (Панель управления). На странице Dashboard найдите кнопку Create new project (Создать новый проект). Откроется страница с множеством полей. Не пугайтесь — большинство из них необязательные. Заполним только самое важное. Поле Title (Название). Напишите название вашей игры — то же, что вы указывали в настройках Player. Например, Bubble Popper или Pop! Pop! Pop!. Поле Tagline (Краткое описание). Это короткая фраза, которая появляется под названием. Например: «Лопай шарики, уворачивайся от врагов и набирай очки» .
Поле Kind of project (Тип проекта). Из выпадающего списка выберите HTML,. Это значит, что игра будет запускаться в браузере . Раздел Pricing (Цена). Если вы не планируете зарабатывать на игре (а скорее всего, нет), выберите SO or donate — игра бесплатная, но игроки могут вас поблагодарить донатом . Раздел Uploads (Загрузки). Это самое важное. Нажмите кнопку Upload files. Выберите ZIP- архив BuilcLWebGL. zip, который вы создали. Когда файл загрузится, ниже появится галочка This file will be played in the browser (Этот файл будет запускаться в браузере). Обязательно поставьте эту галочку . Раздел Embed Options (Настройки встраивания). Здесь выберите Auto Detect Size (Автоматически определить размер). Не включайте полноэкранный режим от itch.io , потому что у Unity свой собственный . Раздел Screenshots (Скриншоты). Загрузите 2-3 скриншота вашей игры. Это могут быть снимки экрана во время игры. Нажмите кнопку и выберите картинки на компьютере.
Раздел Visibility & access (Видимость). Сейчас лучше оставить Draft (Черновик). Это значит, что страница игры существует, но её никто не видит, кроме вас. Вы сможете проверить, как всё работает, и только потом сделать игру публичной . В самом низу страницы нажмите кнопку Save (Сохранить). Часть четвёртая. Проверка игры После сохранения вы попадёте на страницу управления проектом. В верхней части есть ссылка View page — нажмите на неё . Откроется страница вашей игры. Вы увидите название, описание, скриншоты — и поле, где должна быть сама игра. Подождите несколько секунд. Игра загружается. Когда загрузка завершится, вы увидите ваш шарик, фон и надписи «Score: 0» и «Lives: 3». Проверьте, что всё работает. Кликается ли шарик? Счёт увеличивается?
Двигается ли враг? Появляется через несколько секунд? Отнимаются ли жизни? Когда враг касается шарика, жизни уменьшаются? Появляется ли экран Gaine Over? Когда жизни кончаются, появляется тёмная панель с надписью и кнопкой Restart? Работает ли кнопка Restart? Нажмите — игра перезапускается? Если всё работает — поздравляю. Ваша игра в интернете. Если что-то не работает, не расстраивайтесь. Вернитесь в Unity, проверьте настройки сборки, соберите заново, замените файл на itch.io (это можно сделать в любой момент, загрузив новую версию в раздел Uploads). Часть пятая. Публикация игры Когда вы убедились, что всё работает, можно сделать игру видимой для всех.
Вернитесь в панель управления проектом (нажмите на своё имя — Dashboard, затем найдите свой проект в списке). Найдите раздел Visibility & access. Измените значение с Draft на Public (Публичная). Или, если хотите, чтобы игра была видна только по прямой ссылке, выберите Restricted и добавьте ссылку в описание. Нажмите Save. Всё. Теперь ваша игра доступна всем. Ссылка на неё будет выглядеть примерно так: https://nickgamedev.itch.io/bubbte-popper Можете отправить эту ссылку другу. Или опубликовать в соцсетях. Или просто сохранить для себя — как напоминание о том, что вы создали нечто настоящее. Бонус: дополнительные настройки для itch.io Если вы захотите сделать страницу игры ещё красивее, вот что можно добавить.
Изменение темы. На странице игры (в режиме просмотра) в правом верхнем углу есть кнопка Edit theme. Там можно изменить цвета, шрифты, фон страницы . Несколько версий игры. Вы можете загрузить не только веб-версию, но и сборку для Windows. В разделе Uploads загрузите ZIP-архив с . ехе-файлом и укажите, что это версия для Windows. Тогда на странице появятся две кнопки: «Play in browser» и «Download for Windows» . Категории и теги. В разделе Metadata (Метаданные) можно добавить теги — например, «arcade», «clicker», «casual». Это поможет людям находить вашу игру через поиск. Что вы теперь знаете и умеете (чек-лист подглавы 4.3) Вы зарегистрировались на itch.io . Создали аккаунт, подтвердили почту, вошли в панель управления. Вы подготовили веб-сборку к загрузке. Заархивировали лапку Build_WebGL в ZIP-файл.
Вы создали страницу игры на itch.io . Заполнили название, описание, тип проекта, загрузили архив, поставили галочку «This file will be played in the browser». Вы проверили игру в браузере. Перешли по ссылке View page, убедились, что игра запускается и работает корректно. Вы опубликовали игру. Сменили видимость с Draft на Public. У вас есть ссылка на вашу игру в интернете. Ею можно делиться с кем угодно. Что делать, если игра не работает на itch.io Иногда веб-сборка работает локально (когда вы открываете index.html на компьютере), но не работает после загрузки на itch.io . Вот самые частые проблемы и их решения. Чёрный экран вместо игры. Это может быть связано с настройками сжатия. Вернитесь в Unity, откройте Project Settings -> Player -» WebGL Publishing Settings. Найдите параметр Compression Format. Если стоит Broth,
попробуйте сменить на Gzip — это более универсальный формат . Если стоит Gzip, попробуйте Disabled (но тогда игра будет загружаться дольше). После смены настройки соберите WebGL заново и замените файл на itch.io . Игра загружается слишком долго. Это нормально для первого запуска — браузер скачивает все файлы игры. При повторных запусках будет быстрее, потому что файлы сохранятся в кеше . Не работают клики по шарику. Убедитесь, что в настройках сборки не включён Development Build — он может вызывать странное поведение . На телефоне всё мелкое или не работает. WebGL-игры на телефонах работают, но интерфейс может быть не рассчитан на маленький экран. Это тема для отдельной книги — адаптация под мобильные устройства. Пока считайте, что ваша игра для компьютера с мышкой. Финальная проверка всей игры Прежде чем окончательно закрыть книгу, давайте проверим, что вы создали полноценный, законченный продукт.
Запускается ли игра в редакторе Unity? Нажмите Play. Всё работает. Собирается ли игра в .ехе? Вы можете запустить её на своём компьютере без Unity. Собирается ли игра в WebGL? Вы можете открыть index . html в браузере. Выложена ли игра на itch.io ? Друзья могут перейти по ссылке и поиграть. Есть ли у игры название и иконка? В собранной версии и на странице itch.io она выглядит как настоящий продукт. Понятно ли, как играть? При первом запуске игрок догадается, что нужно кликать по шарику? Если нет — добавьте короткую подсказку на сцену. Если на все вопросы вы ответили «да» — поздравляю. Вы сделали это.
От автора Мы прошли долгий путь. От человека, который боялся слова «Unity» и никогда не писал код, до создателя игры, которая живёт в интернете и доступна миллионам людей. Вы научились устанавливать Unity, ориентироваться в интерфейсе, писать скрипты на С#, создавать объекты, обрабатывать клики, работать со счётом и звуком, создавать врагов, настраивать движение и столкновения, добавлять жизни и экран проигрыша, делать бесконечный спавн с нарастающей сложностью, настраивать иконку и название, собирать игру для Windows и WebGL, публиковать на itch.io . Это огромный объём знаний и навыков. И всё это за одну книгу. Но главное, чему вы научились — это не бояться. Код больше не кажется магией. Unity не кажется монстром. Вы знаете, что любую задачу можно разбить на маленькие шаги и решить. И теперь вы можете двигаться дальше — в одиночку. Добавлять новые механики, улучшать графику, писать музыку, создавать целые миры.
Это только начало. Добро пожаловать в геймдев. Конец книги. Спасибо, что были со мной. Nick Game Dev Нет, постойте. А эпилог? Впрочем, кто читает эпилоги. Хотя... В общем, напишу, так и быть. Кто-то может сказать: «да что там должно быть путного в эпилоге, ведь все знания — в главах. Так-то оно так, но напишу-ка я мотивирующий эпилог. Ведь в главах в основном знания, а гут — чистая мотивация, которая может вас подтолкнуть, дать, так сказать, волшебный пинок, после чего вы сами удивитесь тому, как сдвинулись с места и оказались на пути успеха.
Эпилог Знаете, в чём разница между человеком, который мечтает делать игры, и человеком, который их действительно делает? Первый ждёт идеального момента. «Вот выучу английский — тогда начну. Вот куплю мощный компьютер — тогда точно. Вот найдётся свободная неделя — и я сделаю ту самую игру». Второй просто открывает Unity в среду вечером, после работы, когда глаза слипаются. Добавляет квадратик на экран. Пишет три строчки кода. Шарик лопается от клика. В этот момент что-то щёлкает в голове. И обратной дороги нет. Вы — теперь второй. Вы сделали не просто игру. Вы прошли путь, который большинство даже не начинают. Вы установили программу, разобрались в панелях, написали код, нашли ошибку в консоли, победили её. Вы увидели, как ваше творение оживает, как враги преследуют шарик, как счёт растёт, как приходит Game Over — и как хочется нажать Restart и попробовать ещё раз.
Вот это чувство — «ещё одну попытку» — и есть магия геймдева. Что дальше? Вы можете остановиться здесь. Это нормально. Вы получили опыт, поняли, как устроены игры изнутри, и теперь по-другому смо трите на любой кликер или аркаду. Вы вооружены. Но если вы хотите идти дальше — вот несколько идей. Добавьте новые виды врагов. Например, быстрого и медленного. Или врага, который движется не по прямой, а волнами. Или врага, который взрывается при столкновении. Каждый новый враг — это новый вызов для игрока. Добавьте бонусы. Например, если игрок лопает три шарика подряд — время замедляется на три секунды. Или появляется щит, который защищает от одного столкновения. Или шарик временно становится неуязвимым. Бонусы делают игру глубже. Добавьте рекорды. Запоминайте самый высокий счёт, который набрал игрок за всё время. При Game Over
показывайте не только текущий счёт, но и «Рекорд: X». Это даёт игроку цель — побить свой прошлый результат. Добавьте главное меню. Экран с кнопками «Новая игра», «Рекорды», «Выход». Это отдельный большой кусок работы, но он превращает игру из «просто игры» в «настоящий продукт». Улучшите графику и звук. Бесплатные картинки и звуки из интернета — это хорошо для старта. Но вы можете нарисовать свои спрайты — даже в Paint. Или заказать художнику на фрилансе за пять долларов. Или найти красивые бесплатные наборы на itch.io . Добавьте уровни. Первый уровень — один медленный враг. Второй — два врага быстрее. Десятый — пять врагов и молнии с неба. Игрок должен не просто держаться бесконечно, а проходить конкретные испытания. Изучите новые темы. Анимации, частицы (взрывы, искры), работа с камерой (тряска при столкновении), сохранение данных (чтобы рекорд не сбрасывался при перезапуске), звуковое сопровождение (фоновая музыка, смена треков). Мир геймдева огромен. Вы только заглянули в прихожую.
Я не знаю, станете ли вы профессиональным разработчиком. Может быть, напишете игру, которая попадёт в Steam. Может быть, сделаете приложение для телефона и проснётесь знаменитым. А может быть, геймдев останется хобби — тем, чем вы занимаетесь для души вечерами после работы. Любой из этих вариантов правильный. Потому что вы уже сделали главное. Вы перестали быть тем, кто только думает. Вы стали тем, кто делает. Это была моя первая книга. И если честно, я волновался. Я боялся, что будет слишком сложно. Или слишком скучно. Или что я пропущу какую-то важную деталь, и у вас ничего не заработает, и вы бросите книгу на двадцатой странице. Но вы дочитали до конца. Вы сделали игру. Мы сделали это вместе. Спасибо вам. Серьёзно. А теперь идите и творите. Мир ждёт ваши игры. Ваш Nick GameDev