Mirror unity как устроен

Обновлено: 09.05.2024


Хочу поделиться опытом с теми, кто хочет попробовать себя в написании сетевой игры, но не знает с чего начать. Так как информации по этой теме в интернете много, но полезную и актуальную было найти тяжело (а в русскоязычном сегменте и подавно), я решил собрать и структурировать то, что удалось найти.

Итак, для написания сетевой игры на Unity сейчас есть несколько вариантов:

UNet. Устаревшая сетевая технология. На данный момент deprecated и поддержка закончится в ближайшие пару лет. Но что же Unity предлагает взамен?

NetCode. Потенциально крутая технология, которая будет работать в связке с Entity Component System. Но очень уж медленно она развивается, за пару лет существования вышло 6 версий разной степени багованности, api постоянно меняется и делать что-то серьезное на нем пока рановато. Когда ее доделают – неизвестно. Я слежу за ней уже около года и особого прогресса не заметил.

Что тогда остается? Из бесплатных решений это:

MLAPI. Альтернатива UNet с широким спектром возможностей. Достойное решение, стоит к нему присмотреться.

Mirror. Доведенный до ума UNet, который потенциально может использоваться даже в MMO. Может работать как Клиент+Сервер, так и NoGUI-Сервер.

И платные решения (ознакомится с ними не удалось, напишите у кого был опыт как они):

Таблица преимуществ этих решений от Unity:


Мой выбор пал на Mirror, как на ближайший потомок UNet, использующий большинство принципов уже знакомого UNet. На примере простого проекта мы посмотрим основы Mirror, а именно:

NetworkMessage и spawn игрока в выбранной точке

Синхронизация переменных посредством SyncVar

Синхронизация переменных посредством SyncList

Spawn предмета и взаимодействие с предметом

3. Синхронизация переменных посредством SyncVar

Переходим к очень интересной фиче – SyncVar. Она позволяет избежать ручной синхронизации данных. Главное правило – меняем переменную только на сервере и не используем ее как данные (только как временное хранилище для данных, которые нам нужно обработать).

Для начала подготовим объекты, которые мы будем использовать для наглядной синхронизации. Например, здоровье в виде красных кружков. Открываем редактирование префаба Player и добавляем ему несколько объектов, представляющих собой жизнь (Knob + красный цвет). Располагаем их так, чтобы было хорошо видно.

Редактируем скрипт Player.cs, добавляем переменные:

Сохраняем, закидываем объекты-жизни в переменную HealthGos и выставляем такое же количество в переменной Health.


Добавляем в Update обновление объектов-жизней в соответствии с количеством жизней:

И переходим к методу на клиенте, который будет выставлять Health в соответствии с синхронизированным значением:

Теперь нам нужно сделать метод, который будет менять переменную _SyncHealth. Этот метод будет выполняться только на сервере.

Далее переходим к методу, который также будет выполняться на сервере, но клиент сможет запросить его выполнение:

Подробнее про Command и Rpc

Command используется для того, чтобы клиенты могли попросить сервер выполнить заданную команду.

Rpc используется для того, чтобы сервер мог попросить клиентов выполнить заданную команду.

Command можно вызывать на сервере+клиенте, но Rpc нельзя вызывать на клиенте.

Передавать в Rpc и Command можно только ограниченный набор типов.

Вызов Rpc в режиме сервер+клиент также выполнится на нем самом.

Все готово для синхронизации, зададим условия изменения жизней. На этом этапе сделаем простую схему – каждый игрок может только уменьшить свои жизни. Для этого дополним Update:

Этап завершен. Теперь у игроков всегда будет актуальное количество жизней, даже у тех, кто присоединяется позднее (после изменения количества жизней у других игроков).

Основы Unity + Mirror

Основы Unity + Mirror, изображение №1

Хочу поделиться опытом с теми, кто хочет попробовать себя в написании сетевой игры, но не знает с чего начать. Так как информации по этой теме в интернете много, но полезную и актуальную было найти тяжело (а в русскоязычном сегменте и подавно), я решил собрать и структурировать то, что удалось найти.

