# Создание простой онлайн-игры с комнатами и синхронизацией

Этот урок охватывает весь цикл создания простой онлайн-игры на Unity с использованием SyncHubCloud: от подключения к серверу до синхронизации движения персонажей между клиентами.

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

***

### Сцена Menu

1. Переименуйте сцену в которой мы подключаемся к облачному серверу на “Menu”

2. Создайте на сцене поле для ввода текста UI InputFiled и назовите его “InputFieldNameRoom”

3. Создайте на сцене 2 кнопки UI Button и назовите их “ButtonCreateRoom” и “ButtonGetRooms”

4. Вот что по итогу у нас должно получиться:

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdXBEsJz86y8Rvl7S8gCEOgxK-VraUOuge03vGemeTuucztbxCXEHB23kHtmlFqSvLnVuZFsbXDykL1rHdHusUq4v8fd_mMNc96dhoofVjBugYILwyeDXBvn-e4m54xP3i5X7GaJg?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

5. Создайте скрипт “RoomsManager” и пустой объект на сцене “RoomsManager”, добавьте скрипт на этот объект

6. Откроем скрипт RoomsManager и напишем код для создания комнаты

```csharp
using UnityEngine;
using UnityEngine.UI;
using SyncHubCloud;

public class RoomsManager : MonoBehaviour
{
    // Поле для ввода названия комнаты
    public InputField InputFieldNameRoom;
    // Кнопка создания комнаты
    public Button ButtonCreateRoom;
    void Start()
    {
        //Назначаем событие на кнопку создания комнаты
        ButtonCreateRoom.onClick.AddListener(CreateRoom);
    }

    public void CreateRoom ()
    {
        // Проверяем подключены ли мы к серверу
        if(SyncHub_ConnectionManager.Instance.IsConnected)
        {
            // Проверяем ввели ли мы название комнаты
            if(string.IsNullOrEmpty(InputFieldNameRoom.text) == false)
            {
                /* Создаём комнату, первый параметр её название, второй параметр название сцены для неё и третий
                максимальное количество игроков */
                SyncHub_ConnectionManager.Instance.CreateRoom(InputFieldNameRoom.text, "Game", 5);
            }
        }
    }
}

```

7. Назначим объекты в инспектор скрипта “RoomsManager“

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe9RFLCC0HQanC_to-HCDMbNrxoUXbReW3XJMJWE6JEQfdAmwN7w0hFlyUFbIgYO8eOVU3kDYw01DjYyhpFR9cIaxr34W6tDQT0MWcuuSwcEx4DCtyt2FQeNXZY2d-JW4_YyQocBw?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

8. Теперь давайте запустим и попробуем создать комнату. Для этого введём её название и нажмём кнопку “Создать комнату”

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfMX8zOlrGWcdGgP2wpjYbHtgIvpSx90oirR5bxKGr0IzkaacZl11vcQxz0NVbGU_Z7N55O75mNZPanOsFX2ByZtBJzqzQ3bltTgS4RKScVxm3bwe5HvTPp1v3Go5pwfKBUfEqjiA?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

9. В результате мы получаем ошибку

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXejN0dFrUH5UV6danDr2m4EtKfdVzyezOvbgE8LIz4zUNpZFKMNQAehnELdcxrz0rRYBVxVj430cN6n2JDCJJS69M3MqE6edexQMbXbpFXqI6xcsRQjv9muMczCUafOmD0z2r0quA?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

   Так и должно быть, потому что мы ещё не создали сцену “Game” и SynHubCloud ругается на это

10. Давайте создадим простенькую цену Game и добавим на неё объект 3D Plane, это будет наш пол

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe5RRdpqmori0lB_Pn2GvaD1MRYjEDOnVev_32Ga2wAJPUVaQosUObCBGDgwW4M0vDXwhGmAVSmnZJUbzd8QHpT85O21KxKytWIh8mWx5jzegRN0icv4Nk4-MO5j3_kIBZV8DOSew?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

11. Обязательно добавьте сцену в сборку проекта

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcukcqVf3Zy96rmH5IVlRdZMMVtYdNgD2iuF8xWXoBTo9SBafID77Vh56hsgwoxSPSDGvjr1GVvj9uUs5vVRM4nWR6sfoabpe5zZGvNYgrRUuBdaSGQm-tgjfK5yXLCTZUYTocfcA?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

