Публикация сборок
В любой момент разработки игры можете захотеть посмотреть на то, как она выглядит вне редактора, при сборке в качестве самостоятельного приложения или веб-проигрывателя. В этом разделе рассказано, как вызвать и использовать окно Build Settings (настройки сборки) для создания разных сборок ваших игр.
Пункт меню File->Build Settings… позволяет открыть окно Build Settings. В нём выводится редактируемый список сцен для включения в сборку игры.

Список будет пуст при первом открытии этого окна в проекте. В таком случае, при сборке, в игру будет включена только текущая открытая сцена. Если вы желаете быстро собрать тестовый плеер с единственной текущей сценой, просто соберите плеер с пустым списком сцен.
Для создания сборки с несколькими сценами можно довольно просто добавить нужные сцены в этот список. Первый способ заключается в нажатии кнопки Add Current . Вы увидите, что текущая сцена появилась в списке. Второй способ предполагает перетаскивание в список сцены из окна Project View .
Следует заметить, что каждая из сцен в списке имеет свой индекс. Scene 0 — это первая сцена, которая будет загружена в сборке. Если вы желаете загрузить другую сцену во время игры, используйте в вашем коде метод Application.LoadLevel().
Если вы добавили более одной сцены и хотите изменить их порядок, просто перетаскивайте сцены в списке до тех пор, пока не добьётесь необходимого вам порядка.
Чтобы удалить сцену из списка, достаточно выбрать её в списке и нажать Command-Delete (на Mac) или Delete (на Win). Сцена пропадёт из списка и не будет включена в сборку.
Когда вы будете готовы к публикации своей сборки, выберите нужную платформу в списке Platform и удостоверьтесь, что напротив неё находится логотип Unity; если это не так, тогда нажмите кнопку Switch Platform , чтобы сообщить Unity о том, под какую платформу вы желаете совершать сборку. После этого, нажмите кнопку Build . Откроется стандартное диалоговое окно сохранения файла, в котором вы можете выбрать имя и расположение для игры. После нажатия кнопки Сохранить Unity соберёт ваше приложение, и готово! Довольно просто, не так ли? Если вы не уверены, куда лучше сохранять сборку, сохраняйте её в корневую папку проектов. Вы не можете сохранять сборку в папку Assets.
Включение опции Development Build добавит плееру возможность использовать Profiler и позволит изменять опции Autoconnect Profiler и Script Debugging.
Further information about the Build Settings window can be found on the Build Settings page.
Сборка standalone плееров
Unity может собирать standalone приложения для Windows, Mac и Linux. Достаточно просто выбрать целевую платформу в настройках сборки и нажать кнопку ‘Build’. При сборке standalone проигрывателей, получаемые в результате файлы могут различаться в зависимости от выбранной платформы. На Windows в результате сборки будет создан исполняемый файл (.exe) и папка “Data”, содержащая все ресурсы приложения. На Mac будет создан “app bundle”, содержащий все необходимые файлы для запуска приложения и его ресурсы.
Распространение standalone приложения на Mac заключается в передаче “app bundle” (в него упаковано всё необходимое). На Windows необходимо предоставить .exe-файл и папку Data, чтобы другие могли запустить приложение. То есть, чтобы другие пользователи могли запустить у себя ваши приложения, на их компьютерах должны быть файлы, которые для вас собрал Unity.
В недрах процесса сборки
Сперва процесс сборки разместит пустую копию игры там, где вы указали. Затем он начнёт прорабатывать список сцен в настройках сборки: открывать в редакторе одну из них за раз, оптимизировать их и интегрировать их в пакет приложения. Он также подсчитает все ассеты, необходимые включенным в сборку сценам и сохранит эти данные в отдельном файле внутри пакета приложения.
- Любой GameObject в сцене с тэгом ‘EditorOnly’ не будет включён в собираемый пакет. Это удобно для отладки скриптов, которые не должны оказаться в финальной игре.
- Все объекты в текущем уровне уничтожаются при загрузке нового уровня. Чтобы это предотвратить, используйте DontDestroyOnLoad() на любых объектах, которые вы желаете уберечь от уничтожения. Обычно это используют для проигрываемой при загрузке уровня музыки, или для скриптов игровых контроллеров, которых хранят состояние и прогресс игры.
- После загрузки уровня будет разослано сообщение OnLevelWasLoaded() всем активным игровым объектам.
- Для дополнительной информации о том, как лучше всего создавать игры, в которых насколько сцен (например, главное меню, экран рейтинга и сами уровни игры), ознакомьтесь с нашими уроками.
Предварительная загрузка (далее — прелоадинг)
Опубликованные сборки автоматически осуществляют прелоадинг всех ассетов в сцене при её загрузке. Исключением является сцена 0, так как она, как правило, используется в качестве загрузочного экрана, который нужно отобразить как можно быстрее.
Если вы желаете, чтобы прелоадинг осуществлялся для всего содержимого, достаточно просто создать пустую сцену, в которой будет вызываться Application.LoadLevel(1) , и в окне настроек сборки сделать её первой в списке сцен (чтобы индекс был 0). Все последующие уровни будут загружаться с прелоадингом.
Вы готовы собирать игры
На данный момент вы изучили, как использовать интерфейс Unity, как использовать ассеты, как создавать сцены и как публиковать ваши сборки. Теперь вас ничто не останавливает от создания игры вашей мечты. Мы уверены, что по пути вам ещё предстоит многое узнать, и мы всегда рядом, чтобы помочь вам во всём разобраться.
Для дополнительной информации о том, как создавать игровые уровни, см. раздел Построение сцен.
Для дополнительной информации о написании скриптов для вашей игры, см. раздел Скриптинг.
Для дополнительной информации о создании графических ассетов, см. раздел Импорт и создание ассетов данного руководства.
Для общения с другими пользователями Unity, посетите Unity Forums. Там вы можете задавать вопросы, делиться проектами, строить команду, можете делать там всё, что вы захотите. Обязательно загляните на форумы хотя бы один раз, потому что мы хотим посмотреть на невероятные игры, которые вы создадите.
Как создать игру на Unity