Итак, для написания сетевой игры на Unity сейчас есть несколько вариантов:

  • UNet. Устаревшая сетевая технология. На данный момент deprecated и поддержка закончится в ближайшие пару лет. Но что же Unity предлагает взамен?

Основы Unity + Mirror, изображение №2

  • NetCode. Потенциально крутая технология, которая будет работать в связке с Entity Component System. Но очень уж медленно она развивается, за пару лет существования вышло 6 версий разной степени багованности, api постоянно меняется и делать что-то серьезное на нем пока рановато. Когда ее доделают – неизвестно. Я слежу за ней уже около года и особого прогресса не заметил.

Что тогда остается? Из бесплатных решений это:

    . Альтернатива UNet с широким спектром возможностей. Достойное решение, стоит к нему присмотреться. . Доведенный до ума UNet, который потенциально может использоваться даже в MMO. Может работать как Клиент+Сервер, так и NoGUI-Сервер.

И платные решения (ознакомится с ними не удалось, напишите у кого был опыт как они):

Таблица преимуществ этих решений от Unity:

Основы Unity + Mirror, изображение №3

Мой выбор пал на Mirror, как на ближайший потомок UNet, использующий большинство принципов уже знакомого UNet. На примере простого проекта мы посмотрим основы Mirror, а именно:

  1. Настройка окружения
  2. NetworkMessage и spawn игрока в выбранной точке
  3. Синхронизация переменных посредством SyncVar
  4. Синхронизация переменных посредством SyncList
  5. Spawn предмета и взаимодействие с предметом

1. Настройка окружения

Для статьи будем использовать Unity 2020.3.0f1 и Mirror 32.1.4. Добавляем Mirror себе через Asset Store, создаем проект, импортируем Mirror (Window -> Package Manager -> Packages -> My Assets -> Mirror -> Import).

Для начала нам нужно создать префаб игрока. Создаем пустой GameObject (назовем его Player), вешаем на него SpriteRenderer, задаем sprite Knob и масштабируем чтобы лучше его рассмотреть. Далее создаем скрипт Player.cs и вешаем его на тот же GameObject. Редактируем скрипт следующим образом:

Подробнее про NetworkBehaviour и NetworkIdentity

Компонент NetworkIdentity добавится автоматически при добавлении скрипта, наследуемого от NetworkBehaviour.

В одном GameObject (и всех его потомках) может быть только один NetworkIdentity.

NetworkIdentity позволяет отличить один сетевой объект от другого (для этого используем netId - его значение всегда будет уникальным).

Добавляем компонент NetworkTransform, чтобы положение нашего игрока синхронизировалось между всеми игроками. Ставим галочку ClientAuthority, чтобы изменения произведенные клиентом, считались валидными.

Подробнее про NetworkTransform

Компонент NetworkIdentity также добавится автоматически при добавлении NetworkTransform (если его еще не было).

Если вам нужно синхронизировать потомков, добавляйте NetworkTransformChild на тот же объект, где уже есть NetworkIdentity, и указывайте в Target тот transform, который нужно синхронизировать.

Делаем из нашего GameObject префаб. Получилось что-то такое:


Далее создаем скрипт NetMan.cs, создаем пустой GameObject (назовем его NetMan) и вешаем на него скрипт. Это будет наш скрипт, который отвечает за старт сервера и подключение игроков.

Пока просто наследуем класс от NetworkManager, на этом этапе этого будет достаточно.

У нас в инспекторе появятся настройки сервера и добавится компонент KcpTransport. Докидываем на тот же GameObject компонент NetworkManagerHUD (он создает необходимое для подключения GUI).

Остановимся подробнее на настройках:

Don’t Destroy On Load. Будет ли объект существовать между сценами?

Run In Background. Будет ли компонент продолжать работать когда окно программы неактивно?

Auto Start Server Build. Будет ли сервер стартовать автоматически, если была выбрана опция билда «Server Build»?

Show Debug Messages. По этой опции не удалось разобраться или найти какую-то информацию.

Server Tick Rate. Количество обновлений сервера в секунду.