12. Снова запустим сцену Menu и попробуем создать комнату, вводим название комнаты и нажимаем создать комнату и нас сразу перебрасывает в сцену Game, после того как комната создалась на сервере

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe2lXkRyd7sY-ZDf8xQYxwM5-DNRrfqfipxVNpAw32LtQ9qcWmHVNtaasetJ-LfvrrzM9iNIIgM73uvWO9lh8UG3hV54ZzkjQKz5Mo8CYBGFwNy9g2cC0YbW2lrsSVhQwXkDKvBWg?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

13. Сейчас наша сцена Game пустая, давайте теперь создадим простейшего персонажа, для этого создайте 3D объект капсулу и назовём её “Player”, это будет наш персонаж

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcsuLzuGW3JChRU7oJ1q-gtt5XTBBps1Whj2zD6Z1GFr4pWePncI1lwDP_EHSGwL_8DuQZsghVm81DcMZZWTq8QjJBZplkKlhnzV05CnxT0z0sHmef3OH6Ex3HdOYcFO_E4U6sf?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

14. Теперь добавим на объект Player скрипт SyncHub\_ConnectionView (он уже есть в плагине SyncHub Cloud), этот скрипт нужно добавлять на все объекты которые будут синхронизироваться в режиме реального времени или принимать сообщения

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeTeVW2wpM1i3Hf4D1XeUI1KnFJLsFwbBOROVX5QMKxaaj8tvQjoTgZ8DYcS3O239P8Be1SP_C2GZdUAJSjdRAtAIzCA1uBk_fjg3wStx-Sot_b7sQKafzqTvJFGvZ4UjZvKrn0?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

15. Далее, создадим управление персонажем. Для этого создайте скрипт PlayerController.cs и напишите простейший код управления

```csharp
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    //Скорость перемещения игрока
    public float SpeedMove = 5f;

    
    void Update()
    {
        // перемещение вперёд - назад
        transform.position += Vector3.forward * SpeedMove * Input.GetAxis("Vertical") * Time.deltaTime;

        // перемещение влево - вправо
        transform.position += Vector3.right * SpeedMove * Input.GetAxis("Horizontal") * Time.deltaTime;
    }
}

```

16.Добавьте скрипт PlayerController.cs на объект Player чтобы у нас получилось вот так

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe26iOKFk2-oAstMD9siYibXseLfxqlUh7OxZRvplfaDNFSjnElxseK7yb9FvzRy2HDbX8JpEOx16ZlQ6LQstDDEnHH3MIBsa7X-RZWjd8SfHtABifE3dLCGIyzT8lsNCXRn56tCg?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

17. Теперь нам нужно из объекта Player сделать префаб, этот префаб будет использоваться для спавна всех игроков. Создайте в папке Assets папку SyncHubPrefabs и перенесите в эту папку объект Player, после удалите со сцены объект Player. Вот что у нас по итогу получится

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdnnYppKZzzu9m-3s5W2S9WWWNitTtjJffE8W6KNhesYvfOUjDsE8UUsP_l24SnDx-pnRfYSg6WGp8ij8neL7yOH4oI9KG8yfjELs0h52RozmPTQMZ7zM3TyrgN-TzazHcLdRtKIQ?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

18. И так, у нас есть уже игровой персонаж с управлением и он занесён в префаб, теперь нам нужно спавнить префаб игрока при подключении к комнате. Создайте скрипт GameManager.cs. На сцене создайте объект GameManager и добавьте на него созданный скрипт. Должно получится вот так:

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf5JBVrpeAB5zVLobiBQCSyXDk9k1JJ3FZC-CTNvXEQev8dvuohpxIGbREICAbZeGlMsxDFOlx-VzZrtZjDU_cv6_jagETqM9KDEJMxVE5ckPOZXueNLLNRUwSHpyVdEE7RU0A_?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

### Спавн игроков через GameManager

1. Теперь отредактируем скрипт `GameManager.cs`

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using SyncHubCloud;

public class GameManager : MonoBehaviour
{
    //Массив префабов персонажей игроков аттриубт "SyncHubPrefabPlayers" ОБЯЗАТЕЛЕН!
    [SyncHubPrefabPlayers]
    public List<GameObject> PrefabsPlayer = new List<GameObject>();