Владимир Филимонов Эксперт в медицинских тренажерах VR на Unity, физических симуляциях и сетевых играх.
Сделать игру на Unity сможет даже начинающий кодер, который не знает С#. Большое количество обучающих материалов и активное комьюнити значительно облегчают первые этапы знакомства с движком и создание первого проекта. Вместе с ведущим разработчиком Unity Владимиром Филимоновым и преподавателем на курсе «Разработчик игр» разбираемся, почему писать код — не главное в геймдеве и какие базовые инструменты и ПО в играх нужно освоить, чтобы соорудить свою первую игру.
Что такое Unity
Unity — это и среда разработки, и игровой движок, с помощью которого создаются проекты для разных платформ: ПК, мобильных устройств, игровых консолей и интернет-платформ, — поэтому он называется кроссплатформенным. В Unity есть инструменты для создания объектов, их перемещения, работы с графикой, текстурами и звуком, поэтому сделать полноценную игру с его помощью можно даже в одиночку. Наглядный пример игры, созданной на Unity, которая поддерживает разные устройства, — Genshin Impact, успешный мультиплатформенный проект китайской студии miHoYo Limited. Более популярной стала ее мобильная версия, но пользователи могут войти в аккаунт, например, с компьютера и продолжить играть с того же момента, на котором остановились в мобильной версии. Кроме Genshin Impact, на Unity созданы такие известные проекты, как Hearthstone, Outlast, Cuphead, Pokemon GO и многие другие.

Освойте профессию «Разработчик игр на Unity»
Разработчик игр на Unity
Все главные навыки разработчика игр на одном курсе. Вы освоите все этапы геймдизайна, научитесь программировать на С# и создадите 7 игр во время курса.

Профессия / 18 месяцев
Разработчик игр на Unity
Создавайте виртуальные миры
5 399 ₽/мес 9 817 ₽/мес

- имеет практически неограниченный бесплатный функционал;
- не требует глубокого знания языков программирования для создания первых простых проектов;
- имеет многочисленное и активное сообщество, в котором можно найти ответ на любой вопрос, потому что среди такого большого количества людей кто-то обязательно уже сталкивался с вашей проблемой.
Читайте также Как скачать и установить Unity
Как создать простую игру
При создании собственного проекта важно помнить, что разработка кода — это примерно 20% игры; гораздо большее значение в ней имеют другие аспекты:
- Геймплей — это общее понятие взаимодействия игрока с игровым миром, которое определяет его действия (бежать вперед, преодолевать препятствия, стрелять по мишеням, обгонять других) и цели (прийти первым к финишу, выбить 10 из 10, победить врага в бою, собрать как можно больше монет). Геймплей напрямую связан с жанром игры, так как у каждого из них есть специфичный набор правил и механик.
- Игровые механики— конкретные элементы взаимодействия с игрой, которые входят в состав геймплея. Стрельба — это одна механика, сражение на мечах — другая, гонка — третья. Одна игра может сочетать в себе десятки таких механик.
- Сюжет— это развитие действия в игре; он одинаково важен и для масштабных AAA-проектов, и для небольших, но глубоких инди-игр. Сюжет должен затянуть игрока, рассказать ему историю, а также развивать персонажей, чтобы они не оставались однобокими и раскрывались для игрока с новых сторон.
- Персонажи — в них важны и дизайн, и характер. Удачно проработанный персонаж обладает узнаваемыми особенностями поведения, интересной историей, а еще для полного погружения он должен иметь что-то общее с игроком, что зацепит его и заставит сопереживать. На эту тему Unity разработали гайд «Пять типов привлекательных игровых персонажей», чтобы у новичков получалось сделать игрового персонажа правдоподобным.
- Дизайн уровней— это внешний вид игры, цветовые решения, общая стилистика объектов, фона, персонажей, предметов, которая создает определенное настроение. В помощь начинающим разработчикам Unity опубликовали в своем блоге «Советы по дизайну уровней вашей первой видеоигры».
- Баланс — это соотношение характеристик разных объектов, он тоже отвечает за увлеченность игрока. Например, если меч в игре может наносить объекту 3 единицы урона, а объект имеет всего 3 HP (hit points — величина, обозначающая максимальный урон), то его можно уничтожить с первого раза, и играть будет слишком легко. Если объект имеет 30 HP, то игроку придется нанести 10 ударов, чтобы его уничтожить. Такое уже подходит скорее для босса, например на первом или втором уровне. Разработчику важно грамотно распределить эти величины, чтобы игра была увлекательной и бросала игроку вызовы.

