|
27.07.2010, 12:06
|
#1
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Unity3d - сеть (M2H_2B)
Как ясно из названия - я собираюсь показать работу с сетью на основе примера (M2H_2 .
Я перевел три скрипта, необходимых для сборки сетевого приложения, на C# и следовательно тема в нужном разделе.
Итак:
1. Скрипт подключения к сети "Connect.cs":
using UnityEngine; using System.Collections; public class Connect : MonoBehaviour { public string connectToIP = "127.0.0.1"; public int connectPort = 25001; // Смешанный GUI для сервера и клиента public void OnGUI() { if (Network.peerType == NetworkPeerType.Disconnected) { //Сейчас мы отключены и не являемся клиентом или хостом GUILayout.Label("Connection status: Disconnected"); connectToIP = GUILayout.TextField(connectToIP, GUILayout.MinWidth(100)); connectPort = int.Parse(GUILayout.TextField(connectPort.ToString())); GUILayout.BeginVertical(); if (GUILayout.Button("Connect as client")) { // Подсоединяемся к "connectToIP" и "connectPort" как клиент // В данном случае игнорируем NAT Network.useNat = false; Network.Connect(connectToIP, connectPort); } if (GUILayout.Button("Start Server")) { // Создаем север с 32 клиентами используя порт "connectPort" // Так же игнорируем NAT Network.useNat = false; Network.InitializeServer(32, connectPort); } GUILayout.EndVertical(); } else { //Мы имеем подключение(я)! if (Network.peerType == NetworkPeerType.Connecting) { // Статус - пдключение GUILayout.Label("Connection status: Connecting"); } else if (Network.peerType == NetworkPeerType.Client) { // Статус - клиент GUILayout.Label("Connection status: Client!"); GUILayout.Label("Ping to server: " + Network.GetAveragePing(Network.connections[0])); } else if (Network.peerType == NetworkPeerType.Server) { // Статус - сервер GUILayout.Label("Connection status: Server!"); GUILayout.Label("Connections: " + Network.connections.Length); if (Network.connections.Length >= 1) { GUILayout.Label("Ping to first player: " + Network.GetAveragePing(Network.connections[0])); } } if (GUILayout.Button("Disconnect")) { Network.Disconnect(200); } } } // ВСЕ функции ниже НЕ ИСПОЛЗУЮТСЯ в данном примере, а приведены только для демонстрации. // Сначала убедитесь в понимании кода, приведенного выше в функции OnGUI() // Слиентские фукнции, вызываемые Юнити public void OnConnectedToServer() { // Этот КЛИЕНТ подключился к серверу Debug.Log("This CLIENT has connected to a server"); } public void OnDisconnectedFromServer(NetworkDisconnection info) { // Этот СЕРВЕР или КЛИЕНТ отключился от сервера Debug.Log("This SERVER OR CLIENT has disconnected from a server"); } public void OnFailedToConnect(NetworkConnectionError error) { // Не удалось поключиться к серверу Debug.Log("Could not connect to server: " + error); } //Серверные фукнции, вызываемые Юнити public void OnPlayerConnected(NetworkPlayer player) { Debug.Log("Player connected from: " + player.ipAddress + ":" + player.port); } public void OnServerInitialized() { // Сервер инициализирован и готов Debug.Log("Server initialized and ready"); } public void OnPlayerDisconnected(NetworkPlayer player) { // Игрок отсоединился от player.ipAddress + ":" + player.port Debug.Log("Player disconnected from: " + player.ipAddress + ":" + player.port); } // OTHERS: // Для полного обзора всех сетевых функций вызываемых Юнити // следующие четыре так же были добавлены, но они сейчас игнорируются public void OnFailedToConnectToMasterServer(NetworkConnectionError info) { // Не удалось соединиться с мастер-сервером Debug.Log("Could not connect to master server: " + info); } public void OnNetworkInstantiate(NetworkMessageInfo info) { // Новый объект был создан info.sender Debug.Log("New object instantiated by " + info.sender); } public void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { //Пользовательский код здесь (Ваш код!) } }
2. Скрипт игрока "PlayerScript.cs":
using UnityEngine; [RequireComponent(typeof(NetworkView))] public class PlayerScript : MonoBehaviour { public void Awake() { if (!networkView.isMine) { // Если не мы владельцы данного объекта, то выключаем данный скрипт. // Но помним, что RPC и OnSerializeNetworkView работают в любом случае enabled = false; } } public void Update() { if (networkView.isMine) { // Только владелец может двигать куб! Vector3 moveDirection = new Vector3( Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); float speed = 5; transform.Translate(speed * moveDirection * Time.deltaTime); } } public void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { if (stream.isWriting) { // Выполняется у владельца networkview; // Сервер рассылает позицию по сети Vector3 pos = transform.position; stream.Serialize(ref pos);//"Кодирование" и рассылка } else { // Выполняется у всех остальных; // Клиенты получают позицию и устанавливают ее Vector3 posReceive = Vector3.zero; stream.Serialize(ref posReceive); //"Декодирование" и прием transform.position = posReceive; } } }
3. Скрипт создающий игроков при подключении и удалящий при отключении "SpawnScript.cs":
using UnityEngine; using System.Collections; public class SpawnScript : MonoBehaviour { public Transform playerPrefab; public void OnServerInitialized() { Spawnplayer(); } public void OnConnectedToServer() { Spawnplayer(); } public void Spawnplayer() { Transform myNewTrans = (Transform)Network.Instantiate( playerPrefab, transform.position, transform.rotation, 0); } public void OnPlayerDisconnected(NetworkPlayer player) { // Чистим за игроком Debug.Log("Clean up after player " + player); Network.RemoveRPCs(player); Network.DestroyPlayerObjects(player); } public void OnDisconnectedFromServer(NetworkDisconnection info) { // При отключении от сервера чистим за собой Debug.Log("Clean up a bit after server quit"); Network.RemoveRPCs(Network.player); Network.DestroyPlayerObjects(Network.player); /* * Запомните, что мы удаляем только наши объекты и не можем удалить объекты других игроков * т.к. мы не знаем где они и мы не следим за ними. * В игре обычно вы должны перезагрузить уровень или загрузить уровень с главным меню ;). * Сейчас мы можем использовать здесь "Application.LoadLevel(Application.loadedLevel);" для сброса сцены. */ Application.LoadLevel(Application.loadedLevel); } }
Я надеюсь функциональность данных скриптов вы поняли прочитав переведенные мной комментарии.
Сборка сцены: - Создаем в сцене пустой GameObject и называем его Connect. Вешаем на него скрипт "Connet.cs". Данный объект будет отображать GUI для подсоединения к сети или создании сервера.
- Создаем в сцене пустой GameObject и называем его SpawnScript. Вешаем на него скрипт "SpawnScript.cs". Данный объект будет создавать и удалять данные игроков.
- Создаем префаб игрока. Для Этого создаем кубик. На него вешаем "PlayerScript.cs" который автоматически ему добавляет компонент "NetworkView". Перетаскиваем скрипт PlayerScript назначенный кубику на поле Observed компонента NetworkView и устанавливаем параметр State Synchronization в Reliable Data Compressed. Создаем в проекте пустой префаб и перетаскиваем туда наш кубик.
- Назначаем наш созданный префаб игрока в SpawnScript полю Player Prefab (он должен знать как создать игрока).
Вроде все готово, можно собирать и тестировать. Чтобы тестировать на своей машине, нужно указать юнити, что следует работать в фоновом режиме: Edit->Project Settings->Player->Run In Background
Данный пример демонстрирует работу сети где сервер НЕ рулит
Заметки: камера сейчас одна и будет у каждого игрока в том месте, где она установлена с самого начала. Я думаю (не проверял), что для этого в скрипте PlayerScript в методе Awake, если созданный игрок принадлежит текущему сетевому игроку, нужно ее создать и привязать к этому префабу.
PS: вообще я не собирал эту сцену, я только перевел скрипты на C# и написал порядок сборки но должно работать)
|
(Offline)
|
|
Эти 10 пользователя(ей) сказали Спасибо pax за это полезное сообщение:
|
|
27.07.2010, 12:21
|
#2
|
Дэвелопер
Регистрация: 13.02.2010
Сообщений: 1,645
Написано 620 полезных сообщений (для 2,419 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
рах, в M2H есть пример под названием lobby. Он использует мастер сервер. И вот когда создаёш игру, игра переключается на пустую сцену с обной кнопкой-дисконект. Немог бы ты рассказать как поместить в эту игровую сцену кубики, чтоб тоже были с управление и со своей камерой . Чтоб при подключении у игрока создовался кубик, а при дисконекте удалялся.
Думую всем юнитистам этого форума будет полезно услышать это
----------------------------------------------------------------------
----------------------------------------------------------------------
Данный пример демонстрирует работу сети где сервер НЕ рулит
|
Могу описать пример 3, там сервер рулит
|
(Offline)
|
|
27.07.2010, 12:27
|
#3
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Сообщение от Den
рах, в M2H есть пример под названием lobby. Он использует мастер сервер. И вот когда создаёш игру, игра переключается на пустую сцену с обной кнопкой-дисконект. Немог бы ты рассказать как поместить в эту игровую сцену кубики, чтоб тоже были с управление и со своей камерой . Чтоб при подключении у игрока создовался кубик, а при дисконекте удалялся.
Думую всем юнитистам этого форума будет полезно услышать это
----------------------------------------------------------------------
----------------------------------------------------------------------
Могу описать пример 3, там сервер рулит
|
Третий пример я пока не стал описывать, чуть позже, если время будет. А что касается мастер-сервера, то создание сцены для него ничем не отличается от создания сцены без него. Отличие только в подключении. Так что данный пример без скрипта Connet вполне должен работать.
|
(Offline)
|
|
Эти 2 пользователя(ей) сказали Спасибо pax за это полезное сообщение:
|
|
27.07.2010, 20:27
|
#4
|
Дэвелопер
Регистрация: 13.02.2010
Сообщений: 1,645
Написано 620 полезных сообщений (для 2,419 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Вот сделал сетевую игру (точнее изменил пример, вытащил из каждого примера самое лучьшее и соеденил) -------> игра
прошу по тестить.
Вначале вписываем своё имя.
Нажимаем Save.
Нажимаем Host a game (это штоб стать сервером, создать игру, комнату)
Или нажимаем Select a game to join (это штоб стать клиентом, подключится к чюжой игре, комнате).
3 кнопка это подключится к рандомной игре, а если их нет то создать свою.
Если вы сервер- вписываем все данные о игре (пароль не надо вписывать) и нажимаем Go to lobby.
Далее не чего не трогаем, ждём когда подключатся клиенты (во время игры они не смогут подключится), внизу чат, там можно общаца, если подсоеденица клиент, то там будет написано. Как толь ко захотите начать игру- нажимает кнопку Start the game. Если вы клиент-выбираем игру, нажимаем напротив неё кнопка коннект.
Если игр нет, нажимаем кнопку рефреш-это обновляет список. Справа блок с айпи, портом, натом-его не надо трогать.
Далее играем!
Если хотите потестить толпой-напишите сдесь-определим кто будет сервером, и во сколькл играть будем.
-----------------------------------
В игре помойму глюк с именами над кубиками...(((
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
30.07.2010, 13:10
|
#5
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Продублирую я тут ответ по поводу сети, чтобы не искать потом:
Сообщение от Fatalix3d
Pax не мог бы ты обьяснить как избавиться от лагов в сети, и немного про анимацию опять таки для сетевого режима.
|
Для избавления от лагов нужно использовать интерполяцию с задержкой по времени, пример из Networking Example с оффсайта (NetworkInterpolatedTransform):
using UnityEngine; using System.Collections; public class NetworkInterpolatedTransform : MonoBehaviour { // временная задержка для интерполяции public double interpolationBackTime = 0.1; internal struct State { internal double timestamp; internal Vector3 pos; internal Quaternion rot; } // Сохраняем 20 состояний с информацией "для воспроизведения" State[] m_BufferedState = new State[20]; // сколько состояний используется int m_TimestampCount; void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { // Всегда отсылаем трансформ if (stream.isWriting) { Vector3 pos = transform.localPosition; Quaternion rot = transform.localRotation; stream.Serialize(ref pos); stream.Serialize(ref rot); } // Когда принимаем - буфферизируем информацию else { // Принимаем последнее состояние Vector3 pos = Vector3.zero; Quaternion rot = Quaternion.identity; stream.Serialize(ref pos); stream.Serialize(ref rot); // Смещаем данные в буфере на 1 for (int i=m_BufferedState.Length-1;i>=1;i--) { m_BufferedState[i] = m_BufferedState[i-1]; } // сохраняем полученные данные под нулевым индексом State state; state.timestamp = info.timestamp; state.pos = pos; state.rot = rot; m_BufferedState[0] = state; // увеличиваем количество сохраненных состояний, но не больше количества слотов m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length); // проверяем целостность данных for (int i=0;i<m_TimestampCount-1;i++) { if (m_BufferedState[i].timestamp < m_BufferedState[i+1].timestamp) Debug.Log("State inconsistent"); } //Debug.Log("stamp: " + info.timestamp + "my time: " + Network.time + "delta: " + (Network.time - info.timestamp)); } } // Работает только когда компонент включен, т.е. на удаленных соединениях (server/clients) void Update () { double currentTime = Network.time; double interpolationTime = currentTime - interpolationBackTime; // Ищем промежуток, подходящий по отложенному времени if (m_BufferedState[0].timestamp > interpolationTime) { for (int i=0;i<m_TimestampCount;i++) { if (m_BufferedState[i].timestamp <= interpolationTime || i == m_TimestampCount-1) { // два состояния, в промежуток которых попадает времяя State rhs = m_BufferedState[Mathf.Max(i-1, 0)]; State lhs = m_BufferedState[i]; // промежуток времени между состояниями double length = rhs.timestamp - lhs.timestamp; float t = 0.0F; // интерполирующая переменная if (length > 0.0001) t = (float)((interpolationTime - lhs.timestamp) / length); // интерполируем трансформации transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t); transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t); return; } } } // для экстраполяции используем последнее полученное значение else { State latest = m_BufferedState[0]; transform.localPosition = latest.pos; transform.localRotation = latest.rot; } } }
Для синхронизации анимаций там же найдете пример Networking Scripts\NetworkSyncAnimation
|
(Offline)
|
|
Эти 4 пользователя(ей) сказали Спасибо pax за это полезное сообщение:
|
|
02.02.2012, 18:29
|
#6
|
AnyKey`щик
Регистрация: 02.02.2012
Сообщений: 1
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Очень интересно,а можно ли это реализовать не на браузерной основе?
Den что то не получается законнектиться,но все равно спасибо вам двоим,буду осуществлять онлайн режим для игры
|
(Offline)
|
|
10.05.2012, 20:42
|
#7
|
Модератор
Регистрация: 05.11.2005
Сообщений: 161
Написано 63 полезных сообщений (для 182 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Den, не получилось законнектиться на сервер, который я создал - Failed to connect!
А можно ли в Unity сделать мультиплеер через веб-сервер (как WOW например)? Что почитать по это теме посоветуйте?
|
(Offline)
|
|
10.05.2012, 20:50
|
#8
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Либо писать свой сервер на System.Net ( хорошая статья), либо покупать чье-то серверное решение (гугли ES5, Exitgames Photon, Crystal Engine и т.д.).
|
(Offline)
|
|
13.06.2012, 11:17
|
#9
|
ПроЭктировщик
Регистрация: 04.11.2011
Сообщений: 176
Написано 19 полезных сообщений (для 64 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Всем привет. Пожалуйста объясните подробно как сделать что если игрок твой, то есть управляешь им ты, то объект круг. А если не ты то куб. Всю ночь мучался нечего не вышло.
|
(Offline)
|
|
13.06.2012, 12:19
|
#10
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Ну изменить скрипт игрока примерно так:
[RequireComponent(typeof(NetworkView))] public class PlayerScript : MonoBehaviour { public void Awake() { if (!networkView.isMine) { // Если не мы владельцы данного объекта, то выключаем данный скрипт. // Но помним, что RPC и OnSerializeNetworkView работают в любом случае enabled = false; GetComponent<MeshFilter>().mesh = boxMesh; } else { GetComponent<MeshFilter>().mesh = sphereMesh; } }
Где boxMesh и sphereMesh надо либо определить переменными типа Mesh и назначить им соответствующие меши, либо сделать какую-то еще логику подмены модели. Например Добавлять модель в чайлды, а сам префаб плеера будет без модели изначально.
|
(Offline)
|
|
13.06.2012, 13:28
|
#11
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Еще один вариант - префаб игрока - пустышка, управляющая создаваемыми им моделями.
using UnityEngine;
[RequireComponent(typeof(NetworkView))] public class PlayerScript : MonoBehaviour { public GameObject fpsPrefab; public GameObject locomotionPrefab; private GameObject controlledObject;
public void Awake() { if (!networkView.isMine) { // Если не мы владельцы данного объекта, то выключаем данный скрипт. // Но помним, что RPC и OnSerializeNetworkView работают в любом случае enabled = false; controlledObject = Instantiate(locomotionPrefab) as GameObject; } else { controlledObject = Instantiate(fpsPrefab) as GameObject; } }
public void Update() {
if (networkView.isMine) { // Только владелец может двигать куб! Vector3 moveDirection = new Vector3( Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); float speed = 5; controlledObject.transform.Translate(speed * moveDirection * Time.deltaTime); }
}
public void OnDestroy() { Destroy(controlledObject); }
public void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { if (stream.isWriting) { // Выполняется у владельца networkview; // Сервер рассылает позицию по сети
Vector3 pos = controlledObject.transform.position; stream.Serialize(ref pos);//"Кодирование" и рассылка
} else { // Выполняется у всех остальных; // Клиенты получают позицию и устанавливают ее
Vector3 posReceive = Vector3.zero; stream.Serialize(ref posReceive); //"Декодирование" и прием controlledObject.transform.position = posReceive;
} } }
|
(Offline)
|
|
13.06.2012, 22:45
|
#12
|
AnyKey`щик
Регистрация: 13.06.2012
Сообщений: 2
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
пишет ошибку
|
(Offline)
|
|
14.06.2012, 02:10
|
#13
|
AnyKey`щик
Регистрация: 13.06.2012
Сообщений: 2
Написано 0 полезных сообщений (для 0 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Could not open port for debugger. Another process may be using the port.
|
(Offline)
|
|
19.06.2012, 22:09
|
#14
|
Бывалый
Регистрация: 17.05.2009
Адрес: Днепропетровск
Сообщений: 672
Написано 180 полезных сообщений (для 428 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Эм, что-то тут не так.
if (stream.isWriting)
{
// Выполняется у владельца networkview;
// Сервер рассылает позицию по сети
Vector3 pos = transform.position;
stream.Serialize(ref pos);//"Кодирование" и рассылка
}
else
{
// Выполняется у всех остальных;
// Клиенты получают позицию и устанавливают ее
Vector3 posReceive = Vector3.zero;
stream.Serialize(ref posReceive); //"Декодирование" и прием
transform.position = posReceive;
}
|
убрал вообще, но информация о объекте всеравно сообщается О_О
|
(Offline)
|
|
20.06.2012, 16:10
|
#15
|
Unity/C# кодер
Регистрация: 03.10.2005
Адрес: Россия, Рязань
Сообщений: 7,568
Написано 3,006 полезных сообщений (для 5,323 пользователей)
|
Ответ: Unity3d - сеть (M2H_2B)
Сообщение от is.SarCasm
Эм, что-то тут не так.
убрал вообще, но информация о объекте всеравно сообщается О_О
|
А в NetworkView что указывал, трансформ или скрипт?
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 07:59.
|