    //Массив префабов объектов  аттриубт "SyncHubPrefabObjects" ОБЯЗАТЕЛЕН!
    [SyncHubPrefabObjects]
    public List<GameObject> PrefabsGameObjects = new List<GameObject>();

    //Индекс нашего персонажа в массиве, на случай если у вас будет много разных персонажей в игре
    public int MyIndexPlayer;
    // Переменная для хранения нашего заспавненного персонажа
    public GameObject MyPlayerGM;

    private void Awake()
    {
        // Загружаем номер индекса персонажа который вы можете указать меню
        // (не обязательно, если у вас 1 префаб персонажа в массиве)
        MyIndexPlayer = PlayerPrefs.GetInt("SelectedIndexPlayer");

    }

    private void OnEnable()
    {
        // Подписываемся на событие когда всех игроков в комнате заспавнило кроме нашего
        SyncHub_ConnectionManager.OnSpawnedPlayers += OnSpawnedPlayers;
    }

    // отписываемся от всех событий при выходе из game сцены
    private void OnDisable()
    {
        SyncHub_ConnectionManager.OnSpawnedPlayers -= OnSpawnedPlayers;
    }

    private void OnSpawnedPlayers()
    {
        //получаем префаб персонажа из нашего массива
        GameObject myPlayerPrefab = PrefabsPlayer[MyIndexPlayer];

        //спавним нашего персонажа
        MyPlayerGM = SyncHub_ConnectionManager.Instance.SpawnMyPlayer(myPlayerPrefab, new Vector3(myPlayerPrefab.transform.position.x + Random.Range(-4, 4), myPlayerPrefab.transform.position.y, myPlayerPrefab.transform.position.z + Random.Range(-4, 4)));
        
    }

}

```

2. Добавляем префаб нашего персонажа в GameManager

<figure><img src="https://23499272-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTxnBGNcWcbXbuvDBMnXw%2Fuploads%2FuzgaxXCt1W65402ev3L9%2Fimage.png?alt=media&#x26;token=eba90576-0f43-47e0-801b-ec1d4b680089" alt=""><figcaption></figcaption></figure>

3. Запускаем сцену Menu и создаём комнату, после нас перекидывает в сцену Game и мы видим такой результат:

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXey-6CdiHdufo-6T-kv4aRH_omQ891QQiIqAW1IlYpHhDL9CYWyUw__kkimigcJSNZLMMI7FEtlWzDEH1_4tczYtw9bJljmLV4AdtU6qsEP-qtB-QrPTZP33TZSw2b-VLN_GUVXhQ?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

У нас создался экземпляр префаба нашего персонажа после создания и подключения к комнате и мы можем им управлять.

***

### Подключение к уже существующим комнатам

1. Что же, отлично, мы уже умеем создавать комнату и спавнить персонажей на сцене. Теперь нам нужно научиться подключаться к уже созданной комнате. Для этого вернёмся на сцену Menu. Создайте в нашем уже существующем Canvas объект UI ScrollView и назовите его ScrollViewListRooms, в этом скролле мы будем отображать список текущих комнат

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf8RGTgQhzttcB9FoRNouO-uS0cBFNFBKsJPOeLGUFOeBCw_HXZYGwJX3FHqtpynbzyaK_G7j2fArlfqN0RsBphFEwL7D-noVChflV7GugQ39v7uQR4tg-IWdiiRyw2HFq3rjWSIQ?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>
2. Разверните ScrollViewListRooms и в дочернем элементе создайте кнопку UI Button и назовите её ButtonRoom. Этот элемент как раз и будет кнопкой с описанием комнаты по нажатию на который мы будем подключаться к уже созданной комнате

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcpc9NxikorMzMV0XzAGnsT-RDsr0DGn90rjmcRveThIvbfa3b0to1aGu66lvzlsPMaWchKNJAnqU4-2yPzXYL5ZIEZNAkdnhjz8NmT2Ox6YJI_CHv6d4vVo1A7X1TccG3JY11iVg?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>
3. Теперь напишем скрипт для кнопки комнаты, для этого создайте скрипт `ButtonRoom.cs` и напишите в нём такой код

```csharp
using UnityEngine;
using UnityEngine.UI;
using SyncHubCloud;

public class ButtonRoom : MonoBehaviour
{
    //Переменная текста наименования комнаты
    public Text TextDescriptionRoom;
   