Разработчик игр на Unity – одна
из самых творческих профессий в IT. Создайте виртуальные миры уже через полгода обучения
Перед созданием игры важно продумать все эти моменты и представить общую картину, а также найти референсы, на которые можно ориентироваться, продумать опорные точки сюжета и механики. Для создания игры именно на Unity также пригодится понимание некоторых базовых терминов, с которыми постоянно придется сталкиваться в процессе разработки:
- Ассет (Asset)— готовый компонент, который можно использовать для создания своих проектов. Это могут быть элемент интерфейса в игре, текстура, фигурка персонажа, шрифт или звук.
- Игровой объект (GameObject)— это любой ассет, который используется в игровой сцене. Например, изображение монетки, сам ее внешний вид — это ассет, а пять монет, которые должен подобрать персонаж в процессе прохождения уровня — это пять игровых объектов. Сам персонаж при этом тоже станет игровым объектом.
- Компоненты (Components) — часть игрового объекта, отвечающая за его поведение в процессе игры: перемещение или реакцию на определенные триггеры.
- Скрипт (Script)— код на C#, в котором прописаны конкретные условия работы компонента.
Установка Unity занимает 5–10 минут. Для этого нужно зайти на официальный сайт проекта и выбрать бесплатный тариф для физических лиц — Personal. Его будет достаточно для самостоятельного изучения Unity и создания первой игры. Еще один бесплатный тариф — студенческий, но он подойдет тем, кто зарегистрирован на GitHub и может подтвердить свой ученический статус.
После нажатия кнопки «Начать» откроется Unity Store. Для новых пользователей в нем есть вариант установки движка с обучающим руководством для начинающих. С помощью кнопки «Начните здесь» скачивается установщик UnityHubSetup.exe, который запускается как любой другой установщик: нужно просто открыть файл, принять условия пользовательского соглашения и нажать кнопку «Установить».
Русского языка в настройках нет, так что придется совершенствовать технический английский. Всего Unity занимает 11,3 Гб,поэтому перед установкой лучше проверить свободное место на диске и почистить его при необходимости.
Следующий шаг — создание Unity ID. Можно регистрироваться с помощью почты или использовать предложенные аккаунты, например Google или Apple. Важно поставить первые две галочки: согласие с условиями использования Unity и признание политики конфиденциальности. Третья галочка — это согласие на маркетинговые рассылки, ее ставить не обязательно.

После регистрации Unity предложит создать тестовый проект Microgame. На выбор предлагается пять шаблонов:
- LEGO Microgame;
- шутер от первого лица;
- картинг;
- платформер;
- пустой 3D-шаблон.
Можно выбрать любой из них и посмотреть, как работает создание игры в конкретном жанре. Обучающий материал пошагово демонстрирует назначение различных окон в интерфейсе и принцип работы с элементами игры: как заставить двигаться персонажей, поменять текстуру объекта или его форму. В обучении окно Scene, в котором происходит вся работа с элементами, уже заполнено различными объектами, но при создании проекта с нуля оно будет пустым.
Создание проекта
После обучения можно перейти к созданию своей первой игры на Unity с помощью кнопки NEW в меню проектов.
Новому проекту присваивается имя, выбираются место хранения на диске и темплейт — то есть шаблон для разработки, внешний вид и функционал которого зависит от количества измерений в игре. Проще начинать с 2D-проектов, так как для этого формата создано больше готовых ассетов. Конечно, можно сразу начать делать 3D-игры, но в этом случае многие элементы и анимации придется самостоятельно создавать с нуля или выделять бюджет на то, чтобы делегировать эту часть работы другим специалистам.
Настройка интерфейса
В стандартном интерфейсе проекта шесть элементов рабочей области:

- Верхняя панель инструментов— в ней находятся стандартные вкладки File, Edit, Help, как во многих других интерфейсах, а также вкладки Assets, GameObject, Components и Window.
- Scene — окно сцены, в котором выстраивается игровое пространство (элементы игрового мира, текстуры, фигурки персонажей и прочее).
- Games — это окно игры, в котором можно посмотреть глазами пользователя, как будут двигаться элементы и работать игровые механики.
- Hierarchy — окно иерархии, в нем перечислен список всех элементов (GameObject), которые помещены в окно Scene.
- Project — это система папок, в которых хранятся ассеты по категориям (текстуры, шрифты, звуки и т.д.).
- Inspector — окно для изменения элементов игры, их размера, цвета, положения в пространстве и других характеристик.
Добавление объекта
Объекты на экран Scene можно добавить из Asset Store. Для этого на панели инструментов нужно кликнуть на вкладку Window –> General –> Asset Store.
В строке поиска можно по названиям найти нужные компоненты, например, сет Free Platform Game Assets.
Как и другие ассеты, он загружается с помощью кнопки Import.
Перед загрузкой появится список всех компонентов, которые содержит этот пакет; некоторые из них можно исключить. Если в списке есть персонажи, текстуры или другие элементы, которые вам не нужны, можно просто снять галочки, и пакет загрузится без них.
После установки все ассеты будут доступны в окне Project. Теперь можно комбинировать и перемещать эти объекты, менять их форму, причем сделать это можно с помощью мыши или горячих клавиш, не написав ни одной строчки кода. Например, из перечня платформ самых разных видов можно выбрать одну и мышкой перетащить ее в рабочую область.
Шаг 2. Перенести в область Scene