Server Batch Interval. Чем выше это значение, тем реже будет отправляться сетевая информация.

Теперь нам нужно указать префаб, который будет спавниться в качестве игрока. Перетаскиваем префаб Player в поле Player Prefab и после этого убираем его со сцены (оставляем только камеру и NetMan).


Первый этап готов. Выставляем выполнение в неполном экране (чтобы несколько экземпляров помещалось), делаем сборку, запускаем 2 экземпляра и проверяем. Один экземпляр стартуем как сервер, второй как клиент. На wasd двигаем своего персонажа, он успешно синхронизируется с другим экземпляром.

3. Синхронизация переменных посредством SyncVar

Переходим к очень интересной фиче – SyncVar. Она позволяет избежать ручной синхронизации данных. Главное правило – меняем переменную только на сервере и не используем ее как данные (только как временное хранилище для данных, которые нам нужно обработать).

Для начала подготовим объекты, которые мы будем использовать для наглядной синхронизации. Например, здоровье в виде красных кружков. Открываем редактирование префаба Player и добавляем ему несколько объектов, представляющих собой жизнь (Knob + красный цвет). Располагаем их так, чтобы было хорошо видно.

Редактируем скрипт Player.cs, добавляем переменные:

public int Health; public GameObject[] HealthGos;

Сохраняем, закидываем объекты-жизни в переменную HealthGos и выставляем такое же количество в переменной Health.

Основы Unity + Mirror, изображение №6

Добавляем в Update обновление объектов-жизней в соответствии с количеством жизней:

И переходим к методу на клиенте, который будет выставлять Health в соответствии с синхронизированным значением:

[SyncVar(hook = nameof(SyncHealth))] //задаем метод, который будет выполняться при синхронизации переменной int _SyncHealth; void SyncHealth(int oldValue, int newValue) //обязательно делаем два значения - старое и новое.

Теперь нам нужно сделать метод, который будет менять переменную _SyncHealth. Этот метод будет выполняться только на сервере.

[Server] //обозначаем, что этот метод будет вызываться и выполняться только на сервере public void ChangeHealthValue(int newValue)

Далее переходим к методу, который также будет выполняться на сервере, но клиент сможет запросить его выполнение:

[Command] //обозначаем, что этот метод должен будет выполняться на сервере по запросу клиента public void CmdChangeHealth(int newValue) //обязательно ставим Cmd в начале названия метода < ChangeHealthValue(newValue); //переходим к непосредственному изменению переменной >

Подробнее про Command и Rpc

  • Command используется для того, чтобы клиенты могли попросить сервер выполнить заданную команду.
  • Rpc используется для того, чтобы сервер мог попросить клиентов выполнить заданную команду.
  • Command можно вызывать на сервере+клиенте, но Rpc нельзя вызывать на клиенте.
  • Передавать в Rpc и Command можно только ограниченный набор типов.
  • Вызов Rpc в режиме сервер+клиент также выполнится на нем самом.

[ClientRpc] //обозначаем, что этот метод будет выполняться на клиенте по запросу сервера public void RpcTest() //обязательно ставим Rpc в начале названия метода

Все готово для синхронизации, зададим условия изменения жизней. На этом этапе сделаем простую схему – каждый игрок может только уменьшить свои жизни. Для этого дополним Update:

Этап завершен. Теперь у игроков всегда будет актуальное количество жизней, даже у тех, кто присоединяется позднее (после изменения количества жизней у других игроков).

Как создать зеркало в Unity 5

Сегодня я хочу показать вам, как легко можно создать зеркало в игровом движке unity 5. Для этого мы будем использовать всего лишь компонент camera и текстуру, созданную с помощью самого движка.

Начнем. Создадим новый проект в Unity и добавим несколько компонентов на сцену: стандартного персонажа (я буду использовать своего), Plane и Cube.

scene

mirrorscube

rendertexture

Переименуем ее и сразу и изменим размеры 1024 х 1024 для лучшего отображения качества изображения.

rendertextureinspector

Перенесем нашу текстуру на куб и добавим к нему камеру.

cameracube