    public void SetDataRoom (string _nameRoom, int _currentPlayers, int _maxPlayers)
    {
        //Добавляем описание комнаты
        TextDescriptionRoom.text = string.Format($"Название комнаты: {_nameRoom} | Игроки: {_currentPlayers}/{_maxPlayers}");
        //Добавляем событие по клику кнопки на которой висит этот скрипт
        this.GetComponent<Button>().onClick.AddListener(delegate { ConnectToRoom(_nameRoom); });
    }

    public void ConnectToRoom (string _nameRoom)
    {
        //Подключаемся к комнате
        SyncHub_ConnectionManager.Instance.ConnectRoom(_nameRoom);
    }

}

```

4. Откройте префаб ButtonRoom и добавьте на него скрипт [ButtonRooms.cs](http://buttonrooms.cs), а после занесите текст кнопки в переменную скрипта

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdYxg0IBxcKVANcTtBsrvQI_TefwJsZDQiz6xBH7C0AiDY2moFuYqtxa9EkX9LZ6YsvKGuk0qi9yMUJ1cZ0C4R-CtLfpiZBEM5XLMPsBEdCYME1AHwEfcVYW8FjSOvGipSsTtVG?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption><p>Пример</p></figcaption></figure>

5. Создайте в Assets папку MenuPrefabs и занесите эту кнопку в префаб, а после удалите эту кнопку из Content на сцене

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdXfsIM7p4yhK0DkBPU5NaiSDu7743JQ024jzl-cFrwuP0fuCJZj28Oi93OBIoVhAefvHcXsAamB4N8bqf3JFfSf27gshHJFyzNMemmL_hF3ksfMyM977q1iF6Gr-GeRaDOUN_YNg?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

6. Вернёмся теперь к скрипту RoomsManager.cs, откроем его и допишем следующий код

```csharp
using UnityEngine;
using UnityEngine.UI;
using SyncHubCloud;

public class RoomsManager : MonoBehaviour
{
    // Поле для ввода названия комнаты
    public InputField InputFieldNameRoom;
    // Кнопка создания комнаты
    public Button ButtonCreateRoom;

    //Объект внутри которого будем спавнить кнопки комнат
    public Transform ContentScrollRect;
    // Кнопка для запроса текущих комнат на сервере
    public Button ButtonGetRooms;
    // Кнопка - префаб которую мы создали для вывода информации о комнатах
    public GameObject ButtonRoomPrefab;

    void Start()
    {
        //Назначаем событие на кнопку создания комнаты
        ButtonCreateRoom.onClick.AddListener(CreateRoom);

        //Назначаем событие на кнопку для запроса комнат
        ButtonGetRooms.onClick.AddListener(UpdateListRooms);
    }

    private void OnEnable()
    {
        //Подписываемся на событие получения списка комнат
        SyncHub_ConnectionManager.OnGetRooms += OnGetRooms;
    }

    //Отписываемся от всех событий
    private void OnDisable()
    {
        SyncHub_ConnectionManager.OnGetRooms -= OnGetRooms;
    }

    private void OnGetRooms(SyncHub_ConnectionManager.RootRooms _rooms)
    {
        for (int i = 0; i < _rooms.Data.Count; i++)
        {
            // Спавним кнопку в списке
            GameObject buttonRoom = Instantiate(ButtonRoomPrefab, ContentScrollRect);
            // Заносим данные комнаты в скрипт кнопки
            buttonRoom.GetComponent<ButtonRoom>().SetDataRoom(_rooms.Data[i].NameRoom, _rooms.Data[i].CurrentCountPlayers, _rooms.Data[i].CountMaxPlayers);
        }
    }

    public void CreateRoom ()
    {
        // Проверяем подключены ли мы к серверу
        if(SyncHub_ConnectionManager.Instance.IsConnected)
        {
            // Проверяем ввели ли мы название комнаты
            if(string.IsNullOrEmpty(InputFieldNameRoom.text) == false)
            {
                /* Создаём комнату, первый параметр её название, второй параметр название сцены для неё и третий
                максимальное количество игроков */
                SyncHub_ConnectionManager.Instance.CreateRoom(InputFieldNameRoom.text, "Game", 5);
            }
        }
    }

    public void UpdateListRooms ()
    {
        // Запрашиваем у сервера список комнат
        SyncHub_ConnectionManager.Instance.GetListRooms();
    }
}

