Создание простой онлайн-игры с комнатами и синхронизацией
Введение SyncHubCloud — это мощное и гибкое SDK для Unity, разработанное для интеграции облачных сервисов в игровые и интерактивные проекты. Этот инструмент позволяет разработчикам легко подключаться
Этот урок охватывает весь цикл создания простой онлайн-игры на Unity с использованием SyncHubCloud: от подключения к серверу до синхронизации движения персонажей между клиентами.
Что мы будем делать?
Подключаться к серверу по токену
Создавать комнаты
Подключаться к существующим комнатам
Спавнить персонажей (включая других игроков)
Управлять персонажем
Определять владельца экземпляра префаба
Синхронизировать позиции и повороты
Готовить билд и проверять мультиплеер
Интерфейс сцены Menu
Убедитесь, что сцена называется Menu.
Добавьте UI-элемент InputField и назовите его InputFieldNameRoom.
Добавьте две кнопки:
ButtonCreateRoom — создание комнаты
ButtonGetRooms — получение списка комнат
Итоговая сцена должна включать:
SyncHub_ConnectionManager
InputFieldNameRoom
ButtonCreateRoom
ButtonGetRooms
Логика создания комнаты
Создайте C#-скрипт RoomsManager.cs.
Создайте пустой объект RoomsManager и добавьте на него этот скрипт.
Откройте RoomsManager.cs и добавьте следующий код:
RoomsManager.cs
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);
}
}
}
}
Назначьте в инспекторе InputFieldNameRoom и ButtonCreateRoom в скрипт RoomsManager.
Проверка создания комнаты
Запустите сцену Menu.
Введите название комнаты в поле InputFieldNameRoom.
Нажмите на кнопку Создать комнату.
Если вы не создавали сцену Game, вы получите ошибку — это ожидаемо.
Создание сцены Game и персонажа
Создайте сцену Game.
Добавьте 3D Object -> Plane (это будет пол).
Добавьте 3D Object -> Capsule, переименуйте в Player — имя обязательно.
Добавьте на него:
SyncHub_ConnectionView
Скрипт PlayerController.cs
PlayerController.cs:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// Скорость перемещения игрока
public float SpeedMove = 5f;
void Update()
{
// Движение вперёд-назад (ось Z)
transform.position += Vector3.forward * SpeedMove * Input.GetAxis("Vertical") * Time.deltaTime;
// Движение влево-вправо (ось X)
transform.position += Vector3.right * SpeedMove * Input.GetAxis("Horizontal") * Time.deltaTime;
}
}
Сделайте префаб из объекта Player и удалите его со сцены. Сохраните его в Assets/SyncHubPrefabs.
Спавн игроков через GameManager
Создайте скрипт GameManager.cs, добавьте на объект GameManager в сцене Game.
GameManager.cs:
using System.Collections.Generic;
using UnityEngine;
using SyncHubCloud;
public class GameManager : MonoBehaviour
{
// Список возможных префабов персонажей
public List<GameObject> PrefabsPlayer = new List<GameObject>();
// Индекс текущего выбранного персонажа
public int MyIndexPlayer;
// Ссылка на нашего заспавненного игрока
public GameObject MyPlayerGM;
private void Awake()
{
// Читаем выбранный индекс персонажа (если есть)
MyIndexPlayer = PlayerPrefs.GetInt("SelectedIndexPlayer");
// Запрашиваем список игроков в комнате
SyncHub_ConnectionManager.Instance.GetPlayersInRoom();
}
private void OnEnable()
{
// Подписываемся на события
SyncHub_ConnectionManager.OnGetPlayers += OnGetPlayers;
SyncHub_ConnectionManager.OnConnectedNewPlayerInRoom += OnConnectedNewPlayerInRoom;
}
private void OnDisable()
{
// Отписываемся от событий
SyncHub_ConnectionManager.OnGetPlayers -= OnGetPlayers;
SyncHub_ConnectionManager.OnConnectedNewPlayerInRoom -= OnConnectedNewPlayerInRoom;
}
private void OnGetPlayers(SyncHub_ConnectionManager.RootPlayers _players)
{
// Спавним нашего персонажа первым
GameObject myPlayerPrefab = PrefabsPlayer[MyIndexPlayer];
MyPlayerGM = SyncHub_ConnectionManager.Instance.SpawnMyPlayer(myPlayerPrefab, _players);
// Даем случайное смещение позиции
MyPlayerGM.transform.position += new Vector3(Random.Range(-4, 4), 0, Random.Range(-4, 4));
// Спавним всех остальных игроков
SyncHub_ConnectionManager.Instance.SpawnOtherPlayers(PrefabsPlayer, _players);
}
private void OnConnectedNewPlayerInRoom(string _connectionID, string _namePrefab)
{
// Спавним только что подключившегося нового игрока
SyncHub_ConnectionManager.Instance.SpawnConnectedNewPlayer(PrefabsPlayer, _namePrefab, _connectionID);
}
}
Добавляем префаб нашего персонажа в GameManager
Подключение к уже существующим комнатам
На сцене Menu создайте ScrollView, назовите ScrollViewListRooms.
Внутри Content создайте кнопку ButtonRoom.
Создайте скрипт ButtonRoom.cs, привяжите к кнопке.
ButtonRoom.cs:
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 = $"Название комнаты: {_nameRoom} | Игроки: {_currentPlayers}/{_maxPlayers}";
// Подключаемся при нажатии
this.GetComponent<Button>().onClick.AddListener(delegate { ConnectToRoom(_nameRoom); });
}
// Подключение к комнате
public void ConnectToRoom(string _nameRoom)
{
SyncHub_ConnectionManager.Instance.ConnectRoom(_nameRoom);
}
}
Сделайте префаб из кнопки в Assets/MenuPrefabs, удалите оригинал со сцены.
Расширьте RoomsManager.cs:
public Transform ContentScrollRect;
public Button ButtonGetRooms;
public GameObject ButtonRoomPrefab;
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)
{
foreach (var room in _rooms.Data)
{
// Спавним кнопки в списке
GameObject btn = Instantiate(ButtonRoomPrefab, ContentScrollRect);
btn.GetComponent<ButtonRoom>().SetDataRoom(room.NameRoom, room.CurrentCountPlayers, room.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();
}
Вернитесь в сцену Menu и занесите переменные в инспектор
Управление только своим персонажем
Если PlayerController.cs висит на обоих префабах, управляются оба. Добавьте проверку:
using SyncHubCloud;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// Ссылка на SyncHub_ConnectionView на объекте
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;
}
}
}
Синхронизация Transform
Откройте префаб Player.
Добавьте SyncHub_SyncTransfrom.cs (обязательно: должен быть SyncHub_ConnectionView.cs).
Настройте:
IsSyncPosition = true
IsSyncRotation = true
IsSyncScale = false
TypeInterpolationPos = Lerp
TypeInterpolationRot = Lerp
TypeInterpolationScale = Instantly
Давайте их разберём чуть подробнее:
IsSyncPosition - Если нужна синхронизация позиций
IsSyncRotation - Если нужна синхронизация поворота
IsSyncScale - Если нужна синхронизация скейла (размера)
TypeInterpolationPos, TypeInterpolationRot, TypeInterpolationScale - Тут Вы выбираете тип интерполяции, имеются такие настройки:
Lerp - Линейная интерполяция между двумя точками с плавным “торможение” к последней полученным значениям
MoveTowards - Интерполяция без плавного “торможения” к последним полученным значениям
Instantly - Жёсткая привязка к последним полученным данным без интерполяции (плавного перемещения, поворота и т.д.)
Соберите проект, запустите два клиента и проверьте, что позиция и поворот синхронизируются.
Что вы узнали:
Подключение по токену
Создание комнат
Получение списка и подключение к комнате
Спавн собственного и других игроков
Ограничение управления своим объектом
Синхронизация позиции, поворота и масштаба
В следующем уроке мы разберём RPC и Stream в SyncHubCloud — ключ к удалённым вызовам и потоковой передаче данных.