Работа со скриптами
За поведение игровых объектов отвечают присоединенные к ним компоненты (Components). Базовый компонент любого объекта — Transform, он отвечает за положение элемента в окне Scene, возможность поворачивать и масштабировать его. К базовому компоненту можно добавить, например, Renderer, который меняет цвет, или RigidBody, который отвечает за массу и физику объекта. Но кроме базовых компонентов, объектам можно задавать особые условия, и для этого как раз используются скрипты.
Создать новый скрипт можно в окне Project, кликнув мышкой на Assets –> Create –> C# Script.
Двойным кликом мыши скрипт открывается в текстовом редакторе. Скрипты, как и все остальное в Unity, прописываются на С#, так что для создания сложных проектов разработчикам все же придется освоить этот язык программирования.
Базовые элементы скриптов — это:
- using — элемент в коде, который подключает библиотеки;
- public class — в этой строке обычно прописан класс MonoBehaviour, он содержит набор функций, необходимых для работы скрипта;
- void — те самые функции, с их помощью прописываются действия, происходящие в игре.
Рассмотрим, например, функцию start. Любое действие в ней произойдет только один раз, когда запустится игра. Пропишем здесь print (“Hi”).
И можно заметить, что в консоли это слово выводится один раз.
Функция update — повторяющаяся, ее можно использовать, например, для передвижения объекта. Для этого в скрипте задается переменная int i = 0, она выводится на экран с помощью функции print (i) и увеличивается на одну единицу за каждый шаг с помощью i++.
В консоли можно будет заметить, что апдейт действительно срабатывает каждый фрейм и объект, к которому применен этот скрипт, плавно движется.
Настройка триггеров
Для понимания сути триггеров важно усвоить, что такое коллайдер (Collider). Это компонент, который присваивается объекту в пространстве игры, задает форму и делает его твердым, недоступным для прохождения сквозь него. Например, если мы разместим монетку в 2D-пространстве и захотим сделать так, чтобы она упала на платформу, то без использования компонента Collider ничего не получится — монетка пролетит сквозь платформу.
Поэтому обоим объектам необходимо присвоить компонент Box Collider 2D — это тонкая зеленая линия, которая обводит элементы по контуру, и за счет этой рамки они становятся твердыми, то есть один не может пройти сквозь другой.
Так объекты обязательно соприкоснутся и монета встанет на платформу.
Триггер (Trigger) — это пространство на карте, при попадании объекта в которое происходит действие; он тоже обводит объект или область в пространстве по краям. По сути, это тот же коллайдер, только триггер позволяет объектам проходить внутрь этой области. Представьте, что на ту же самую платформу вместе с коллайдером наброшен триггер, и при попадании персонажа внутрь триггерной области активируется телепорт — персонажа перебрасывает в другую точку карты.
Чтобы создать триггер, нужно накинуть тот же самый компонент коллайдера, но поставить галочку Is Trigger.

Триггеры распознают три варианта взаимодействия области на карте и объекта:
- OnTriggerEnter — объект зашел в зону;
- OnTriggerStay — объект находится в зоне;
- OnTriggerExit — объект покинул зону.
Что дальше?
Освоить интерфейс Unity довольно легко, в интернете есть разные гайды на тему того, как сделать это действительно быстро. Например, видео «Я сделал игру на Unity за неделю» или обучающий мини-курс «Как создать RPG за час». Можно изучать геймдев самостоятельно или начать обучение на курсе — это ускорит процесс и даст более заметные результаты.
Для работы со скриптами и создания более сложных механик разработчикам в любом случае понадобится С#, так что к его изучению вы тоже рано или поздно придете. Но в отличие от Unity, по C# нет в свободном доступе такого большого количества актуальных и понятных гайдов, так что в целях экономии времени и сил лучше записаться на курс «Разработчик игр на Unity», где все знания упакованы в структурированные блоки и сбалансированы с практикой на тренажерах.
Основы многопользовательской игры на Unity3D