Настроим ее так, чтобы она смотрела в нужную нам сторону и находилась чуть выше середины кубы (или на ваше усмотрение).

В настройках камеры в поле Target Texture необходимо указать нашу текстуру.

cameratexture

Проверяем что у нас получилось. На куб можно добавить коллайдер и подстроить немного камеру.

Русские Блоги

Indistinct —— Эффект отображения не ясен

Если найдено, отображение зеркала не ясно

Это потому что мы создали Render Texture При использовании разрешения по умолчанию 256 * 256

Это может быть изменено на более высокое разрешение, здесь я изменен на: 1024 * 1024 (в зависимости от ситуации)

举个栗子黑白88

Примечание. Чем выше разрешение, тем выше производительность.

Пока что: урок по созданию зеркала окончен

Project —— Файл проекта

Файл проекта unitypackage Пакет файлов:

Реализация зеркального эффекта Unity (зеркальный шейдер не требуется)

Учебное пособие по созданию зеркального эффекта Unity

Chinar Настаивайте на том, чтобы привнести в мир простой образ жизни!

Помогает быстро достичь простого эффекта зеркального отражения

Chinar Учебный эффект:

Полнотекстовые изображения в высоком разрешении, нажмите для увеличения (Многие люди даже не знают)

1

Create Mirror -Создать зеркало

В этом уроке нет необходимости самостоятельно искать зеркальный шейдер, для создания простого имитационного эффекта зеркального отражения в Unity можно использовать только 2 сценария.

1. Создать один в сцене Plane —— Используется как зеркало

2. Создайте шейдер одновременно /Material —— дать Plane на

3. Изменить только что созданный Material из Shader есть Unlit/Texture

举个栗子黑白88

2

Заключение

Надеюсь эти примеры помогут разобраться с азами работы с сетью в Unity. Знатоков этой темы призываю к обсуждению недочетов (про производительность и GC сейчас речь не идет). Полный проект можно скачать на гитхабе по этой ссылке.

5. Spawn предмета и взаимодействие с ним

На последнем этапе мы посмотрим как спавнить предметы и взаимодействовать с ними. Добавим нашему игроку возможность сделать пулями.

Создадим новый скрипт Bullet.cs:

Также создадим пустой GameObject + SpriteRenderer + Knob + меняем цвет. Вешаем на него скрипт Bullet.cs. Добавляем компонент NetworkTransform. Сохраняем как префаб Bullet.

В скрипт Player.cs добавляем спавн пули на сервере:

().Init(owner, target); //инициализируем поведение пули >

И запрос на свапн со стороны клиента:

[Command] public void CmdSpawnBullet(uint owner, Vector3 target)

Выставляем условие появления пули:

Добавим еще уничтожение игрока, если жизни закончились:

[Server] //обозначаем, что этот метод будет вызываться и выполняться только на сервере public void ChangeHealthValue(int newValue) < _SyncHealth = newValue; if (_SyncHealth

В настройках NetMan выставляем префаб Bullet как доступный для спавна:

Основы Unity + Mirror, изображение №7

Не забываем выставить префаб Bullet в переменную BulletPrefab префаба Player. Напоследок добавляем на префаб Player компонент CircleCollider2D и ставим галочку IsTrigger, чтобы пуля могла отловить попадание.

Последний этап завершен. Проверяем. По нажатию правой кнопки мыши из игрока вылетает пуля и летит туда, где стоял курсор. Если по пути пуля встречает другого игрока – он теряет одну жизнь. Все пули синхронизированы, даже если игрок подключился после их спавна.

using Mirror; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : NetworkBehaviour //даем системе понять, что это сетевой объект < [SyncVar(hook = nameof(SyncHealth))] //задаем метод, который будет выполняться при синхронизации переменной int _SyncHealth; public int Health; public GameObject[] HealthGos; SyncList

_SyncVector3Vars = new SyncList

(); //В случае SyncList не нужно ставить SyncVar и задавать метод, это делается иначе public List

.Operation.OP_CLEAR: < break; >case SyncList

.Operation.OP_INSERT: < break; >case SyncList

