Основы гейм-дизайна
Гейм-дизайн — процесс создания игрового контента и правил. Хороший гейм-дизайн — процесс создания целей, которые игрок захочет достигнуть, и правил, которым игрок будет следовать в процессе принятия значимых решений на пути к достижению этих целей.
Хороший гейм-дизайн акцентирован на игроке. Это значит, что превыше всего остального в расчет берется игрок и его желания. Вместо того, чтобы направлять действия игрока посредством правил, хороший гейм-дизайн мотивирует игрока двигаться в определенном дизайнером направлении. Поставить перед игроками задачу добраться до противоположного края игрового поля или повысить свой уровень — лишь часть задачи. Если у них не будет причины или желания к этому действию, игра станет пыткой.
В процессе создания игры дизайнеры пытаются увидеть проект глазами игрока:
1. О чем эта игра?
2. Как я играю?
3. Как я побеждаю?
4. Почему я хочу играть?
5. Что мне нужно делать в игре?
6. Значимый выбор?
Гейм-дизайн — процесс создания для игрока возможностей сделать значимый выбор, который повлияет на исход игры. Игры типа тетриса и шахмат занимают ваш разум, заставляя просчитывать следующие возможные шаги. Мы знаем, что, совершая их, можем как продолжить игру, так и проиграть с разгромом. Игры типа Sims или серии Sid Meyer's Civilization заставляют игрока принимать десятки решений в минуту. Лишь малая часть этих решений прямолинейна по типу «Пойти на восток или на запад?», но каждое сколь угодно малое решение влияет на игровой процесс.
Игры — лишь набор значимых решений. Вспомните последнюю игру, в которую вы играли и проиграли. Вы можете предельно точно назвать тот момент, когда что-то пошло не так. Некоторые решения или серии решений в результате привели к вашему проигрышу.
Тем не менее, иногда у игрока нет никакого выбора. Вспомните «Монополию». После того, как вся собственность скуплена, какой выбор остается у игрока, помимо «кидать игральные кости и ходить»?
Чем гейм-дизайн не является
Термин гейм-дизайн зачастую используется в неверном значении. Кто-то, кто стремится учиться гейм-дизайну, в результате изучает игровой арт. Другие — чистое программирование. В то время, как и программирование, и арт являются важными направлениями работы и вдвойне важными для цифровых игр, гейм-дизайн является самодостаточным видом искусства.
Типы дизайна
Есть много типов игр, и точно так же есть много типов гейм-дизайна. Вот основные из них:
1. Дизайн мира — создание общей истории, сеттинга и темы игры. Хотя эти задачи в основном решаются ведущим или единственным дизайнером, они зачастую определяют масштаб задач, перечисленных ниже.
2. Системный дизайн — создание правил и сопутствующих расчетов для игры. Это — единственная задача из области гейм-дизайна, актуальная для любой игры, потому что правила есть у всех игр. Поэтому большая часть заданий в этой книге затрагивает системный дизайн.
3. Контент-дизайн — создание персонажей, предметов, загадок и миссий. Хотя он и более распространен в видеоиграх, ролевые и коллекционные карточные игры также задействуют значительное количество контента.
4. Игровые тексты — это написание внутриигровых диалогов, текстов и историй.
5. Дизайн уровней — создание уровней игры, включающей ландшафт карты и расположение на этой карте объектов. Хотя дизайн уровней и является широко распространенным — мастера в настольных ролевых играх составляют карты подземелий начиная с 1970-х годов — говоря «дизайнер уровней», чаще всего имеют в виду дизайнера уровней для видеоигры.
6. Дизайн интерфейсов (UI) — состоит из двух элементов: как игрок взаимодействует с игрой и как игрок получает информацию и реакцию на свои действия от игры. В играх любого типа есть UI, даже в нецифровых. Поля для настольных игр проектируются так, чтобы помещаться на среднестатистический стол, а карты — чтобы помещаться в руку среднего размера. Игровые компоненты должны содержать информацию, легкую для понимая, использования и интерпретации игроком.
Что такое игра?
Есть множество определений слова «игра», ни одно из которых не является общепризнанным в смысле определения границ гейм-дизайна. Одно из определений: «В разной степени осознаваемый человеком как субъектом активности, самодеятельности и творчества (развития в целом) или даже инстинктивный способ получения и развития навыков людьми и животными в момент отсутствия непосредственной угрозы для жизни и развития способностей».
Большая часть игр имеет цель, хотя и есть исключения (The Sims или Sim City). Большая часть игр имеет определенные начало и конец, но есть и исключения (к примеру, World of Warcraft и Dungeon & Dragons). Большая часть игр требует от игроков принятия решений, но есть и исключения (к примеру, Candy Land и Chutes and Ladders). Видеоигра — это игра (в соответствии с определением выше), различным образом использующая цифровой видеоэкран того или иного вида.
Модель МДЭ
Механика
Управляемый механикой гейм-дизайн является более всеобщим, чем может показаться. Рассмотрим классическую игру Super Mario Bros. Mario прыгает через разные предметы, на предметы и в предметы. Сила этой игры состоит в чистой силе именно этой механики — и почти все игры в этом жанре следовали принципу этой игры с давних времен.
Другие, более новые игры, как, например, из серии игр Katamari Damacy, применяют механику, в которой липкий мячик катается по чему-либо и собирает это. Опять-таки, аналогичная механика применяется снова и снова с большим эффектом. Возможно, в наибольшей степени управляемые механикой игры — это игры, в которых даже в названии жанра есть механика: шутеры от первого лица. Механика стрельбы из пушки, из палочки или чего-либо еще, очевидно, никогда не устареет. Даже Mario может стрелять.
Динамика или «ядро» игры
«Ядро» или базовая динамика игры — та единственная вещь, вокруг которой построен игровой процесс — то самое ощущение от игры, которое дизайнер хочет вызвать.
Ядро чаще всего связано с базовой механикой, будь то убийство противников, переворачивание карточек на своем ходу или продажа юнитов другим игрокам. Эта базовая механика, в свою очередь, ведет к базовой динамике — краткому алгоритму игрового процесса. В игровой индустрии, говоря «ядро», чаще всего имеют в виду именно базовую динамику.
Базовые динамики
1. Захват территории: это ядро характерно ограниченным ресурсом, который вполне может исчезнуть. Также реализуется через контроль части территории (к примеру, в FPS). Игры наподобие Risk, Carcassonne и многие пошаговые стратегии используют именно эту базовую механику.
2. Предсказание: Великое множество игр основано на необходимости сделать нужное действие или оказаться в нужном месте в нужное время. Чаще всего это — детские игры, но множество игр для вечеринок также используют эту базовую динамику.
3. Пространственное мышление: Реализованные в качестве видеоигр игры-загадки зачастую задействуют навыки пространственного мышления. Игры наподобие Tetris заставляют игрока думать не только о той фигуре, что доступна ему в данный момент, но и об уже установленных фигурах, и о тех фигурах, которые ну очень бы хотелось получить прямо сейчас, чтобы не проиграть.
4. Выживание: Люди самим естеством стремятся к выживанию и благополучию, и в игровом пространстве этот принцип не перестает действовать. Мы будем защищать сами себя на голых инстинктах еще до того, как нам объяснят цель игры. Выживание — базовая динамика многих игр. Тем не менее важно не путать базовую механику с условиями проигрыша в игре.
5. Разрушение: противоположность динамике «выживание», или даже компаньон, если речь идет о посвященной противоборству игроков игре (PVP), динамика «уничтожь-все-что-увидишь». Каждый FPS делает акцент на этой базовой механике, но не менее часто она встречается и в настольных, и в карточных играх на военную тематику, вроде Nuclear War, Plague and Pestilience и Car Wars.
6. Созидание: не менее сильно, чем стремление к выживанию, в людях проявляется стремление к созиданию, даже тогда, когда это не ставится целью процесса.
7. Собирательство: Мы — люди, и сопоставление — один из наших естественных навыков. Мы — люди, и сопоставление — один из наших естественных навыков. Вы только что заметили, что два этих предложения одинаковы и неосознанно сопоставили их. Это в природе людей. Мы инстинктивно сопоставляем похожие объекты.
8. Погоня или бегство: в древности людям приходилось много бегать как для того, чтобы поймать добычу, так и для того, чтобы спастись от хищников. Неудивительно, что эта базовая механика лежит в основе множества игр. Она превалирует в контактном спорте и видеоиграх типа Pac-Man и настольных играх типа Scotland Yard.
9. Торговля: не каждая игра обязательно должна быть соревновательной. Во многих играх игроки сотрудничают друг с другом (даже тогда, когда являются оппонентами). В тех играх, где присутствует несколько видов ресурсов, принадлежащих разным игрокам, взаимодействие и торговля между этими игроками — обыденное дело. Торговля — основная динамика множества нецифровых игр, таких как Pit и Settlers of Catan.
10. Гонка до победного: Первым преодолеть улицу, пересечь финишную черту, изобрести конкретную технологию — всё это распространенные вариации игрового процесса с использованием базовой динамики «гонка до победного».
Определяя основные фичи для конкретного ядра, дизайнеры стараются увязать каждую фичу с базовой динамикой (или набором динамик) таким образом, чтобы сделать игру лучше.
Откуда черпать вдохновение
Всё — вообще всё — может быть превращено в игру. От выращивания бобов до выпаса овец и вязания — геймдизайнер может превратить в игру что угодно. Тем не менее каждый профессиональный геймдизайнер постоянно сталкивается с вопросом «Откуда ты черпаешь вдохновение?»
Играйте во множество игр. Посредством изучения игр вы разрабатываете необходимый багаж механик и динамик, являющихся теми самыми жизненно необходимыми «кирпичиками» успешного гейм-дизайна. Важно играть в самые разные игры, а не только в те, с которыми у вас сложилось.
Общайтесь с другими дизайнерами. Два дизайнера, профессионально обсуждающих нюансы дизайна — надежный способ сделать игру. Помните, что это может быть и плохая игра, поэтому обращаться за фидбеком важно к квалифицированным профессионалам. Тем не менее, все дизайнеры используют одну и ту же методику, поэтому даже простое общение мотивирует их к более глубокому осмыслению.
Везде. Ищите идеи для игры во всем, что вы делаете, и заставляйте себя делать игру или думать о том, как сделать игру, посвященную чему-то новому, хотя бы раз в день. Прямо сейчас вас окружают приглушенные звуки: шорох страниц, звук собственного дыхания, возможно, музыка или телевизор на фоне. Гейм-дизайн точно так же может быть приглушенным или громким. Если вы будете постоянно искать идеи, вы будете находить их повсюду.
Интеллектуальная собственность (ИС)
Игры, основанные на ИС, очень распространены в гейм-индустрии, и большинство дизайнеров рано или поздно в своей карьере обнаруживают, что работают над игрой на основе изначально существующей ИС. Термин ИС используется для обозначения кого угодно или чего угодно, под подобие которого построена игра. Примеры ИС-игр — Spiderman, Halo, The Sims, а также персоналии, такие как John Madden.
История
Разработка игры, основанной на определенной истории, — это тоже достаточно распространенный подход, причем он больше относится к видео играм и в меньшей степени — к нецифровым играм. Обычно это сопряжено с интеллектуальной собственностью, в случае, когда обладатель лицензии хочет, чтобы разработчики придерживались сюжета книги, телевизионного шоу или фильма.
Что такое Unity?
Unity — кроссплатформенная 2D/3D среда разработки компьютерных игр, разработанная американской компанией Unity Technologies. Unity позволяет создавать приложения, работающие на более чем 25 различных платформах, включающих персональные компьютеры, игровые консоли, мобильные устройства, интернет-приложения и другие. Выпуск Unity состоялся в 2005 году и с того времени идёт постоянное развитие.
На этом движке были разработаны такие игры, как: Genshin Impact, Hollow Knight, Valheim, Rust, Pokemon Go, Kerbal Space Program. Unity подходить для созданий анимаций и фильмов, презентаций, приложений и игр.
Что такое C#?
C# (C Sharp, Си Шарп) очень мощный и относительно простой в освоении язык программирования от компании Microsoft. Язык относится к объектно-ориентированным языкам программирования и по синтаксису очень похож на Java и C++.
На языке C# можно писать приложения для настольных платформ (Windows. Linux, MacOS), мобильных (Android, iOS), умных телевизоров (Smart TV), носимых устройств (умные часы), создавать веб-приложения и многое другое.
Устанавливаем Unity Hub
1. Открываем браузер и заходим на официальный сайт Unity;
2. Нажимаем кнопку "Download for Windows";
3. Если у вас платформа отличная от Windows, то:
3.1. Нажмите кнопку "Download other versions";
3.2. Выберите "скачать установщик для MacOS" или "посмотреть инструкцию по установке на Linuxсистемы";
4. Начнется скачивание вспомогательного приложения "Unity Hub". Дождитесь окончания скачивания;
5. Запустите установщик "Unity Hub";
6. Примите "Лицензионное соглашение";
7. Выберите папку для установки "Unity Hub";
8. Нажмите кнопку "Установить" и дождитесь окончания установки;
9. После окончания установки нажмите кнопку "Готово".
Что такое Asset Store и UnityID
Для дальнейшей работы нам необходимо зарегистрироваться и получить UnityID. Позже он может вам пригодится при использовании Asset Store (о нём, в конце урока). Если у вас уже есть UnityID, то этот шаг можно пропустить.
Asset Store— это магазин готовых наборов текстур, моделей, эффектов (ассетов) и много чего ещё, для Unity. Не пугайтесь слова "магазин" в названии, помимо платных ассетов, в нём можно найти и множество бесплатных наборов для ваших проектов.
Регистрация
Когда вы запустите Unity Hub в первый раз, возможно, потребуется дать разрешение брандмауэру на доступ Unity Hub к своим ресурсам.
Запускаем "Unity Hub", выбираем пиктограмму "Учётной Записи" и кликаем на пункт "Create account".
Заполняем необходимые поля:
1. Вводим адрес электронной почты в поле "Email";
2. Имя пользователя (никнейм) в поле "Username";
3. Пароль в поле "Password". Пароль должен состоять: минимум из 8 символов (максимум 72), содержать одну большую букву, одну маленькую букву и одну цифру;
4. Имя в поле "Full Name". Можно ввести тоже что и в поле "Username";
5. Отмечаем пункты "I have read and agree to the Unity Terms of Service(required)." и "I acknowledge the Unity Privacy Policy [Republic of Korea Residents agree to the Unity Collection and Use of Personal Information] (required).";
6. Проходим проверку на то, что вы человек, а не бот;
7. Жмём кнопку "Create a Unity ID".
Подтверждаем свой электронный адрес - пройдя по ссылке из письма и можем войти в свою учётную запись.
Безопасность
Рекомендую включить в параметрах безопасности учётной запись "Двухфакторную Аутентификацию".
Вы можете включить аутентификацию как по номеру телефона, через код из SMS, так и через приложение аутентификатор (рекомендую именно второй вариант). Самые надёжные приложения для двухфакторной аутентификации, это: Microsoft Authenticator и Google Authenticator. Эти приложения доступны в Google Play Market и iOS Store, рекомендую скачивать их именно оттуда. Также при включении двухфакторной аутентификации вам будут показаны одноразовые резервные коды для прохождения двухфакторной аутентификации при невозможности использовать приложение - обязательно сохраните их.
Устанавливаем Unity
1. Запустим Unity Hub;
2. В появившемся окне поставим галочку в пункте "Don't ask me again" и нажмем кнопку "Skip installation";
3. В пункте "Installs" - нажмём кнопку "Install Editor";
4. В открывшемся окне, на вкладке "Official releases", нажмите кнопку "Install" на самом свежем релизе с припиской "LTS";
5. Далее, в появившемся окне, можно выбрать дополнительные модули для Unity, если вы не уверены или не знаете какие дополнительные модули вам необходимы, то уберите галочки со всех пунктов кроме "Documentation" и нажмите кнопку "Install". Если в дальнейшем вам понадобится какой-нибудь модуль из этого списка, то его всегда можно будет доустановить позже.
Дальше нам потребуется выбрать, в чем мы будете писать код для Unity - в редакторе кода Visual Studio Code или в среде разработки Visual Studio. Несмотря на похожие названия, это два совершенно разных инструмента, но не стоит боятся - дальше я объясню разницу между ними, и вы сами решите, что вам больше подойдёт.
Выбираем редактор кода для Unity
О Visual Studio Code
Visual Studio Code, это кроссплатформенный редактор кода, если совсем просто, то это "Текстовый редактор" или "Блокнот", от компании Microsoft, с дополнительными функциями работы с синтаксисом различных языков программирования. Редактор имеет огромное число поддерживаемых языков программирования.
О Visual Studio
Visual Studio по сравнению с Visual Studio Code, представляет из себя полноценную среду разработки (IDE) с возможность компиляции кода в исполняемый файл или библиотеку. И поскольку это среда разработки, то в неё входит очень много инструментов для написания консольных приложений, приложений с графическим интерфейсом, отладки кода и дальнейшей работы с ним.
Скачиваем и устанавливаем редактор кода Visual Studio Code
Скачиваем
1. Открываем браузер и заходим на официальный сайт Visual Studio Code;
2. Нажмите кнопку "Download for Windows".
Если у вас платформа отличная от Windows, то:
1. Нажмите на стрелку рядом с кнопкой "Download for Windows";
2. В выпадающем меню выберите "скачать установщик для MacOS", "пакет для установки в Linux x64" или версию для Windows x64;
3. Начнётся скачивание "Visual Studio Code". Дождитесь окончания скачивания.
Устанавливаем
1. Запустите установщик "Visual Studio Code";
2. Примите "Лицензионное соглашение" и нажмите "Далее";
3. Выберите путь, куда будет установлена "Visual Studio Code";
4. Выберите название папки программы в меню "Пуск" или вообще не создавайте её и нажмите "Далее";
5. Выберите необходимые дополнительные задачи (например: "Добавить действие "Открыть с помощью Code", для добавления возможности открывать файл в редакторе кода при выборе этого действия в контекстном меню, доступному по клику правой кнопкой мыши, или "Создать ярлык на Рабочем столе") или оставьте выбор по умолчанию и нажмите кнопку "Далее";
6. Проверьте, правильно ли выбраны дополнительные задачи и, если всё в порядке, - жмите кнопку "Установить";
7. Начнется процесс установки;
8. По завершению установки отметьте галочкой пункт "Запустить Visual Studio Code" и нажмите кнопку "Завершить".
Настройка Visual Studio Code
В конце предыдущего шага мы запустили наш редактор кода. Осталось немного его настроить:
1. В открывшейся Visual Studio Code выберите подходящую вам цветовую схему и нажмите "Mark Done";
2. Кликните в левой части окна на кнопку "Extensions", введите в строке поиска "Unity" и установите следующие расширения:
2.1.Unity от издателя Microsoft (это расширение установит всё необходимое);
2.2.Опционально. Unity Code Snippets" от издателя Kleber Silva (поможет быстро создавать базовые методы Unity);
2.3.Опционально. Russian Language Pack for Visual Studio Code от издателя Microsoft (интерфейс Visual Studio Code на русском).
Скачиваем и устанавливаем среду разработки Visual Studio 2022
Скачиваем
1. Открываем браузер и заходим на официальный сайт Visual Studio 2022;
2. Если у вас платформа отличная от Windows, то:
2.1.Если вам нужна версия для MacOS, то нажмите кнопку "Скачать Visual Studioдля Mac";
2.2.Если вам нужна версия для Linux x64, то выберите формат нужного вам пакета из выпадающего списка;
3. Для платформы Windowsнадо выбрать редакцию "Community" (эта редакция предназначена для отдельных разработчиков и проектов с открытым исходным кодом);
4. Начнется загрузка веб-установщика "Visual Studio 2022".
Устанавливаем
1. Запустите установщик "Visual Studio2022";
2. Нажмите "Продолжить";
3. В вкладке "Рабочие нагрузки" - отметьте "Разработка игр с помощью Unity" и, поскольку Unity Hub у нас уже установлен, то можно снять галочку на пункте "Unity Hub" в правой части экрана;
4. Если всё выбрано правильно, жмите кнопку "Установить";
5. Дождитесь окончания установки.
О Unity
Отличие 2D проекта от 3D
В Unity вы можете создавать как 2D проекты с "плоской" графикой, так и 3D использующие полноценно все три измерения. Также вы, скорее всего, встречали так называемые 2.5D проекты, в которых игровой мир или модели персонажей представляют из себя трехмерные модели, но передвижение по игровому миру ограничено двумя измерениями.
Первый запуск Unity
1. Запустите "Unity Hub";
2. Выберите вкладку "Projects" и нажмите кнопку "New project";
3. Далее выберите вкладку "All templates" или "Core", выберите "3D Core" (можете задать имя проекта в "Project name") и нажмите кнопку "Create project".
Терминология
Перед тем как перейти к обзору интерфейса программы давайте немного разберёмся в терминах. Пойдём по возрастанию.
Компоненты — это базовые кирпичики, из которых состоит любой "Объект" в Unity.
Объект — Это контейнер для "Компонентов". Если мы посмотрим, даже на пустой объект, то на нём обязательно будет компонент "Transform". Позволяющий нам двигать объект, вращать его и менять его размеры.
Добавив к объекту компоненты "Mesh Filter" и "Mesh Renderer" позволит придать объекту внешний вид, а добавив к ним ещё и "Rigidbody" наш объект приобретёт физические свойства.
Таким образом "Объект" состоит из "Компонентов".
Сцена - Тут всё просто. Сцена содержит в себе "Объекты", которые содержат в себе ... (вы и так знаете теперь что они содержат).
Обзор интерфейса Unity
Панель Иерархии (Hierarchy) - Здесь находятся все объекты, которые находятся на текущей "сцене" (уровне игры). На этой панели можно создавать папки и удочерять (группировать) объекты.
Окно Сцены (Scene) - Основное рабочее пространство, где мы будем видеть, что у нас происходит на сцене. В этом окне можно перемещать объекты и всячески с ними взаимодействовать.
Панель Свойств Компонентов (Inspector) - Как понятно из названия, это - свойства всех компонентов выбранного объекта. На этой панели мы можем менять свойства компонентов, добавленных к объекту, удалять и добавлять компоненты к объекту.
Список всех объектов в проекте (Project) — Это - список всех объектов, которые находятся в игре. Так как игры обычно состоят как минимум из нескольких сцен (уровней), то здесь хранятся объекты из всех сцен игры.
Гизмо (Gizmos) - Своего рода компас, показывающий направление в пространстве по осям. Также, "Гизмо" имеется у любого объекта на сцене, достаточно выбрать объект и вы его увидите.
Панели Инструментов трансформации объекта - Инструменты для перемещения, изменения размера и поворота объекта. Подробнее об этих инструментах будет рассказано в следующем модуле.
То, что сейчас видит объект "Камера" - Поскольку, в данный момент, у нас выбран объект "Камера", то для большего удобства её обзор выведен в отдельное окно. Если мы выберем другой объект, то это окно исчезнет.
Это далеко не весь интерфейс, и вы можете заметить, как минимум вкладки "Game" и "Console". Дальше я расскажу для чего они нужны и как настроить интерфейс под свои нужды.
Панель Иерархии (Hierarchy)
На этом шаге мы подробнее разберем панель "иерархии" в нашем проекте.
В панели "иерархии" мы можем добавлять объекты в нашу сцену. Например, мы можем создать пустой объект и использовать его как привычную нам, по работе с ОС, папку или добавить к этому пустому объекту скрипт или компонент и придать объекту необходимые свойства. Помимо пустых объектов можно создать геометрические 3D объекты, такие как: куб, сфера. цилиндр и т.п., эффекты частиц: взрывы, пламя и т.п., источники освещения: направленные, точечные и т.п., элементы интерфейса, такие как: текст, поля для ввода, слайдеры (ползунки) и кнопки, и многое-многое другое.
Окно сцены (Scene)
Настройка сцены и окна сцены
1. Переключение между центром объекта (Center) и точкой поворота (Pivot). Центр объекта — это именно центр объекта, вне зависимости от настроек 3D модели. Точка поворота (Pivot) — это точка, вокруг которой вращается объект и которая настроена при создании объекта в стороннем 3D редакторе (если Pivot не настроена, то она совпадает с центром объекта). Конкретно в Unity можно изменить точку поворота, если удочерить объект. Т.е. точка поворота будет назначена на родительский объект.
2. Переключает объект между локальными (Local) и глобальными (Global) координатными пространствами.
2.1.Локальное координатное пространство — это пространство относительно родительского объекта (если он есть), если родительского объекта нет, то объект сам по себе является родительским для себя самого. Например, вытяните руку вперёд и для вас она всегда будет смотреть вперёд вне зависимости в какую сторону света (север, юг, запад, восток) она направлена.
2.2.Глобальное координатное пространство — это пространство, где у всех объектов одни и те же направления по осям X, Y и Z, но разные координаты в пространстве. Например, вы и ваш друг стоящий рядом имеете разные координаты в пространстве, но стороны света для вас будут в одном и том же направлении.
3. Включает и выключает сетку для облегчения позиционирования. Позволяет настроить ось, на которой располагается сетка, её прозрачность и позицию по выбранному объекту или по нулевым глобальным координатам.
4. Включает "прилипание" к узлам сетки. Позволяет настроить размер ячейки для всех осей, отдельно для каждой из них и выровнять выбранный объект по ближайшему углу сетки.
5. Полезный инструмент. Он позволяет настраивать то, насколько пошагово будет изменяться размер выбранного объекта, угол поворота или на какое расстояние будет перемещаться объект при зажатой клавише Ctrl (Command для MacOS).
6. Очень объёмное меню, с пунктами, позволяющими менять вид сцены для визуализации проблемных мест в сцене и оптимизации. Описывать все пункты этого меню не имеет смысла, проще попробовать самим и понять как эта опция влияет на сцену.
7. Переключение вида в 2D проекцию. Удобно для редактирования интерфейса.
8. Отключает отрисовку источников света.
9. Включение/Отключение звуковых эффектов в сцене.
10. Позволяет включать и выключать различные эффекты, такие как: "Небо" (Skybox), "Туман" (Fog), "Эффект линзирования" от источников света, пост-обработку источников света, систему частиц и постоянное обновление этих эффектов.
11. Позволяет скрыть или показать объекты, отмеченные как "невидимые".
12. Настройка параметров главной камеры (Main Camera) на экране сцены.
13. Позволяет включать и отключать различные вспомогательные обозначения, линии (например, "Гизмо"), иконки источников звука и т.п. Также рекомендую не боятся пробовать включать/отключать различные пункты в этом меню, для наилучшего понимания.
Свойства выделенного объекта
Позиция объекта (Transform) - Как вы догадались по названию, это - позиция объекта на сцене. Она может быть "Глобальная" - когда объект находится на сцене и не является дочерним, или локальная - когда объект является дочерним объектом другого объекта.
Добавить компонент (Add Component) - Очень важная кнопка, позволяющая добавить компоненты к выбранному объекту.
Создание объектов
Для того, чтобы у нас был какой-то ориентир при перемещении по сцене - создадим объект.
Щелкнем в панели "Иерархии" правой кнопкой мыши и выберем "3D Object/Sphere". В окне сцены мы увидим шар, - это наш первый объект, который мы только что создали.
Управление взглядом в сцене
Давайте теперь немного полетаем по сцене и поймем, как в ней ориентироваться.
Для осмотра по сторонам - зажмите Правую Кнопку Мыши и поводите мышью по сторонам. Тоже самое будет происходить при зажатой Левой Кнопке Мыши + Alt, если не один объект в "иерархии" не выбран.
Для поворота камеры вокруг центра объекта - выберите объект в "иерархии", зажмите Левую Кнопку Мыши + Alt и ведите мышью по горизонтали или вертикали.
Для приближения или удаления камеры - зажмите Правую Кнопку Мыши +Alt и ведите мышью по горизонтали или вертикали.
Перемещение по сцене осуществляется с помощью зажатия Правой Кнопки Мыши и привычной многим раскладки W, A, S, D. Движение вверх и вниз осуществляется похожим образом - зажимаем Правую Кнопку Мыши и клавишу Q - чтобы опустится вниз или Правую Кнопку Мыши и клавишу E - для поднятия вверх. Для ускоренного перемещения - дополнительно зажмите клавишу SHIFT. Также, если с зажатой Правой Кнопкой Мыши покрутить колесом мыши, то можно регулировать скорость перемещения (от 0.1 до 2 единиц. По умолчанию выставлено значение 1). А если просто покрутить колесом мыши, то можно медленно приближать и отдалять взгляд к\от объекта.
Если вы потерялись на сцене или не можете найти нужный вам объект, то выберите объект в "Иерархии" и нажмите комбинацию клавиш Shift + F, то камера сфокусируется на выбранном объекте.
Позиционирование объекта на сцене
Если объект создался где-то за пределом вашего "Поля зрения", то давайте перенесем его в центр сцены и сфокусируемся на нем.
Выберем наш шар на панели "Иерархии", нажмем на "Три точки" в правом верхнем углу компонента "Transform", выберем пункт "Reset Property", далее пункт - "Position". Готово, выбранный объект в нулевых координатах нашей сцены.
Теперь кликнем два раза на нашем объекте в "Иерархии" и переместимся к объекту, который окажется в центре кадра (также, можно нажать кнопку "F").
Изменение положения и формы выбранного объекта
Также вам будет просто необходимо быстро изменять форму объектов и их положение в пространстве сцены.
Компонент "Камера" (Main Camera)
В нашей игре компонент "Камера" — это "глаза" игрока. Давайте посмотрим на её настройки.
Выберите в панели "Иерархии" объект "Main Camera".
Clear Flags- Эта настройка, в основном, используется, когда у вас больше, чем одна камера в сцене. Например, одна камера у вас демонстрирует вид из глаз персонажа, а второй камерой выведем инвентарь. И эта настройка отвечает за заполнение "пустой" области, в которой нет объектов.
Background- Если в предыдущем пункте не выбран какой-либо "Skybox", то "пустая" область заполняется выбранным цветом.
Culling Mask- Для каждого объекта можно назначить слой, эта настройка позволяет исключить какие-либо слои из отрисовки камерой.
Projection- Переключение режимов "Перспектива" и "Ортография".
- Perspective- Камера рисует объекты в перспективе.
- FOV Axis- Появляется при выборе режима "Perspective". Выбор оси ("Vertical" или "Horizontal") для пункта "Field of View".
- Field of View - Появляется при выборе режима "Perspective". Ширина угла обзора камеры измеряется в градусах по локальной оси Y.
- Orthographic- Камера рисует объекты без эффекта перспективы (ортографический режим). Подходит для отрисовки пользовательских интерфейсов.
- Size- Появляется при выборе режима "Orthographic". Область видимости камеры в этом режиме.
Physical Camera- При включении этой настройки камера начинает имитировать настройки объектива настоящей камеры.
Clipping Planes
- Near- Ближайшее расстояние от камеры, которое будет отрисовываться.
- Far - Самое дальнее расстояние от камеры, которое будет отрисовываться.
Viewport Rect- Определяет, в какой части экрана будет отрисовано изображение с камеры.
Depth - Позиция камеры в очереди отрисовки. Камеры с большим значением будут отрисованы поверх камер с меньшим значением.
Rendering Path- Выбор метода отрисовки для камеры.
Target Texture- Выбор текстуры, куда будет выводится изображение с камеры. Отключает возможность отрисовки изображения на экран
Occlusion Culling- Если включено, то объекты, находящиеся за другими объектами (например стеной) или вне поля зрения, не будут отрисовываться (подробнее).
HDR - Включение технологии High Dynamic Range в окне камеры.
MSAA - Включение аппаратного сглаживания в окне камеры.
Allow Dynamic resolution- Включение динамического разрешения.
Target Display- Выбрать внешнее устройство вывода изображения с этой камеры.
Быстрое перемещение камеры и объектов
Есть ещё несколько очень полезных действий, которые позволяют быстрее позиционировать камеру или объект в поле зрения камеры.
1. Move To View (Ctrl + Alt + F) - Перемещает выбранный в данный момент объект в центр экрана.
2. Align With View (Ctrl + SHIFT + F) - Перемещает выбранный в данный момент объект в начало позиции "взгляда" на сцену. Очень удобный инструмент для выставления объекта "Камера". Выбираете камеру, выставляете нужную точку обзора в сцене, выбираете данное действие - всё готово, камера установлена в нужной точке.
3. Align View to Selected (НЕТ) - Перемещает "взгляд" в выбранный на данный момент объект (как будто мы смотрим от лица выбранного объекта).
4. Toggle Active State (Alt + SHIFT + A) - Включает или выключает выбранный объект на сцене. Аналогично тому, что мы уберем галочку в "Инспекторе" напротив имени объекта.
Запуск нашей игры
Перед запуском игры зайдите в вкладку "Game" и выберите разрешение и соотношение сторон, в которых будет запускаться игра. Поскольку общепринятым стандартом минимального разрешения стал FullHD (1920x1080), то рекомендую выбирать между ним и пропорцией экрана 16 к 9.
Добавляем компонент "Твердое тело" (Rigidbody)
Теперь добавим нашему шару немного физики, а именно компонент "Rigidbody".
Выбираем наш шар на панели "Иерархии", в панели "Инспектор" мы увидим все компоненты, которые добавлены на объект по умолчанию. Нажмём на кнопку "Add Component" в самом низу "Инспектора" и в открывшемся списке, через поиск, начав вводить название компонента, или выбрав пункт "Physics", найдем компонент "Rigidbody" (ВНИМАНИЕ: не Rigidbody 2D, а именно Rigidbody).
Добавляем "землю"
Добавим для нашего шара землю, чтобы он не падал в "бездну".
Здесь всё точно также, как и с добавлением объекта шара, только вместо шара мы выберем "Куб" (Cube). У нас появился куб, и мы точно также отцентруем его позицию. Возникла проблема: наш шар оказался внутри куба. Давайте поднимем наш шар над кубом на две единицы (условно на два метра) от центра нашей сцены. Тут я предоставлю вам свободу в выборе способа как это сделать. Можете его поднять с помощью инструмента "Move Tool" (на клавишу "W") или введя значение с клавиатуры в компоненте "Transform" нашего шара (чтобы понять, в каком направлении нужно поднять наш шар, посмотрите на "Гизмо").
"Но ведь это просто куб, а никакая не земля?!" - Скажите вы, и будете правы. Для того, чтобы превратить наш куб в "землю", его нужно растянуть. И я думаю, вы уже догадались, как это сделать. Если нет, прочитайте ещё раз шаг "Изменение положения и формы выбранного объекта" из урока "Создание и взаимодействие с объектами".
Твёрдое тело (Rigidbody)
Компонент добавляющий или, наоборот, ограничивающий физические свойства объекта, такие как: масса, гравитация, сопротивление "воздуха" при падении и повороте.
Разберем некоторые пункты компонента "Rigidbody", чтобы вы могли немного поиграть с настройками и понять принцип взаимодействия с параметрами в компонентах.
Mass- Масса нашего объекта в килограммах.
Drag- Сопротивление "воздуха" при перемещении объекта. Например, мы можем толкнуть объект, и этот параметр будет влиять на то, как быстро наш объект остановится. Например, если установить значение это параметра равное нулю, положить объект на бесконечно ровную поверхность и придать ему импульс, то объект будет двигаться бесконечно долго. А если установить значение равное, например, единице, то импульс переданный объекту начнёт затухать и в конечном итоге - объект остановится.
Angular Drag- Сопротивление "воздуха" при вращении объекта. По сути это предыдущий пункт, но для объекта который вращается.
Use Gravity - Действует ли на объект гравитация.
Is Kinematic - Если нужно управлять объектом не физически, а перемещать его, например, с помощью скрипта.
Interpolate- Задействуется при аномалиях, когда мы используем физику при перемещении объекта (оставим по умолчанию).
Collision Detection - Настройка обнаружения столкновений (оставим по умолчанию).
Costraints- Запрет движения или вращения по определенным осям.
Материал поверхности (Material)
"Материал", по сути, — это набор текстур разного назначения. Основное их назначение - придание нужного цвета и визуального объема нашему объекту.
Добавление материала немного отличается от создания объекта и больше похоже на создание "Префабов" (об этом дальше). Давайте на примере добавим к нашему шару материал.
Кликаем "Правой Кнопкой Мыши" на панели "Проект", выбираем пункт "Create" и "Material".
Даём название нашему материалу (например: "Red").
Выбираем только что созданный материал, переходим в его свойства (панель "Inspector"), нажимаем на пункт "Albedo" и в появившемся круге выбираем цвет, а в квадрате в центре - оттенок.
Внизу свойств материала мы сразу можем видеть, как меняется цвет материала.
Осталось перетащить материал на нужный объект (в нашем случае это наш шар).
А как это сделать - решать вам. Вы можете:
- Перетащить материал на объект, находящийся на сцене.
- Перетащить материал на нужный объект в "Иерархии".
Выбрать нужный объект в "Иерархии" и перетащить материал в его "Инспектор".
Отлично, теперь наш шар не сливается с "землей".
Префабы (Prefab)
Поговорим про такую полезную вещь как "Префабы" (Prefabs). Префабы нужны для сохранения в проекте уже настроенных объектов. Например, мы создали объект, изменили его размер на необходимый нам и хотим, чтобы в нашей игре таких объектов с таким размером было 10 или 20, или может быть даже 100. Конечно, можно вручную копировать или создавать объект и изменять его размер, но здесь нам на помощь приходят префабы. Мы "объявляем" объект префабом и в любое время можем добавить на нашу сцену уже настроенный объект.
Или мы добавили наш префаб на сцену некоторое количество раз и вдруг поняли, что необходимо добавить к объекту какой-то компонент или дочерний объект. Мы просто редактируем префаб и все объекты на сцене, которые являются экземпляром этого префаба, также изменяются.
Если вы отредактируете префаб находящийся на сцене, то это никак не повлияет на остальные экземпляры префаба.
Для редактирования префаба и всех его экземпляров необходимо найти префаб в папке "Assets", два раза щёлкнуть на нём Левой кнопкой мыши и таким образом перейти в режим редактирования префаба
Давайте сохраним наш шар как префаб. Просто перетаскиваем наш объект "Sphere" из панели "Иерархии" в панель "Проект". Всё, наш префаб готов, и мы можем сколько угодно раз перетащить его из панели "Проект" в нашу сцену.
Также заметьте, если объект является копией префаба - в "Иерархии" он обозначается синим цветом.
Если удалить префаб из панели "Проект", то со сцены он не исчезнет и будет подсвечен в "Иерархии" красным цветом.
Порядок в проекте
Теперь давайте наведем порядок в нашем проекте. В данный момент у нас очень маленький проект, состоящий, буквально, из трех объектов, но даже средние по объему проекты состоят из сотен объектов.
Создадим папки под определенные виды объектов. Процесс этот достаточно прост и привычен рядовому пользователю ПК. На панели "Проект" выбираем папку "Assets", кликаем правой кнопкой мыши или на самой папке "Assets" или внутри неё выбираем пункт "Create" и далее - пункт "Folder".
Даём имя нашей папке (например "Materials") и переносим туда наш, недавно созданный, материал. Также поступаем с нашим префабом.
Направленный источник света (Directional Light)
"Directional Light" — это базовый компонент каждой сцены (как и "Main Camera"). Он играет роль "солнца" в сцене. Мы можем выделить этот объект, и с помощью инструмента "Rotate Tool", поменять направление его свечения.
Позиция этого источника света не имеет никакого значения и ни на что не влияет. Если он вам мешает при работе со сценой, вы можете отодвинуть его в сторону и это никак не повлияет на то, как он светит, в отличии от угла поворота по осям. Позиция данного объекта — это некая условность.
Разберем его настройки:
- Type - Тип источника света (Spot, Directional, Point и Area (baked only))
- Color - Цвет испускаемого света.
- Mode - Режимы.
- Realtime - Все источники света обрабатываются в реальном времени.
- Mixed - Смешенный. Он включает в себя режимы "Realtime" и "Baked".
- Baked Shadow Angle (доступно только в режимах: Mixed и Baked) - Чем длиннее тень, тем больше она будет рассеиваться к своему окончанию.
- Baked - Заранее просчитывает все источники света и создаёт "Карту освещенности" (Lightmap). Отлично подходит для статических сцен без динамических источников света.
- Intensity - Яркость источника света.
- Indirect Multiplier - Так как свет отражается от любой поверхности, то этим параметром мы выставляем степень отражения света от объектов для этого источника освещения.
- Shadow Type - Тип отбрасываемой тени.
- No Shadows - Без теней.
- Hard Shadows - Жесткие тени с четким контуром.
- Soft Shadows - Мягкие тени с рассеянным контуром.
- Доступны только в режимах "Realtime" и "Mixed" и при выбранном типе "Hard Shadows" или "Soft Shadows".
- Strength - Отвечает за то насколько тёмная будет тень.
- Resolution - Разрешение карт теней. Чем выше качество, тем корректнее будут тени от этого источника света (влияет на производительность).
- Bias - Параметр, влияющий на длину тени и, в некоторых случаях, позволяющий избавится от артефактов.
- Normal Bias - Параметр, позволяющий избавится от артефактов с тенями.
- Cookie - Текстурная маска, с помощью которой можно создавать различные эффекты (например эффект абажура).
- Cookie Size - Размер текстурной маски.
- Draw Halo - Рисует сферический ореол света вокруг источника.
- Flare - Ссылка на ассет блика.
- Render Mode - Важность этого источника освещения (т.е. насколько подробно он будет отрисован).
- Auto - Unity сам выбирает качество отрисовки.
- Important - Важный источник света (хорошая отрисовка).
- Not Important - неважный источник света (не ресурсоёмкая отрисовка).
- Culling Mask - Позволяет выбрать, какие слои нужно освещать.
Точечный источник света (Point Light)
Точечный источник света проще всего представить как лампочку.
Настройки в нём точно такие же, как в "Directional Light", кроме одного пункта, который доступен в источниках света Point и Spot, этот пункт называется Baked Shadow Radius, он становится доступен при выборе режима: Baked или Mixed и при выборе типа тени - Soft Shadows. Этот параметр смягчает края теней и придает им естественности при "запекании" освещения.
"Фонарь" (Spot Light)
Этот источник света проще всего представить, как уличный фонарь, прожектор или карманный фонарик с направленным конусом светом.
Настройки схожи с другими источниками света, кроме пункта "Spot Angle". Эта настройка отвечает за ширину конуса освещения.
Переменные
Переменные используются для хранения неких данных. Например:
- int = 100 - Переменная типа int хранит целое число в диапазоне от -2147483648 до 2147483647.
- float = 10.50f - Переменная типа float хранит значение числа с плавающей точкой от -3.4*1038 до 3.4*1038.
- string = "Hello!" - Переменная типа string хранит строку. Строка обозначается двойными кавычками " ".
Тип переменной должен соответствовать её содержанию, но не всегда. Например, тип float может содержать значение типа int равное - 100, это возможно благодаря тому, что, в случае перевода целого числа в число с плавающей точкой не произойдёт потери точности и число, просто превратится в 100.0, это так называемое неявное преобразование. А вот число с плавающей точкой также неявно перевести в целое число уже не получится, т.к. число типа float равное - 100.5 при таком переводе потеряет в точности (отпадёт дробная часть после точки) и то, что мы хотим сделать именно так - необходимо указывать явно, т.е., произвести явное преобразование.
Переменная типа bool
Отдельно хочется упомянуть переменную типа bool, она может хранить значение: false ("ложь" или условно 0) или true ("правда" или условно 1). Очень часто используется с условными операторами if и else if (о них дальше).
Методы (функции) и модификаторы доступа
Модификаторы доступа
Модификаторы доступа позволяют давать или запрещать доступ к данным в программе. Разберем те модификаторы доступа, которые будем использовать:
- public - Даёт доступ к методу, классу или переменной всем.
- private - Даёт доступ к методу или переменной только внутри класса, где он объявлен.
Методы
Если очень упрощенно, то метод — это список действий, который надо выполнить. В программировании не принято копировать один и тот же код (раздувая код программы) и поэтому используют методы, в которые просто передаются разные данные.
Например:
public int Add (int a, int b)
{
return a + b;
}
Здесь мы создали метод, который в качестве аргументов принимает два числа, а возвращает их сумму.
public - Модификатор доступа.
int - Тип возвращаемого значения.
Add (int a, int b) - Add это название нашего метода. К названию метода предъявляются некоторые требования:
Имя метода может содержать любые цифры, буквы и символ подчеркивания, при этом первый символ в имени должен быть буквой или символом подчеркивания (хорошим тоном считается название метода с большой буквы).
Имя метода не может быть ключевым словом языка C#. Таких слов не так много, и при работе в Visual Studio или Visual Studio Code, среда разработки подсвечивает ключевые слова синим цветом.
В имени метода не должно быть знаков пунктуации и пробелов.
Дальше, после названия метода, в круглых скобках, идут аргументы, т.е. то с чем метод может производить какие-то операции. В нашем случае это сложение
{и} - Фигурные скобки обозначают начало и конец метода, так же называемое зоной ответственности метода.
return - Оператор, который возвращает результат нашей операции. Это ключевое слово при возвращении значения в методе. Если после этого оператора есть ещё какие-то команды, то они не будут выполнены, т.к., после оператора return метод закончит свою работу.
a + b - Сложение наших переданных аргументов.
; - Обозначает, для компилятора, конец строки.
Также давайте рассмотрим метод без возвращаемого значения:
public void PrintMsg()
{
Console.WriteLine("Hello!");
}
void - Говорит нам о том, что метод не возвращает никакого значения (void - дословно переводится как - "пустота").
Console.WriteLine("Hello!"); - Метод, печатающий в консоль "Hello!".
Если метод ничего не возвращает (void), то невозможно объявить переменную, которая хранит значение, этого метода. В случае с методами, которые возвращают значение это сделать возможно.
Перегрузка методов
В классах Unity очень часто используется перегрузка методов. Перегрузка методов — это использование одного и того же метода (с одним и тем же названием), но с разными аргументами, их количеством и типом.
Например, есть метод, который складывает два целых числа, типа int, и возвращает результат.
public int Sum (int a, int b)
{
int result = a + b;
return result;
}
А что, если нам нужно сложить не два, а три целых числа? Не проблема - пишем ещё один метод, точно с таким же названием, но в качестве аргументов принимающий три числа.
public int Sum (int a, int b, int c)
{
int result = a + b + c;
return result;
}
Или нужно сложить уже не два целых числа типа int, а два числа с плавающей точкой, типа float. Опять пишем метод с тем же названием, но с аргументами типа float.
public float Sum (float a, float b)
{
float result = a + b;
return result;
}
Таких методов в Unity очень много, и вы сами можете это увидеть - нажмите Левой Кнопкой Мыши на интересующем вас методе, зажмёте клавишу Ctrl и ещё раз нажмите Левую Кнопку Мыши на методе.
Условные операторы "if", "else if" и "else"
Разберем на примере кода:
int a = 2;
int b = 1;
if(a > b) // если a больше b, то ...
{
Console.WriteLine("YES"); // ... выведем в консоль эту строку.
}
else // в противном случае ...
{
Console.WriteLine("NO"); // выведем в консоль эту строку.
}
Мы объявляем две переменные a и b и с помощью if, задаем условие: "если a больше, чем b, то мы должны сделать следующее" и в ответ получаем переменную типа bool, в данном случае она равна true, т.е. ответ "Да, это правда. a больше b". И если это "правда", то в консоль выводится слово "YES", а если неправда, т.е. "ложь" то даётся следующее указание (else) "Тогда сделай следующее..." и в консоль выведется "NO".
В этом примере мы получим противоположный результат:
int a = 2;
int b = 3;
if(a > b) // если a больше b, то ...
{
Console.WriteLine("YES"); // ... выведем в консоль эту строку.
}
else // в противном случае ...
{
Console.WriteLine("NO"); // ... выведем в консоль эту строку.
}
Но что, если наши значения будут равны, что выведется на консоль?
int a = 2;
int b = 2;
if (a > b) // если a больше b, то ...
{
Console.WriteLine("YES"); // ... выведем в консоль эту строку.
}
else // в противном случае ...
{
Console.WriteLine("NO"); // ... выведем в консоль эту строку.
}
Выведется "NO", т.к., a, в первую очередь, не больше b. Но как же нам поступить в этом случае, ведь у нас может быть три состояния: a больше b, a меньше b и a равно b? Для этого есть выражение if else, в условиях которого мы можем прописать проверку на равенство. В этом случае наш пример будет выглядеть вот так:
int a = 2;
int b = 2;
if (a > b) // если a больше b, то ...
{
Console.WriteLine("YES"); // ... выведем в консоль эту строку.
}
else if(a == b) // если a равно b, то ...
{
Console.WriteLine("EQUALS"); // ... выведем в консоль эту строку.
}
else // в противном случае ...
{
Console.WriteLine("NO"); // ... выведем в консоль эту строку.
}
Теперь в ответе мы получим - "EQUALS". Заметьте, что для сравнения мы используем ДВА знака равно (==), если мы поставим один знак, то компилятор нас не поймёт, т.к., ОДИН знак равно (=) это присвоение, а в выражениях if и if else используется сравнение.
Логические операции
Часто в условиях вы будете встречать логические операторы, например:
&& или "Логическое И". Если два условия верны - возвращает значение (true).
int a = 2;
int b = 1;
if(a > b && 1 + 2 == 3) // если a больше b И 1 + 2 равняется 3, то ...
{
Console.WriteLine("YES"); // ... выведем в консоль эту строку.
}
else // в противном случае ...
{
Console.WriteLine("NO"); // ... выведем в консоль эту строку.
}
|| или "Логическое ИЛИ". Если, хотя-бы, одно из условий, верно, т.е., является "правдой" - возвращает (true). Если оба условия не верны и являются "ложью"- возвращает (false), если оба условия верны и являются "правдой" - возвращает (true).
int a = 2;
int b = 1;
if (a > b || a * b == 10) // если a больше b ИЛИ a * b равняется 10, то ...
{
Console.WriteLine("YES"); //... выведем в консоль эту строку.
}
else // в противном случае ...
{
Console.WriteLine("NO"); //... выведем в консоль эту строку.
}
Выбираем редактор кода для Unity
Для использования установленного ранее редактора кода вместе с Unity нам необходимо выбрать его в настройках.
В окне Unity зайдите в "Edit\Preferences...", на вкладке "External Tools", в пункте "External Script Editor" выберите редактор кода.
Основные принципы создания игры
Чтобы шар не выкатился за пределы нашей "земли" - оградим площадку "забором" из растянутых примитивов-кубов. Также создайте новый материал и прикрепите его к нашему забору, чтобы он не сливался с "землей".
Отпозиционируйте камеру так чтобы ось X пересекала наше игровое поле по вертикали, а ось Z по горизонтали.
Кнопки
Родительский объект для кнопок
Внутри "Иерархии" создадим пустой объект "Create Empty" и назовем его UI, этот объект будет "родителем" для наших кнопок.
Создание кнопок
Далее, в нашем родительском объекте, UI, создадим кнопку - кликнем Правой Кнопкой Мыши на нашем, только что созданном, объекте UI, выберем пункт UI и в нём пункт "Button - TextMeshPro".
В появившемся окне нас предупредят, что для работы с TextMeshPro необходимо добавить в проект некоторые ресурсы. Жмём на кнопку "Import TMP Essentials" и можем закрывать это окно. Если же вы хотите добавить в проект дополнительные примеры работы с объектами TextMeshPro и изучить их, то дополнительно кликните на кнопку "Import TMP Examples & Extras".
При добавлении на сцену объекта Пользовательского интерфейса (например: текста, изображения, кнопки и т.п.) - объект "Canvas" и "EventSystem" будут добавлены на сцену автоматически, при условии, что они отсутствовали на сцене до этого.
В нашем объекте UI появился объект "Canvas". "Canvas" (холст) это 2D объект на котором, как дочерний объект, расположилась наша кнопка. Давайте создадим на холсте ещё три кнопки и назовем их все: "ButtonUp", "ButtonDown", "ButtonLeft", "ButtonRight".
Вместе с объектом "Canvas", автоматически создаётся объект "EventSystem". Именно он позволит взаимодействовать с элементами Пользовательского интерфейса и в нашем случае, обрабатывать нажатия на кнопки. Не надо его удалять.
Настройка кнопок
Размещение кнопок
Кликнем два раза на любой из кнопок, созданных в предыдущем шаге, немного отдалим камеру и увидим наш "Холст" (Canvas) с одной кнопкой. На самом деле их там четыре, именно столько мы и создали, но они находятся на одной позиции и из-за этого их не видно. Распределите наши объекты кнопок по холсту в удобном для вас месте.
Текст на кнопках
Также, давайте напишем текст на наших кнопках, обозначающий, что они будут делать. Выбираем кнопку, внутри находим дочерний объект "Text (TMP)", выбираем его, и в "Инспекторе" ищем на нём компонент "TextMeshPro - Text (UI)" с нужным нам полем "Text Input". В нём мы и пишем наш текст, который будет отображаться на кнопке.
Также, ниже, вы можете настроить привычные атрибуты для текста, такие как: шрифт, размер, регистр и т.п.
У нас должно получится примерно так.
Настройка "холста"
Перед тем как писать скрипт для кнопок, нам необходимо изменить настройки объекта "Холст" (Canvas), чтобы наши кнопки не "убегали" при разных размерах окна игры.
Настраиваем "холст"
Настроим для нашего "холста" поведение при изменении размера дисплея. Выберем наш "холст" и в компоненте "Canvas Scaler" выставим следующие настройки:
Режим "Scale With Screen Size" означает что "холст" будет изменять размер в зависимости от размера экрана, "Reference Resolution" - эталонное разрешение (я выбрал FullHD, с соотношением сторон 16:9), "Screen Match Mode - Expand" - означает что за основание мы берём самую узкую сторону и изменяем размер элементов интерфейса пропорционально размеру самой узкой стороны.
Поэкспериментируйте с настройками, возможно, вам понравится другой вариант.
Прикрепляем кнопки к краю экрана с помощью "якоря"
У каждого объекта находящегося на "холсте" есть компонент "Rect Transform", с помощью него можно настроить уже привычные нам параметры, такие как: позиция объекта, его ширина, высота и т.д., но есть и новый для нас элемент, это "Якорь" (Anchor).
Мы можем указать настройки как вручную, так используя готовые шаблоны (ими мы и воспользуемся). Выберем все четыре кнопки в "иерархии" и укажем для них, в качестве "опорной точки", левый нижний угол.
Скрипт движения
Пишем код
Создаем новый скрипт, открываем и пишем в нём следующий код:
Разбираем наш код
В начале код выглядит похожим на наш предыдущий скрипт, но после объявления используемых пространств имен - следует новый, для нас, код [RequireComponent(typeof (Rigidbody))]. Эта строка идёт перед объявлением класса и принудительно добавляет к объекту компонент - Rigidbody, так как на этом объекте он нам нужен. Это своеобразная защита "от дурака" и таким образом можно добавлять к объекту любые требуемые компоненты.
Давайте разбираться дальше.
private Rigidbody ball; - Объявляем приватную переменную типа Rigidbody с названием ball, но не инициализируем её.
[SerializeField] private float powerImpulse = 80f; - Объявляем приватную переменную типа float и инициализируем её числом. Это будет начальное значение силы толчка нашего шара. В последствии мы сможем менять её прямо во время игры и таким образом подобрать подходящее нам значение.
[SerializeField] - Этот атрибут позволяет видеть и изменять значение приватного поля в инспекторе.
private - Переменная будет приватной и к ней нельзя будет обращаться из других классов.
float - Тип переменной. В данном случае это число с плавающей точкой.
powerImpulse - Название переменной. Вы можете дать ей любое другое название за исключением ключевых слов, зарезервированных в Unity и языке C# (например: Update или int).
= 80f; - Знак равно = означает присвоение какого-то значения нашей переменной, а 80f - значение, которое мы присвоили. f после числа - ставится в том случае если число является типом данных float.
В методе Start мы присваиваем переменной ball ссылку на компонент Rigidbody который находится на объекте, на который добавлен этот скрипт.
gameObject - Означает объект, на который добавлен этот скрипт.
GetComponent <Rigidbody> (); - Метод для получения ссылки на компонент определенного типа (тип указан в угловых скобках). В начале мы указали что переменная ball является переменной типа Rigidbody, поэтому нам нужно получить компонент точно такого же типа.
Дальше идёт наш публичный метод MoveUp() . Публичный он для того, чтобы мы могли взаимодействовать с ним за пределами это скрипта (класса).
ball - Здесь это уже переменная типа Rigidbody и как мы помним Rigidbody нам нужен для физического взаимодействия с объектом.
AddForce(Vector3.forward * powerImpulse) - Метод прилагающий физическую силу к объекту. В качестве аргумента метод принимает направление, в котором нужно приложить силу умноженное на переменную powerImpulse;
Следом идёт метод MoveDown () с небольшим отличием, перед аргументом в методе AddForce стоит знак минус -. Он означает противоположное направление, т.е. если бы мы написали AddForce(Vector3.back * powerImpulse); , то это было бы одно и тоже. Подобным образом написаны и остальные два метода, так что, не будем их разбирать, думаю вы и сами всё поймёте.
Прикрепляем метод к кнопкам
Переходим обратно в Unity. Добавляем только что созданный скрипт на наш шар и видим, что в компоненте нашего скрипта есть объявленное нами в скрипте поле для ввода.
Как мы помним, это поле содержит число, обозначающее силу, с которой мы будем воздействовать на наш объект.
Далее, выбираем нашу кнопку, нажимаем "плюс" внизу поля "OnClick()" и присваиваем появившемуся событию наш шар, просто перетащив его из "Иерархии" на нужное поле.
И из списка выбираем нужную нам функцию.
Повторяем это с оставшимися тремя кнопками.
Создание сцены
Давайте создадим "Главное Меню" для нашей игры, чтобы она не начиналась сразу с игрового процесса.
Открываем папку "Ресурсы" (Assets), внутри неё есть папка "Scenes", в которой содержится наша единственная сцена, кликаем Правой Кнопкой Мыши, выбираем "Create" и "Scene".
Назовём её - MainMenu.
- Пишем код
Логика скрипта
1. Добавим пространство имён для работы с сценами.
2. Объявляем переменные:
1. Переменная типа GameObject с именем ballPrefab для хранения префаба.
2. Переменная типа float с именем xBound для ограничения появления шара по оси X.
3. Переменная типа float с именем zBound для ограничения появления шара по оси Z.
4. Переменная типа float с именем destroyBorder ниже которой наш шар будет уничтожен.
5. Переменную типа GameObject с именем ball, которая будет хранить в себе ссылку на наш шар. Для чего это нужно - поймёте чуть ниже.
3. Начало метода Update (), выполняющегося каждый кадр.
1. Запускам метод BallSpawner () (метод будет описан ниже).
2. Запускам метод BallDestroy (), с аргументом (метод также будет описан ниже).
4. Начало метода BallSpawner (), который создаёт шар в случайных координатах заданной области.
1. Сначала выполним условие if (ball! = null), которое отвечает на вопрос - "Если переменная ball не пуста и на что-то ссылается, то выполнить код условия", т.е. что делать если шар у нас уже создан.
2. Если шар у нас уже создан, то мы не будем делать ничего и просто выйдем из метода с помощью оператора return.
3. Если переменная ball не на что не ссылается т.е. пуста, то выполняем следующий блок кода.
4. Создаётся переменная типа float, для оси X и присваиваем ей случайное число из диапазона: от -xBound до +xBound (в случае с положительным числом плюс опускается).
5. Создаётся переменная типа float, для оси Z и присваиваем ей случайное число из диапазона: от -zBound до +zBound (в случае с положительным числом плюс опускается).
6. Используем сгенерированные выше значения для создания нового вектора, для дальнейшего его использования.
7. Инициализируем переменную ball, одновременно создавая объект шара, указанный в переменной ballPrefab.
8. При появлении, шар в "Иерархии" будет находится в родительском объекте.
5. Начало метода BallDestroy (аргумент метода)
1. Если позиция шара ниже цифры, указанной в аргументе, то ...
2. Уничтожаем объект.
6. Метод AppExit (), для выхода из приложения\игры.
1. Специальное условие #if, которое сработает только в редакторе.
2. Выйти из режима игры.
3. Окончание условия специального условия, обозначающееся через#endif.
4. Выход из приложения\игры.
5. Выводим в консоль слово "EXIT".
7. Метод LoadNextScene (), для загрузки первого уровня, нашей игры.
1. Загружаем указанную сцену.
8. Окончание скрипта.
Разбор нового кода
using UnityEngine.SceneManagement; - Позволяет использовать методы для работы с различными данными связанными с сценами в проекте.
[SerializeField] private GameObject ballPrefab; - [SerializeField] позволяет видеть в редакторе Unity приватные поля и заполнять их данными или объектами. Также, можно было бы сделать эту переменную публичной (public GameObject ballPrefab) и не писать никакого [SerializeField], но это не очень безопасно, т.к., переменная будет видна из других классов и можно будет случайно (или не случайно) изменить данные в ней.
private GameObject ball; - GameObject является базовым объектом для всех остальных объектов в Unity. Грубо говоря, это наш шар со всеми компонентами, прикреплёнными к нему.
В методе Update мы используем два метода, хотя вместо второго метода, который очень короткий, могли бы написать это условие в Update. Всё это ради чистоты и читабельности кода.
if (ball! = null) - Отдельно хочется остановится на значении null, оно означает, что переменная не ссылается ни на что, т.е., это не ноль, как может показаться по названию, а именно ничего. В данном условии мы проверяем переменную на её неравенство (! = - проверка на неравенство, == - проверка на равенство) null.
В методе BallSpawner() мы могли бы всё вместить в одну строку и получить - ball = Instantiate(ballPrefab, new Vector3(Random.Range(-xBound, xBound), transform.position.y, Random.Range(-zBound, zBound)), Quaternion.identity, transform);, но мало кто любит разбираться в длинных строках содержащих методы, которые содержат ещё методы. Поэтому мы разбили эту длинную строку на много маленьких и легко читаемых переменных и в конце сложили из них метод.
Random.Range() - Класс, в котором мы вызываем метод Range который в качестве аргументов принимает минимальное и максимальное число с плавающей точкой или целое число и возвращает случайное число из этого диапазона. В данном методе случайные числа у нас получают оси X и Z, а ось Y у нас берет значение от объекта, на который добавлен этот скрипт. Обратите внимание, что в диапазоне мы используем одно число, но добавляя к нему минус мы получаем диапазон от -число до +число.
ball = Instantiate (ballPrefab, pos, Quaternion.identity); - Instantiate (); - Метод позволяющий создать экземпляр объекта. В качестве аргументов он принимает: префаб объекта который нужно создать, позицию где создастся объект(в данном случае нашу переменную с позицией) и вращение в представлении Кватерниона( identity - означает что оно "нулевое"). Также, в качестве аргумента можно сразу задать родительский объект, но мы делаем это уже после создания объекта.
if (ball.transform.position.y < value) - В этом условии, мы обращаемся к компоненту Transform, нашего объекта и проверяем у него только значение оси Y. Также в этом методе мы используем аргумент для которого я не придумал имя :)
Destroy(ball); - Метод позволяющий уничтожать объекты и принимающий в качестве аргумента объект, который нужно уничтожить. Также может принимать вторым аргументом значение типа float, для задания времени, через сколько объект надо уничтожить.
#if и #endif — Это специальные условия. В данном случае мы задаём исполнение условия только если мы запускаем проект в редакторе. Также, подобные условия можно настраивать в зависимости от запуска приложения в определённой среде. Например, в случае запуска под Windows мы можем делать одно действие, а в случае запуска под MacOS другое и всё это в рамках одного метода.
Application.Quit(); - Класс Application с методом Quit (), который завершает выполнение приложения.
Debug.Log("EXIT"); - Просто выводит в консоли слово "EXIT", что является показателем того, что метод отработал, так как в запущенной игре, в редакторе Unity, функция выхода из приложения не работает.
SceneManager.LoadScene(1); - Здесь как раз используется добавленный в начале скрипта SceneManager, LoadScene это метод принимающий в качестве аргумента порядковый номер сцены (об этом ниже).
Устанавливаем порядок сцен
Для того чтобы наш первый уровень загрузился, нужно добавить его в список сцен.
Заходим в "File" и кликаем на пункт "Build Settings...".
В открывшемся окне, просто перетащите наши сцены в вкладку "Build Settings", отсортируйте их в правильном порядке и закройте это окно.
Завершаем создание сцены "Главного Меню"
Для того чтобы наш скрипт заработал его надо добавить к объекту.
Создадим пустой объект, назовём его Spawner и разместите, над нашим полем, там откуда хотим чтобы появлялись наши шары.
Осталось выполнить несколько простых действия:
1. Добавить, к объекту Spawner, наш скрипт MainMenuScript;
2. В поле Ball Prefab, скрипта MainMenuScript - поместить префаб шара;
3. Добавить к кнопкам меню нужные методы, на действия кнопок "OnClick ()", точно также как мы это делали с кнопками управления.
Is Trigger
Что же такое "Триггер" в понимании Unity? Это объект, который при определенном, с ним, взаимодействии вызывает определенные действия. Например, сейчас мы сделаем площадку, при остановке на которой будет запускаться следующий уровень.
Немного переделаем наш уровень, добавив в него проход и источник света "Point Light".
Также добавим на место нашего финиша - куб, отключим у него компонент "Mesh Renderer", чтобы он не отображался на нашей сцене, и в компоненте "Box Collider" поставим галочку напротив пункта "Is Trigger". Также добавим компонент коллайдера на наш шар, если по какой-то причине он там отсутствует. Можете поэкспериментировать и вместо компонента "Sphere Collider" добавить например "Box Collider" или "Capsule Collider" и посмотреть, что получится.
В итоге у нас получился невидимый объект, с которым можно взаимодействовать при помощи скриптов.
Отмечаем объект
Мы создали невидимый объект и такие объекты, бывает, очень сложно найти в сцене. Поэтому мы отметим наш объект и его будет всегда видно.
Проверим, как у нас настроено отображение иконок в проекте. Для этого нажмём на кнопку, как на изображении ниже, и посмотрим на пункт "3D Icons". Если он включен, то мы можем регулировать размер иконок объектов ползунком справа, а если выключен, то иконки будут всегда одного размера, вне зависимости как далеко вы от объекта.
Теперь, выберем объект, который хотим отметить и в "Инспекторе", слева от название кликнем на иконку "куба" и выберем цвет и форму иконки.
Поздравление при прохождении уровня
Также давайте поздравим игрока за то, что он прошёл уровень. Создадим на нашем холсте объект "Text - TextMashPro". Отпозиционируем нашу надпись по центру.
Пишем код
Логика скрипта
1. Переменная, которая будет хранить текст с поздравлением.
2. Запуск нашего метода с аргументом (сам метод чуть ниже).
3. Базовый метод OnTriggerStay() срабатывающий когда объект останавливается в зоне "триггера".
4. Запуск нашего метода с аргументом (сам метод чуть ниже).
5. Запуск метода через определённое время.
6. Наш метод для перехода на следующий уровень.
7. Поскольку следующего уровня у нас нет, то мы просто выведем сообщение в консоли и это будет означать, то, что метод отработал корректно.
8. Наш метод включающий и отключающий сообщение с поздравлением.
9. В зависимости от аргумента, метод, включает и выключает сообщение с поздравлением.
Разбор нового кода
[SerializeField] GameObject congrats; - В это поле мы вставим текст с поздравлением, который будет отображаться при успешном завершении уровня.
OnTriggerStay() - Базовый метод срабатывающий когда объект с коллайдером останавливается в коллайдере другого объекта у которого отмечен пункт "Is Trigger" в компоненте коллайдера.
Также есть ещё два базовых метода взаимодействия с триггером:
· OnTriggerEnter() - Срабатывает когда один объект входит в коллайдер другого объекта.
· OnTriggerExit () - Срабатывает когда один объект выходит из коллайдера другого объекта.
Invoke ("NextLvl", 3f); - Базовый метод, который в качестве первого аргумента принимает строку с названием метода, который нужно запустить, а в качестве второго аргумента - время, в секундах, через которое нужно запустить этот метод.
Congrats(bool state); - Метод который принимает в качестве аргумента переменную типа bool и в зависимости от аргумента - включает или отключает объект добавленный в самом начале скрипта, в переменную congrats.
Осталось добавить этот скрипт к нашему невидимому кубу-триггеру и поместить наш текст с поздравлением в поле congrats.
Переименование продукта
1. Откройте продукт, который вы хотите переименовать. Перейдите в File> Build Settings> Player Settings.
2. Выберите категорию «Player» из списка слева. Теперь вы увидите место для ввода в название продукта справа (Product Name).
3. Внесите изменения и закройте окно настроек проигрывателя. Теперь у вашего продукта новое название.
Добавление иконки
1. Откройте продукт, который вы хотите переименовать. Перейдите в File> Build Settings> Player Settings.
2. Выберите категорию «Player» из списка слева. Теперь вы увидите место для ввода в название продукта справа (Default Icon).
3. Внесите изменения и закройте окно настроек проигрывателя. Теперь у вашего продукта новое название.
Добавление фоновой музыки к игре
После добавления компонента Audio Source, нас интересуют три поля:
1. В поле AudioClip, необходимо из окна Project, перетащить Ваш аудиофайл.
2. В поле Play On Awake поставить галочку, чтобы музыка воспроизводилась сразу после того, как загрузится на сцене игровой объект, к которому прикреплён данный аудиофайл.
3. В поле Loop так же поставьте галочку, чтобы после окончания вашего аудиофайла, он воспроизводился снова.
Установка модулей для поддержки сборки под разные платформы
Если хотите собрать проект под другую платформу, отличную от той в которой вы работаете то запустите Unity Hub, выберите пункт "Installs" и нажмите на значок "шестерёнки", рядом с вашей версией Unity.
Если он у вас уже установлен можете пропустить эту часть.
К установке модуля мы можем перейти двумя путями.
В Unity Hub:
1. Открываем вкладку Install;
2. Нажимаем на значок в правой части вкладки нужной версии редактора (если у вас их несколько);
3. Выбираем пункт "Add modules";
4. Отмечаем галочкой пункт "WebGL Build Support";
5. Нажимаем кнопку "Continue" и ждём окончания установки модуля.
В самом Unity:
1. Открываем окно "File\Build Settings...";
2. Выбираем в списке платформ справа WebGL;
3. Нажимаем на кнопку "Install with Unity Hub" и попадаем в Unity Hub с уже отмеченным нужным модулем;
4. Нажимаем кнопку "Continue" и ждём окончания установки модуля.
Выберите пункт "Add modules". В вкладке "Platforms" - выберите нужные вам модули и нажмите "Install" (в более свежих версиях это кнопка имеет название "Continue").
В некоторых случаях, например, при выборе, для установки "Microsoft Visual Studio Community", вместо кнопки "Install" - появится кнопка "Continue" и при нажатии на неё нужно будет принять пользовательское соглашение, а после нажать "Install".
Сборка проекта под платформу ПК
Заходим в "File" и выбираем пункт "Build Settings...".
Расположим сцены в хронологическом порядке, просто перетащив их из папке "Scene", выберем платформу, целевую платформу и архитектуру проекта.
Поскольку я работаю в Unity на платформе Windows и не устанавливал дополнительных модулей для поддержки других платформ (Mac и Linux), то в пункте "Target Platform" я не могу выбрать ничего кроме "Windows".
Всё, что теперь нужно сделать - нажать на кнопку "Build" (собрать проект) или "Build And Run" (собрать проект и запустить) и выбрать папку для сохранения готового проекта.
Подождите пока Unity соберёт проект и сохранит его в указанную папку. Всё, можете запустить проект, как любое другое самостоятельное приложение.
Сборка проекта под платформу Android
Для сборки под платформу Android - необходимо установить модуль для поддержки этой платформы. Как это сделать описано в этом шаге.
Заходим в "File" и выбираем пункт "Build Settings...".
Расположим сцены в хронологическом порядке, просто перетащив их из папке "Scene", выберем платформу, совместимость с известными моделями устройств и нажмём "Switch Platform".
Если вы уже собирали проект под эту платформу, то вместо кнопки "Switch Platform" будут привычные кнопки "Build" и "Build And Run".
Подождём пока Unity подготовит ресурсы для проекта. После этого станут доступны кнопки "Build" (просто собрать проект) и "Build And Run" (собрать проект и сразу запустить). Поскольку для пункта "Build And Run" нужно подключить устройство к ПК, то рекомендую выбрать кнопку "Build". После нажатия кнопки - необходимо будет выбрать папку куда будет сохранён готовый .APK файл и дождаться окончания сборки.
После окончания сборки, вы можете перенести .APK файл на устройство и установить его как обычное приложение.