Я, как и многие из вас, большой поклонник многопользовательских игр. В них меня прельщает в основном дух соревнования и возможность приобретать улучшения, накапливая достижения. Да и сама идея выхода в свет все большего количества игр данного типа побуждает к действию.
С недавнего времени я и сам взялся за разработку собственного проекта. И поскольку на Хабрахабре статей на эту тематику не нашел – решил поделиться своим опытом написания многопользовательской игры на движке Unity3D. Также хочу рассказать о компонентах Network и NetworkView, атрибуте RPC и встроенных методах-ивентах. В конце статьи подан пример игры и, разумеется, сам проект для Unity. Итак…
Класс Network
Данный класс нужен для организации соединения «клиент-сервер». Основные функции: создание сервера, подключение к серверу, создание сетевого экземпляра префаба.
Основные методы:
Network.Connect (string host, int remotePort, string password = «») – выполняет подключение к серверу host с портом remotePort и паролем password. Метод возвращает перечисление NetworkConnectionError.
Network.InitializeServer(int connections, int listenPort, bool useNat) – создает сервер с максимально разрешенным количеством подключений connections; порт входящих подключений listenPort, а также useNat: использовать либо нет NAT . Также возвращает перечисление NetworkConnectionError.
Network.InitializeSecurity() – вызывается перед Network.InitializeServer() для защиты от читерства. Подробности в официальной документации. Не вызывать на клиенте!
Network.Instantiate(Object prefab, Vector3 position, Quaternion rotation, int group) – создает экземпляр префаба prefab в сети в позиции position с поворотом rotation и группой group. Возвращает весь созданный объект, с которым после создания можно выполнить дополнительные действия. Подробности – далее в статье.
Основные свойства:
bool Network.isClient и bool Network.isServer – определяют, является ваша игра сервером либо клиентом. Оба свойства являются false, если не был создан сервер или не было подключения к серверу.
string Network.incomingPassword – свойство задает пароль для входящих подключений.
NetworkPlayer Network.player – возвращает экземпляр локального игрока NetworkPlayer.
NetworkPeerType Network.peerType – возвращает текущее состояние подключения: Disconnected (отключен), Server (запущен как сервер), Client (подключен к серверу), Connecting (попытка, в процессе подключения).
NetworkPlayer[] Network.connections – возвращает всех подключенных игроков. На клиенте возвращает только игрока сервера.
Основные ивенты (для унаследованного от MonoBehaviour):
OnConnectedToServer() – вызывается на клиенте при успешном подключении к серверу.
OnDisconnectedFromServer(NetworkDisconnection info) – вызывается на клиенте при отключении от сервера и на сервере при завершении подключений Network.Disconnect(). В info содержится причина отключения: LostConnection (потеря связи) и Disconnected (при успешном отключении).
OnFailedToConnect(NetworkConnectionError error) — вызывается на клиенте при ошибке подключения. error содержит ошибку типа NetworkConnectionError.
OnNetworkInstantiate(NetworkMessageInfo info) — вызывается на клиенте и сервере, если был создан новый экземпляр методом Network.Instantiate(). Содержит info типа NetworkMessageInfo.
OnPlayerConnected(NetworkPlayer player) — вызывается на сервере при успешном подключении клиента и содержит player типа NetworkPlayer.
OnPlayerDisconnected(NetworkPlayer player) — вызывается на сервере при отключении клиента и содержит player типа NetworkPlayer.
OnServerInitialized() — вызывается на сервере, после того как сервер был успешно создан.
OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) — важный ивент для синхронизации компонента с сетью. Подробности – далее в статье.
Класс NetwokView
Данный класс существует также и как компонент для Unity, и предназначен он для синхронизации компонентов в сети и для вызова RPC .
Обладает такими свойствами синхронизации NetworkStateSynchronization:
- Off — не выполняет синхронизацию объекта, однако позволяет вызывать удаленные процедуры.
- ReliableDeltaCompressed — выполняет передачу пакетов поочередно и проверяет, доставлен ли пакет (подобно протоколу TCP).
- Unreliable — выполняет быструю отправку пакетов, не гарантируя доставки (подобно протоколу UDP).
Основные методы:
networkView.RPC(string name, RPCMode mode, params object[] args) — вызывает удаленную процедуру name, mode определяет получателей, args – аргументы для передачи процедуре.
networkView.RPC(string name, NetworkPlayer target, params object[] args) – то же, что и предыдущий метод, однако выполняет отправку конкретному игроку NetworkPlayer.
Основные свойства:
bool networkView.isMine – свойство, определяющее, является ли объект локальным. Весьма часто используется для проверки владельца объекта.
Component networkView.observed – компонент, который будет синхронизироваться. Если это скрипт, то он должен содержать метод OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info), упомянутый выше.
NetworkPlayer networkView.owner – свойство, возвращающее владельца объекта.
NetworkStateSynchronization networkView.stateSynchronization — тип синхронизации: Off, ReliableDeltaCompressed, Unreliable.
NetworkViewID networkView.viewID — уникальный идентификатор в сети для NetworkView.
Атрибут RPC
Согласно данным из Википедии RPC — класс технологий, позволяющих компьютерным программам вызывать функции или процедуры в другом адресном пространстве (как правило, на удалённых компьютерах).
Атрибут используется для назначения метода, вызываемого из сети. Для его функционирования необходимо добавить компонент NetworkView.
Метод OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
Данный метод используется для синхронизации компонента в сети. Он вызывается всякий раз при получении либо отправке данных по сети.
Вот типы данных, которые могут быть получены/отправлены методом Serialize: bool, char, short, int, float, Quaternion, Vector3, NetworkPlayer, NetworkViewID.
Для проверки, идет ли прием либо передача, используются свойства isReading или isWriting.
Привожу пример использования:
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) < Vector3 syncPosition = Vector3.zero; // обязательно должен быть инициализирован перед приемом if (stream.isWriting) < syncPosition = rigidbody.position; // считываем текущую позицию stream.Serialize(ref syncPosition); // синхронизируем с сетью >else < stream.Serialize(ref syncPosition); // получаем позицию из сети rigidbody.position = syncPosition; // записываем позицию в наш объект. >>
Данный пример не идеален, поскольку при его работе наши объекты будут «дергаться». Чтобы избежать этого, нужно воспользоваться интерполяцией. Подробнее – далее в статье.
Интерполяция
Суть интерполяции заключается в том, что между чтением положения из сети мы плавно перемещаем наш объект через функцию Lerp во время обновления экрана.
Берем текущую позицию как начало и синхронизированную — как конец, и по мере обновления кадров перемещаем наш объект.