```

7. Вернитесь в сцену Menu и занесите переменные в инспектор

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeZSERW98-OP0NMhk7cFtK3fzKZg1yYpxDmK-a4ngzQoakELTLX5OKvVvrq8T2fMV2m8qF_0v4o5-_ZNfeELSWK4BV7erYEJogLA4AgJbD_h0Puv9tLjdV44zbzDsdYnj_O5B1GgQ?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption><p>Пример</p></figcaption></figure>

8. Давайте теперь соберём сборку для Windows и запустим 2 клиента сразу. Заходим в File -> Build Settings, далее выбираем платформу Windows, потом заходим в Player Settings и устанавливаем оконный режим, что бы было нагляднее

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe2-JULrZ0DzQ7HVZqRjFaGVyOL4xWidd2CTdeg37DrDTNG6gMqR6pBS8IaO72Cipov-XKTx29xI5153WwoR6JKTGeljms9yKsc8OMK0OSd6cXytvKKRxjXw2Hl-nVYBCS5oPIt?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXckwmz4-7ewTD7N4zgNrbXUiyekXlY161fpwksDIpKJDggE6l_vwQHrccEaLoVpAmrQnuQmSwgT74KsPz2JFZpLr06rhRZHWuNrAjTawyNTUY8mwDlQ-PlJwA9BS27xvy-2yfNwNA?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

9. После сборки проекта, запустите 2 экземпляра клиента

   <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdhQYj2qgpj9dB5miikWcCwrmlLX59juzIpz1_uYuebLOX8YMdanzqAaDUobBUkCcVUR0R5Rh_OYKxPsl14yZTqFH2IEVFOVDO-p8LE3Kidee5eRXoKsYvW7fpr50L4nKprPmhc9w?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

10. Создайте на одном из клиентов комнату

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcs9TmYdHtUMH8KxBUnB5m37NWOiVjFHxqTcB5gw394-22gnhGLGrXV-xutTOjHBY6aUrwLk-WYA_U6APx6WZ6MAd55eFzqxEQTmsMOYJUqsxlyxE7x9b3K9EDCsdD9kPoDLEw4hw?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

11. На клиенте на котором была создана комната, мы попали в Game сцену

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeXXZoLekSnN8AM9EkZVBHEAhcjk9kPoiBpCqH18e8916AXqM3wMvFmOelGzSGdhx9xZxaq2YbS6yJnE21n4xDk5vPHdc_QhMiEY0orX7vUaz2sZ0SagKNqebgcMEmHx9QMs-Rv?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

12. Теперь на клиенте слева нажмите кнопку получить список комнат и у нас появится кнопка созданной комнаты, нажмите на неё, таким образом вы подключитесь к комнате созданной другим игроком (в данном случае Вами)

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfnges_qpvaVdfTFq0PB2zWxfRz158NjqHOBTwhIOFhfT53r-APqzghI4gVGXdqty7hXH4U_GQ3bn_KleSvqAL-lLJhHpiPSuwB6OlT8ihehuyXgIjI6gDrsTN5blTtlZd1cpDQ?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

13. После того как Вы подключились созданной комнате, Вы увидите примерно вот такую картину

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe4RgktSD8l1IY0k8Nzd1GOH92QAFa8o4ojx50HeY0BeK6JwSnUCd0_PN6-pems3ACJIARKLw-xpXkih086-Shy946fwna2zDlksqUsHsZa8yCf3XLBDbRtkKOpVzCbuQ-LXZxi?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

14. Если Вы попробуете управлять персонажем, то заметите что перемещаются оба префаба, хотя должен только Ваш персонаж (такое происходит потому что скрипт контроллера PlayerController.cs висит на 2 экземплярах префаба), исправить проблему поможет SyncHub\_ConnectionView\.IsMine(). Откройте скрипт PlayerController.cs и допишите такие строки:

```csharp
using SyncHubCloud;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    // переменная нашего скрипта SyncHub_ConnectionView который уже висит на префабе Player
    public SyncHub_ConnectionView syncHub_ConnectionView;

    //Скорость перемещения игрока
    public float SpeedMove = 5f;

    
    void Update()
    {
        // проверка если это наш префаб игрока
        if (syncHub_ConnectionView.IsMine())
        {
            // перемещение вперёд - назад
            transform.position += Vector3.forward * SpeedMove * Input.GetAxis("Vertical") * Time.deltaTime;

            // перемещение влево - вправо
            transform.position += Vector3.right * SpeedMove * Input.GetAxis("Horizontal") * Time.deltaTime;
        }
    }
}