.Operation.OP_REMOVEAT: < break; >case SyncList

(_SyncVector3Vars.Count); //так как Callback действует только на изменение массива, for (int i = 0; i ().Init(owner, target); //инифиализируем поведение пули > [Command] public void CmdSpawnBullet(uint owner, Vector3 target) < SpawnBullet(owner, target); >>

3

May Be —— Занимайтесь когда-нибудь разработкой!

Chinar Обеспечить универсальное руководство, создать с закрытыми глазами!

70




Группа технического обмена: 806091680! Chinar Приглашаем вас присоединиться

Этот блог является некоммерческим личным оригиналом. За исключением некоторых работ с четкими подписями, авторские права на все опубликованные работы принадлежат мне, и я оставляю за собой все законные права. Правонарушители будут расследованы

Для использования статей и контента с явного разрешения и разрешения этого блоггера, пожалуйста, укажите источник статьи или контент и укажите URL при его использовании.

Заключение

Надеюсь эти примеры помогут разобраться с азами работы с сетью в Unity. Знатоков этой темы призываю к обсуждению недочетов (про производительность и GC сейчас речь не идет). Полный проект можно скачать на гитхабе по этой ссылке.

2. NetworkMessage и spawn игрока в выбранной точке

В настройках NetMan убираем галочку AutoCreatePlayer, дальше мы будем контролировать спавн игрока сами. Для этого мы изменим скрипт NetMan.cs. Начнем с создания struct с данными о позиции:

public struct PosMessage : NetworkMessage //наследуемся от интерфейса NetworkMessage, чтобы система поняла какие данные упаковывать < public Vector2 vector2; //нельзя использовать Property >

Далее создадим метод непосредственно спавна, который будет выполняется только на сервере:

(OnCreateCharacter); //указываем, какой struct должен прийти на сервер, чтобы выполнился свапн >

Создадим метод, который будет активировать спавн (и выполняться локально на клиенте):

И напоследок зададим условия для активации спавна:

В итоге получаем такой скрипт NetMan.cs:

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

4. Синхронизация переменных посредством SyncList

Синхронизировать одну переменную это конечно хорошо, но для серьезных проектов нам понадобится инструмент посерьезнее. SyncList позволяет синхронизировать массивы данных. Разберемся с ним на примере сохранения пройденного пути по нажатию кнопки (просто для наглядности). Редактируем скрипт Player.cs по аналогии с SyncVar.

Изменение массива на сервере:

_SyncVector3Vars = new SyncList

(); //В случае SyncList не нужно ставить SyncVar и задавать метод, это делается иначе [Server] void ChangeVector3Vars(Vector3 newValue)

Команда для запроса с клиента на сервер:

[Command] public void CmdChangeVector3Vars(Vector3 newValue)

И обработчик события изменения массива на клиенте:

Vector3Vars; void SyncVector3Vars(SyncList

.Operation op, int index, Vector3 oldItem, Vector3 newItem) < switch (op) < case SyncList

.Operation.OP_CLEAR: < break; >case SyncList

.Operation.OP_INSERT: < break; >case SyncList

.Operation.OP_REMOVEAT: < break; >case SyncList

Теперь перегрузим метод старта клиента:

(_SyncVector3Vars.Count); //так как Callback действует только на изменение массива, for (int i = 0; i

Синхронизация готова, но нам нужно задать условия изменения массива и визуализировать данные. Создадим пустой GameObject + SpriteRenderer + Knob + меняем цвет. Сохраняем как префаб Point.

Добавим компонент LineRenderer на префаб Player, выставим ему ноль позиций и немного уменьшим ширину. Отредактируем скрипт Player.cs:

public GameObject PointPrefab; //сюда вешаем ранее созданные префаб Point public LineRenderer LineRenderer; //сюда кидаем наш же компонент int pointsCount; void Update() < if (hasAuthority) //проверяем, есть ли у нас права изменять этот объект < . if (Input.GetKeyDown(KeyCode.P)) < if (isServer) ChangeVector3Vars(transform.position); else CmdChangeVector3Vars(transform.position); >> . for (int i = pointsCount; i