Подробнее о методах оптимизации синхронизации по сети смотрите на сайте разработчиков: Valve Developer Community — Source Multiplayer Networking
Пример многопользовательской игры
Итак, имея представления об основах, можно приниматься за написание небольшой многопользовательской игры. В качестве примеров я использую разные способы применения NetworkView. Вам остается лишь выбрать для себя наиболее удобный способ.
Создаем скрипт ServerSide.cs и пишем туда следующее:
using UnityEngine; using System.Collections; [RequireComponent( typeof( NetworkView ) )] // сообщает Unity о том, что нам нужен компонент NetworkView. Данному компоненту NetworkStateSynchronization можно выставить Off. public class ServerSide : MonoBehaviour < private int playerCount = 0; // хранит количество подключенных игроков public int PlayersCount < get < return playerCount; >> // публичный доступ для внешних компонентов относительно количества игроков на сервере void OnServerInitialized() < SendMessage( "SpawnPlayer", "Player Server" ); // создаем локального игрока сервера >void OnPlayerConnected( NetworkPlayer player ) < ++playerCount; // при подключении каждого нового игрока увеличиваем количество подключенных игроков networkView.RPC( "SpawnPlayer", player, "Player " + playerCount.ToString() ); // вызываем у игрока процедуру создания экземпляра префаба >void OnPlayerDisconnected( NetworkPlayer player ) < --playerCount; // уменьшаем количество игроков Network.RemoveRPCs( player ); // очищаем список процедур игрока Network.DestroyPlayerObjects( player ); // уничтожаем все объекты игрока >>
Теперь создаем скрипт клиента ClientSide.cs:
using UnityEngine; using System.Collections; [RequireComponent( typeof( NetworkView ) )] // сообщает Unity о том, что нам нужен компонент NetworkView. Данному компоненту NetworkStateSynchronization можно выставить Off. public class ClientSide : MonoBehaviour < public GameObject playerPrefab; // префаб игрока, который будет создан в процессе игры public Vector2 spawnArea = new Vector2( 8.0f, 8.0f ); // зона спауна private Vector3 RandomPosition < // случайная позиция в зоне спауна get < return transform.position + transform.right * ( Random.Range( 0.0f, spawnArea.x ) - spawnArea.x * 0.5f ) + transform.forward * ( Random.Range( 0.0f, spawnArea.y ) - spawnArea.y * 0.5f ); >> [RPC] // сообщает Unity о том, что данный метод можно вызвать из сети private void SpawnPlayer( string playerName ) < Vector3 position = RandomPosition; // делаем случайную позицию создания персонажа GameObject newPlayer = Network.Instantiate( playerPrefab, position, Quaternion.LookRotation( transform.position - position, Vector3.up ), 0 ) as GameObject; // создаем нового персонажа в сети newPlayer.BroadcastMessage( "SetPlayerName", playerName ); // задаем созданному персонажу имя (оно будет автоматически синхронизировано по сети) >void OnDisconnectedFromServer( NetworkDisconnection info ) < Network.DestroyPlayerObjects( Network.player ); // удаляемся из игры >>
Таким образом, клиентская и серверная логика есть, теперь для нее нужно сделать управление MainMenu.cs:
using UnityEngine; using System.Collections; public class MultiplayerMenu : MonoBehaviour < const int NETWORK_PORT = 4585; // сетевой порт const int MAX_CONNECTIONS = 20; // максимальное количество входящих подключений const bool USE_NAT = false; // использовать NAT? private string remoteServer = "127.0.0.1"; // адрес сервера (также можно localhost) void OnGUI() < if ( Network.peerType == NetworkPeerType.Disconnected ) < // если не подключен if ( GUILayout.Button( "Start Server" ) ) < // кнопка «запустить сервер» Network.InitializeSecurity(); // инициализируем защиту Network.InitializeServer( MAX_CONNECTIONS, NETWORK_PORT, USE_NAT ); // запускаем сервер >GUILayout.Space(30f); // отступ remoteServer = GUILayout.TextField( remoteServer ); // поле адреса сервера if ( GUILayout.Button( "Connect to server" ) ) < // кнопка «подключиться» Network.Connect( remoteServer, NETWORK_PORT ); // подключаемся к серверу >> else if ( Network.peerType == NetworkPeerType.Connecting ) < // во время подключения GUILayout.Label( "Trying to connect to server" ); // выводим текст >else < // в остальных случаях ( NetworkPeerType.Server, NetworkPeerType.Client) if ( GUILayout.Button( "Disconnect" ) ) < // кнопка «отключиться» Network.Disconnect(); // отключаем всех клиентов либо отключаемся от сервера >> > void OnFailedToConnect( NetworkConnectionError error ) < Debug.Log( "Failed to connect: " + error.ToString() ); // при ошибке подключения к серверу выводим саму ошибку >void OnDisconnectedFromServer( NetworkDisconnection info ) < if ( Network.isClient ) < Debug.Log( "Disconnected from server: " + info.ToString() ); // при успешном либо неуспешном отключении выводим результат >else < Debug.Log( "Connections closed" ); // сообщение выводится при выключении сервера Network.Disconnect() >> void OnConnectedToServer() < Debug.Log( "Connected to server" ); // сообщение выводится при успешном подключении к серверу >>
Управление сетью создано. Далее пишем управление игроком PlayerControls.cs. В данном примере я использую другой способ применения компонента NetworkView:
using UnityEngine; using System.Collections; [RequireComponent( typeof( Rigidbody ) )] // в данном примере нам понадобится Rigidbody public class PlayerControls : MonoBehaviour < /* для интерполяции */ private float lastSynchronizationTime; // последнее время синхронизации private float syncDelay = 0f; // дельта между текущим временем и последней синхронизацией private float syncTime = 0f; // время синхронизации private Vector3 syncStartPosition = Vector3.zero; //начальная позиция интерполяции private Vector3 syncEndPosition = Vector3.zero; // конечная позиция интерполяции private Quaternion syncStartRotation = Quaternion.identity; // начальный поворот интерполяции private Quaternion syncEndRotation = Quaternion.identity; // конечный поворот интерполяции private NetworkView netView; // компонент NetworkView private string myName = ""; // наше имя (для примера, мы его не используем) public string MyName < get < return myName; >> // публичный доступ к имени public float power = 20f; void Awake () < netView = gameObject.AddComponent( typeof( NetworkView ) ) as NetworkView; // добавляем компонент NetworkView нашему игровому объекту netView.viewID = Network.AllocateViewID(); // присваиваем уникальный идентификатор в сети netView.observed = this; // указываем этот скрипт (компонент) для синхронизации netView.stateSynchronization = NetworkStateSynchronization.Unreliable; // нам подходит способ быстрой передачи с потерями, поскольку наше передвижение интерполируется lastSynchronizationTime = Time.time; // последнее время синхронизации >void FixedUpdate () < if ( netView.isMine ) < // если объект принадлежит нам, то мы им управляем, в противном случае делаем интерполяцию движения float inputX = Input.GetAxis( "Horizontal" ); float inputY = Input.GetAxis( "Vertical" ); if ( inputX != 0.0f ) < rigidbody.AddTorque( Vector3.forward * -inputX * power, ForceMode.Impulse ); >if ( inputY != 0.0f ) < rigidbody.AddTorque( Vector3.right * inputY * power, ForceMode.Impulse ); >> else < syncTime += Time.fixedDeltaTime; rigidbody.position = Vector3.Lerp( syncStartPosition, syncEndPosition, syncTime / syncDelay ); // интерполяция перемещения rigidbody.rotation = Quaternion.Lerp( syncStartRotation, syncEndRotation, syncTime / syncDelay ); // интерполяция поворота >> void OnSerializeNetworkView( BitStream stream, NetworkMessageInfo info ) < Vector3 syncPosition = Vector3.zero; // для синхронизации позиции Vector3 syncVelocity = Vector3.zero; // для синхронизации действующей силы Quaternion syncRotation = Quaternion.identity; // для синхронизации поворота if ( stream.isWriting ) < // если отправляем в сеть, то считываем данные объекта перед отправкой syncPosition = rigidbody.position; stream.Serialize( ref syncPosition ); syncPosition = rigidbody.velocity; stream.Serialize( ref syncVelocity ); syncRotation = rigidbody.rotation; stream.Serialize( ref syncRotation ); >else < // в противном случае считываем из сети stream.Serialize( ref syncPosition ); stream.Serialize( ref syncVelocity ); stream.Serialize( ref syncRotation ); syncTime = 0f; // сбрасываем время синхронизации syncDelay = Time.time - lastSynchronizationTime; // получаем дельту предыдущей синхронизации lastSynchronizationTime = Time.time; // записываем новое время последней синхронизации syncEndPosition = syncPosition + syncVelocity * syncDelay; // конечная точка, в которую движется объект syncStartPosition = rigidbody.position; // начальная точка равна текущей позиции syncEndRotation = syncRotation; // конечный поворот syncStartRotation = rigidbody.rotation; // начальный поворот >> void SetPlayerName( string name ) < myName = name; // задаем имя игрока >>
Знаю, что синхронизация и управление должны находиться раздельно, но для примера я решил объединить их. Как вы заметили, здесь NetworkView создается во время инициализации скрипта. На мой взгляд, это более удобный способ для защиты от возможного «забыл добавить» (разумеется, если не написано RequireComponent( typeof( Rigidbody ))), а также уменьшает в инспекторе количество компонентов на объекте.
К примеру, у меня был случай: когда, на первый взгляд, все было сделано правильно, однако мой скрипт не делал интерполяцию, и все мои действия в синхронизации игнорировал. Так вот ошибкой оказалось то, что Observed был не моим скриптом, а трансформ объекта.
Итак, теперь у нас есть все необходимые скрипты для написания мини-игры.
Создаем пустой объект и назначаем ему скрипты MultiplayerMenu, ServerSide, ClientSide.
Создаем плоскость и немного опускаем.
Создаем префаб игрока (в моем примере это будут шары). Создаем объект «сфера», назначаем ему скрипт PlayerControls и добавляем в префаб. Префаб перетягиваем на ClientSide в поле Player Prefab.
На этом все, компилируем проект (не забывая в настройках игрока включить Run in background) и запускаем несколько раз. В одном из окон жмем сервер, на остальных – клиент, и смотрим на результат.
Ссылка на проект.
*В проекте могут быть логические ошибки, но на суть данной статьи они не влияют.
Всех благодарю за внимание!
Желаю успехов в создании многопользовательских игр!
Как создавать игры на Unity 3D? Гайд для новичков