```

15. Добавьте компонент SyncHub\_ConnectionView\.cs в переменную syncHub\_ConnectionView на префабе Player

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfe0S0fz8T_wXKdD0LdznFDhaCSiwlY_zTGAGcx9jv4MyO61E5WWuRbtcIyE-wz-t-AiAfFOFa5F3xVjb5Ng2v03rM6f2L1D3MP2ISIvidafiO_QebLtDdn2YExnlnxm7LWl0YY?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

16. Снова сделайте сборку и повторите запуск двух экземпляров клиента и после, увидите что, Вы можете управлять только своим персонажем. Но теперь у нас другая проблема, мы не видим перемещения позиции другого игрока

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcu2uEdAqEIXeNAvoBPbSIP0c-ljK5iBQKkDBkdx-DY8ftZRVXC-REGX078mDqqje_9dxwoKzynVIaW-Yp9e5IiA0jNuqh1beWfjf4KeajuLtWbxpQwD8okoui3iueA01zT-8EqfQ?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

17. Для этого нам нужно синхронизировать позиции игроков, есть несколько вариантов как это сделать, но самый простой и рекомендуемый, использовать компонент SyncHub\_SyncTransfrom.cs (Он есть в плагине SyncHub Cloud). Для этого выделите префаб Player и добавьте на него скрипт SyncHub\_SyncTransfrom.cs (ВАЖНО, там где Вы будете использовать SyncHub\_SyncTransfrom.cs обязательно должен присутствовать SyncHub\_ConnectionView\.cs). После его добавления, Вы увидите вот такие настройки:

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfc3Ll8-kd1v_D1u2GztzuY5-1Fa7bKlBx_2YHKKqNkDdP4SxVSNifIz2FXhEwFtrgwE0fqSri0UIK_jUj1om-ES_xllmjOdxFInNDw5HwGpa2rAOVAA1bZdJ_REFVKJ81s9K1Xsg?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

    Давайте их разберём чуть подробнее:\
    `IsSyncPosition` - Если нужна синхронизация позиций\
    `IsSyncRotation` - Если нужна синхронизация поворота\
    `IsSyncScale` - Если нужна синхронизация скейла (размера)\
    \
    `TypeInterpolationPos, TypeInterpolationRot, TypeInterpolationScale` - Тут Вы выбираете тип интерполяции, имеются такие настройки:\
    `Lerp` - Линейная интерполяция между двумя точками с плавным “торможение” к последней полученным значениям\
    `MoveTowards` - Интерполяция без плавного “торможения” к последним полученным значениям\
    `Instantly` - Жёсткая привязка к последним полученным данным без интерполяции (плавного перемещения, поворота и т.д.)

18. Укажем такие настройки:

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc3nTOhj_Yj6Xwd7rez7oc-HkExp-r6SQBJpLeWswDHY4YrtVF1ULPAHbopknKM4cdtN4SzEQoobIxnrcSI0xiXHffQT_H7IrVyOtP40iZ28-A07-tu6wXqCfs4NAaoitdR97aUxw?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

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

    <figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcTiaYzElYWouPvkvYrwYAgO_KAQwJV8fhzvMzyy8bfJTpTuff_ASZoTKn5YtAaOZLdepEztNkPJVvpSzqbLU4J3m7Y7lwqrSih06jMIDW7Nx9nPmzJGnz2Uw3X08K6coZpBH5d?key=VLNEpC8OQKn8xxgwf7UqYUpu" alt=""><figcaption></figcaption></figure>

20. На этом урок по созданию простой онлайн игры завершён. Вы научились из этого урока:
    * Как подключаться к серверу по токену
    * Как создавать комнату
    * Как получать список комнат и подключаться к ним
    * Как спавнить своего персонажа
    * Как спавнить персонажей которые уже есть в комнате
    * Как спавнить нового персонажа другого игрока который подключился к комнате
    * Как определить кому принадлежит экземпляр префаба
    * Как синхронизировать позиции, повороты и скейлы

***

В следующем уроке мы разберём **RPC и Stream в SyncHubCloud** — ключ к удалённым вызовам и потоковой передаче данных.