Как будут выглядеть Player и Point

using Mirror; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : NetworkBehaviour //даем системе понять, что это сетевой объект < [SyncVar(hook = nameof(SyncHealth))] //задаем метод, который будет выполняться при синхронизации переменной int _SyncHealth; public int Health; public GameObject[] HealthGos; SyncList

_SyncVector3Vars = new SyncList

(); //В случае SyncList не нужно ставить SyncVar и задавать метод, это делается иначе public List

.Operation.OP_CLEAR: < break; >case SyncList

.Operation.OP_INSERT: < break; >case SyncList

.Operation.OP_REMOVEAT: < break; >case SyncList

(_SyncVector3Vars.Count); //так как Callback действует только на изменение массива, for (int i = 0; i

Этап завершен, посмотрим на результат. Во время выполнения игрок может нажать клавишу P и его позиция отправится в массив для синхронизации всем игрокам. Также точки соединяться линией, чтобы маршрут был виден наглядно.

4. Синхронизация переменных посредством SyncList

Синхронизировать одну переменную это конечно хорошо, но для серьезных проектов нам понадобится инструмент посерьезнее. SyncList позволяет синхронизировать массивы данных. Разберемся с ним на примере сохранения пройденного пути по нажатию кнопки (просто для наглядности). Редактируем скрипт Player.cs по аналогии с SyncVar.

Изменение массива на сервере:

Команда для запроса с клиента на сервер:

И обработчик события изменения массива на клиенте:

Теперь перегрузим метод старта клиента:

Синхронизация готова, но нам нужно задать условия изменения массива и визуализировать данные. Создадим пустой GameObject + SpriteRenderer + Knob + меняем цвет. Сохраняем как префаб Point.

Добавим компонент LineRenderer на префаб Player, выставим ему ноль позиций и немного уменьшим ширину. Отредактируем скрипт Player.cs:

Как будут выглядеть Player и Point




Этап завершен, посмотрим на результат. Во время выполнения игрок может нажать клавишу P и его позиция отправится в массив для синхронизации всем игрокам. Также точки соединяться линией, чтобы маршрут был виден наглядно.

4

Create Cube -Создать куб

Чтобы увидеть эффект зеркала

Создать один в сцене Cube —— Используется как эталонный объект

举个栗子黑白88

Затем нажмите Run, и вы увидите, что зеркальный эффект завершен.

5

2. NetworkMessage и spawn игрока в выбранной точке

В настройках NetMan убираем галочку AutoCreatePlayer, дальше мы будем контролировать спавн игрока сами. Для этого мы изменим скрипт NetMan.cs. Начнем с создания struct с данными о позиции:

Далее создадим метод непосредственно спавна, который будет выполняется только на сервере:

Создадим метод, который будет активировать спавн (и выполняться локально на клиенте):

И напоследок зададим условия для активации спавна:

В итоге получаем такой скрипт NetMan.cs:

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

1. Настройка окуржения

Для статьи будем использовать Unity 2020.3.0f1 и Mirror 32.1.4. Добавляем Mirror себе через Asset Store, создаем проект, импортируем Mirror (Window -> Package Manager -> Packages -> My Assets -> Mirror -> Import).

Для начала нам нужно создать префаб игрока. Создаем пустой GameObject (назовем его Player), вешаем на него SpriteRenderer, задаем sprite Knob и масштабируем чтобы лучше его рассмотреть. Далее создаем скрипт Player.cs и вешаем его на тот же GameObject. Редактируем скрипт следующим образом:

Подробнее про NetworkBehaviour и NetworkIdentity

  • Компонент NetworkIdentity добавится автоматически при добавлении скрипта, наследуемого от NetworkBehaviour.
  • В одном GameObject (и всех его потомках) может быть только один NetworkIdentity.
  • NetworkIdentity позволяет отличить один сетевой объект от другого (для этого используем netId - его значение всегда будет уникальным).

Добавляем компонент NetworkTransform, чтобы положение нашего игрока синхронизировалось между всеми игроками. Ставим галочку ClientAuthority, чтобы изменения произведенные клиентом, считались валидными.