Создание видеоигр — это невероятный способ самовыражения и воплощения своих идей в жизнь. Вам не нужны предварительные знания или опыт в разработке игр. Unity — популярный игровой движок, с которым могут работать даже новички. В статье мы рассмотрим, как создать игру на Unity.
1. Первым шагом будет создание рабочего пространства . Чтобы создать новое рабочее пространство проекта в Unity, откройте экран приветствия, затем нажмите кнопку «Новый» в левой нижней части окна. Дайте проекту имя, выберите место на компьютере, где вы хотите его сохранить, и выберите шаблон (мы рекомендуем «3D»).
2. Теперь пришло время создать свой игровой мир . В Unity есть множество инструментов. Чтобы добавить объекты, откройте панель Hierarchy в верхней левой части окна, затем выберите GameObject>, 3D Object в выпадающем меню. Вы можете выбрать одну из различных форм. Экспериментируйте с различными настройками в панели Inspector в правой части экрана, пока не добьетесь желаемого результата.
3. После того как вы создали свой игровой мир, пришло время добавить в него интерактивности . Здесь на помощь приходят сценарии Unity. Например, если вы хотите заставить персонажа двигаться вперед при нажатии клавиши со стрелкой влево на клавиатуре, вы можете добавить компонент Character Controller к GameObject вашего персонажа на панели Inspector, а затем использовать метод Move внутри него, чтобы заставить его двигаться.
4. Для создания более сложных взаимодействий между объектами в вашем мире попробуйте использовать систему Events. Это мощная система для запуска событий в Unity, которая позволяет отправлять сообщения между различными скриптами или даже запускать анимацию и другие спецэффекты. Чтобы начать работу с этой системой, просто выберите объект в сцене и откройте окно Events на панели Inspector. Эта система особенно полезна при создании игр с большим количеством взаимодействий между объектами и персонажами.
5. Наконец, если вы хотите добавить в свою игру искусственный интеллект (ИИ), Unity предлагает набор инструментов ИИ, таких как ML-Agents. ML-агенты позволяют быстро реализовать сложное поведение NPC в вашей игре, обучая их таким задачам, как навигация или распознавание объектов. Для обучения агентов необходимо создать среду, моделирующую поведение, которому вы хотите научить агента, а затем запустить симуляцию, позволяющую ему обучаться. Как только агенты прошли обучение, их можно протестировать в вашей игре. 
Чтобы создать игру на движке Unity , важно также разработать план создания игры еще до начала работы. Вот несколько советов:
1) Изучите информацию. Еще до начала разработки прочитайте учебники, посмотрите видеоруководства или поговорите с другими разработчиками, создавшими игры с помощью Unity. Ознакомьтесь с системой и узнайте о возможностях.
2) Планирование . Наметьте желаемые функции вашей игры, начиная с простых идей и постепенно включая более сложные элементы по мере развития вашего мастерства. Это позволит создать план для разработки вашей игры.
3) Создание. После того как вы разработали план, пора приступать к созданию. Настройте среду в Unity и начните создавать свою игру. Разбейте проект на небольшие части, чтобы каждую часть можно было завершить и протестировать, прежде чем переходить к следующей.
4) Тестирование и доработка . По мере создания и тестирования игры записывайте, что работает (и не работает). Обязательно регулярно сверяйтесь с первоначальным планом. При возникновении проблем или необходимости внесения изменений не бойтесь пересматривать свой план.
5) Завершающие штрихи. После того как вы протестировали и настроили свою игру, пришло время добавить последние штрихи. Добавьте музыку, звуковые эффекты и любые другие элементы, чтобы придать игре уникальность.
6) Публикация. Когда все готово, опубликуйте игру на выбранной вами платформе. Добавьте дополнительные привлекающие материалы, такие как скриншоты или прохождение, чтобы привлечь больше игроков. Если повезет, люди начнут играть и наслаждаться вашим творением.
7) Обратная связь. Наконец, важно получить обратную связь от ваших игроков. Спросите их, что им нравится или не нравится в игре. Выслушайте их предложения и используйте эту информацию для внесения необходимых улучшений. Это не только сделает игру лучше для ваших игроков, но и сделает вас лучшим разработчиком в долгосрочной перспективе. Не забудьте поблагодарить тех, кто нашел время оставить ценный отзыв.
Создание игр с помощью Unity может оказаться непростым процессом для новичков. Однако следование этому руководству поможет сделать процесс более легким и даст представление о том, как эффективно использовать мощный движок Unity. Тщательно планируя каждый шаг от разработки до публикации, каждый может создать интересную и увлекательную игру с помощью Unity. С помощью Unity ты можешь создать собственную игру на своем смартфоне , разработать трехмерную игру и приложение дополненной реальности . Все это предоставляет школа программирования CODDY. Знакомься с курсами от школы программирования CODDY, чтобы начать создавать свои миры.