Подробнее про NetworkTransform

  • Компонент NetworkIdentity также добавится автоматически при добавлении NetworkTransform (если его еще не было).
  • Если вам нужно синхронизировать потомков, добавляйте NetworkTransformChild на тот же объект, где уже есть NetworkIdentity, и указывайте в Target тот transform, который нужно синхронизировать.

Делаем из нашего GameObject префаб. Получилось что-то такое:

Основы Unity + Mirror, изображение №4

Далее создаем скрипт NetMan.cs, создаем пустой GameObject (назовем его NetMan) и вешаем на него скрипт. Это будет наш скрипт, который отвечает за старт сервера и подключение игроков.

Пока просто наследуем класс от NetworkManager, на этом этапе этого будет достаточно.

using Mirror; using System.Collections; using System.Collections.Generic; using UnityEngine; public class NetMan : NetworkManager

У нас в инспекторе появятся настройки сервера и добавится компонент KcpTransport. Докидываем на тот же GameObject компонент NetworkManagerHUD (он создает необходимое для подключения GUI).

Остановимся подробнее на настройках:

Теперь нам нужно указать префаб, который будет спавниться в качестве игрока. Перетаскиваем префаб Player в поле Player Prefab и после этого убираем его со сцены (оставляем только камеру и NetMan).

Основы Unity + Mirror, изображение №5

Первый этап готов. Выставляем выполнение в неполном экране (чтобы несколько экземпляров помещалось), делаем сборку, запускаем 2 экземпляра и проверяем. Один экземпляр стартуем как сервер, второй как клиент. На wasd двигаем своего персонажа, он успешно синхронизируется с другим экземпляром.

6

поддержка

Main Camera —— Сценарий основной камеры (легко увидеть результаты теста)

Чтобы легко увидеть эффект зеркала после запуска, Chinar Сценарий от третьего лица представлен здесь

Используется для поворота объектива, чтобы увидеть разные направления

举个栗子黑白88

Необходимо установить на основную камеру, а Plane Перетащите в Pivot на

5. Spawn предмета и взаимодействие с ним

На последнем этапе мы посмотрим как спавнить предметы и взаимодействовать с ними. Добавим нашему игроку возможность стрелять пулями.

Создадим новый скрипт Bullet.cs:

Также создадим пустой GameObject + SpriteRenderer + Knob + меняем цвет. Вешаем на него скрипт Bullet.cs. Добавляем компонент NetworkTransform. Сохраняем как префаб Bullet.

В скрипт Player.cs добавляем спавн пули на сервере:

И запрос на свапн со стороны клиента:

Выставляем условие появления пули:

Добавим еще уничтожение игрока, если жизни закончились:

В настройках NetMan выставляем префаб Bullet как доступный для спавна:


Не забываем выставить префаб Bullet в переменную BulletPrefab префаба Player. Напоследок добавляем на префаб Player компонент CircleCollider2D и ставим галочку IsTrigger, чтобы пуля могла отловить попадание.

Последний этап завершен. Проверяем. По нажатию правой кнопки мыши из игрока вылетает пуля и летит туда, где стоял курсор. Если по пути пуля встречает другого игрока – он теряет одну жизнь. Все пули синхронизированы, даже если игрок подключился после их спавна.

Create Camera -Создать новую камеру

1. Создать новый Render Texture (Я переименовал Plane Легко отличить и понять)

2. Щелкните правой кнопкой мыши Иерархический список /Hierarchy -Создать новый Camera

3. новый Render Texture(Plane) Для новых Camera В компоненте Target Texture

4. Для новых Camera Камера, добавить скрипт ChinarMirrorPlane

и Main Camera и Plane Перетащите в Inspector В соответствующих свойствах на панели

5. Для новых Camera Камера, добавить скрипт ChinarMirror и Plane Перетащите в Inspector В панели

Примечание: обязательно измените Plane Свойства материала:

Конкретный процесс на самом деле очень прост, как следует

Оба сценария должны быть подключены к Camera :

Читайте также: