forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Уроки (http://forum.boolean.name/forumdisplay.php?f=145)
-   -   Unity3d - сеть (M2H_2B) (http://forum.boolean.name/showthread.php?t=13012)

pax 27.07.2010 12:06

Unity3d - сеть (M2H_2B)
 
Как ясно из названия - я собираюсь показать работу с сетью на основе примера (M2H_2B).
Я перевел три скрипта, необходимых для сборки сетевого приложения, на C# и следовательно тема в нужном разделе.

Итак:

1. Скрипт подключения к сети "Connect.cs":
PHP код:

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(connectToIPGUILayout.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(connectToIPconnectPort);
            }

            if (
GUILayout.Button("Start Server"))
            {
                
// Создаем север с 32 клиентами используя порт "connectPort" 
                // Так же игнорируем NAT
                
Network.useNat false;
                
Network.InitializeServer(32connectPort);
            }
            
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 streamNetworkMessageInfo info)
    {
        
//Пользовательский код здесь (Ваш код!)
    
}



2. Скрипт игрока "PlayerScript.cs":
PHP код:

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"), 0Input.GetAxis("Vertical"));
            
float speed 5;
            
transform.Translate(speed moveDirection Time.deltaTime);
        }

    }


    public 
void OnSerializeNetworkView(BitStream streamNetworkMessageInfo 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":
PHP код:

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(
            
playerPrefabtransform.positiontransform.rotation0);

    }

    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);
    }


Я надеюсь функциональность данных скриптов вы поняли прочитав переведенные мной комментарии.

Сборка сцены:
  1. Создаем в сцене пустой GameObject и называем его Connect. Вешаем на него скрипт "Connet.cs". Данный объект будет отображать GUI для подсоединения к сети или создании сервера.
  2. Создаем в сцене пустой GameObject и называем его SpawnScript. Вешаем на него скрипт "SpawnScript.cs". Данный объект будет создавать и удалять данные игроков.
  3. Создаем префаб игрока. Для Этого создаем кубик. На него вешаем "PlayerScript.cs" который автоматически ему добавляет компонент "NetworkView". Перетаскиваем скрипт PlayerScript назначенный кубику на поле Observed компонента NetworkView и устанавливаем параметр State Synchronization в Reliable Data Compressed. Создаем в проекте пустой префаб и перетаскиваем туда наш кубик.
  4. Назначаем наш созданный префаб игрока в SpawnScript полю Player Prefab (он должен знать как создать игрока).
Вроде все готово, можно собирать и тестировать. Чтобы тестировать на своей машине, нужно указать юнити, что следует работать в фоновом режиме: Edit->Project Settings->Player->Run In Background

Данный пример демонстрирует работу сети где сервер НЕ рулит :)

Заметки: камера сейчас одна и будет у каждого игрока в том месте, где она установлена с самого начала. Я думаю (не проверял), что для этого в скрипте PlayerScript в методе Awake, если созданный игрок принадлежит текущему сетевому игроку, нужно ее создать и привязать к этому префабу.

PS: вообще я не собирал эту сцену, я только перевел скрипты на C# и написал порядок сборки ;) но должно работать)

den 27.07.2010 12:21

Ответ: Unity3d - сеть (M2H_2B)
 
рах, в M2H есть пример под названием lobby. Он использует мастер сервер. И вот когда создаёш игру, игра переключается на пустую сцену с обной кнопкой-дисконект. Немог бы ты рассказать как поместить в эту игровую сцену кубики, чтоб тоже были с управление и со своей камерой . Чтоб при подключении у игрока создовался кубик, а при дисконекте удалялся.
Думую всем юнитистам этого форума будет полезно услышать это:)
----------------------------------------------------------------------
----------------------------------------------------------------------
Цитата:

Данный пример демонстрирует работу сети где сервер НЕ рулит
Могу описать пример 3, там сервер рулит:)

pax 27.07.2010 12:27

Ответ: Unity3d - сеть (M2H_2B)
 
Цитата:

Сообщение от Den (Сообщение 156291)
рах, в M2H есть пример под названием lobby. Он использует мастер сервер. И вот когда создаёш игру, игра переключается на пустую сцену с обной кнопкой-дисконект. Немог бы ты рассказать как поместить в эту игровую сцену кубики, чтоб тоже были с управление и со своей камерой . Чтоб при подключении у игрока создовался кубик, а при дисконекте удалялся.
Думую всем юнитистам этого форума будет полезно услышать это:)
----------------------------------------------------------------------
----------------------------------------------------------------------

Могу описать пример 3, там сервер рулит:)

Третий пример я пока не стал описывать, чуть позже, если время будет. А что касается мастер-сервера, то создание сцены для него ничем не отличается от создания сцены без него. Отличие только в подключении. Так что данный пример без скрипта Connet вполне должен работать.

den 27.07.2010 20:27

Ответ: Unity3d - сеть (M2H_2B)
 
Вот сделал сетевую игру (точнее изменил пример, вытащил из каждого примера самое лучьшее и соеденил) -------> игра
прошу по тестить.
Вначале вписываем своё имя.
Нажимаем Save.
Нажимаем Host a game (это штоб стать сервером, создать игру, комнату)
Или нажимаем Select a game to join (это штоб стать клиентом, подключится к чюжой игре, комнате).
3 кнопка это подключится к рандомной игре, а если их нет то создать свою.
Если вы сервер- вписываем все данные о игре (пароль не надо вписывать)
и нажимаем Go to lobby.
Далее не чего не трогаем, ждём когда подключатся клиенты (во время игры они не смогут подключится), внизу чат, там можно общаца, если подсоеденица клиент, то там будет написано. Как толь ко захотите начать игру- нажимает кнопку Start the game.
Если вы клиент-выбираем игру,
нажимаем напротив неё кнопка коннект.
Если игр нет, нажимаем кнопку рефреш-это обновляет список.
Справа блок с айпи, портом, натом-его не надо трогать.
Далее играем!
Если хотите потестить толпой-напишите сдесь-определим кто будет сервером, и во сколькл играть будем.
-----------------------------------
В игре помойму глюк с именами над кубиками...(((

pax 30.07.2010 13:10

Ответ: Unity3d - сеть (M2H_2B)
 
Продублирую я тут ответ по поводу сети, чтобы не искать потом:
Цитата:

Сообщение от Fatalix3d (Сообщение 156638)
Pax не мог бы ты обьяснить как избавиться от лагов в сети, и немного про анимацию опять таки для сетевого режима.

Для избавления от лагов нужно использовать интерполяцию с задержкой по времени, пример из Networking Example с оффсайта (NetworkInterpolatedTransform):
PHP код:

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 streamNetworkMessageInfo 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 1m_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 || == m_TimestampCount-1)
                {
                    
// два состояния, в промежуток которых попадает времяя
                    
State rhs m_BufferedState[Mathf.Max(i-10)];
                    
                    
State lhs m_BufferedState[i];
                    
                    
// промежуток времени между состояниями
                    
double length rhs.timestamp lhs.timestamp;
                    
float t 0.0F;
                    
// интерполирующая переменная
                    
if (length 0.0001)
                        
= (float)((interpolationTime lhs.timestamp) / length);
                    
                    
// интерполируем трансформации
                    
transform.localPosition Vector3.Lerp(lhs.posrhs.post);
                    
transform.localRotation Quaternion.Slerp(lhs.rotrhs.rott);
                    return;
                }
            }
        }
        
// для экстраполяции используем последнее полученное значение
        
else
        {
            
State latest m_BufferedState[0];
            
            
transform.localPosition latest.pos;
            
transform.localRotation latest.rot;
        }
    }


Для синхронизации анимаций там же найдете пример Networking Scripts\NetworkSyncAnimation

Ingener 02.02.2012 18:29

Ответ: Unity3d - сеть (M2H_2B)
 
Очень интересно,а можно ли это реализовать не на браузерной основе?
Den что то не получается законнектиться,но все равно спасибо вам двоим,буду осуществлять онлайн режим для игры

ant2on 10.05.2012 20:42

Ответ: Unity3d - сеть (M2H_2B)
 
Den, не получилось законнектиться на сервер, который я создал - Failed to connect!

А можно ли в Unity сделать мультиплеер через веб-сервер (как WOW например)? Что почитать по это теме посоветуйте? :)

pax 10.05.2012 20:50

Ответ: Unity3d - сеть (M2H_2B)
 
Либо писать свой сервер на System.Net (хорошая статья), либо покупать чье-то серверное решение (гугли ES5, Exitgames Photon, Crystal Engine и т.д.).

pie 13.06.2012 11:17

Ответ: Unity3d - сеть (M2H_2B)
 
Всем привет. Пожалуйста объясните подробно как сделать что если игрок твой, то есть управляешь им ты, то объект круг. А если не ты то куб. Всю ночь мучался нечего не вышло.

pax 13.06.2012 12:19

Ответ: Unity3d - сеть (M2H_2B)
 
Ну изменить скрипт игрока примерно так:
PHP код:

[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 и назначить им соответствующие меши, либо сделать какую-то еще логику подмены модели. Например Добавлять модель в чайлды, а сам префаб плеера будет без модели изначально.

pax 13.06.2012 13:28

Ответ: Unity3d - сеть (M2H_2B)
 
Еще один вариант - префаб игрока - пустышка, управляющая создаваемыми им моделями.

PHP код:

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"), 0Input.GetAxis("Vertical")); 
            
float speed 5
            
controlledObject.transform.Translate(speed moveDirection Time.deltaTime); 
        } 

    } 

    public 
void OnDestroy() 
    { 
       
Destroy(controlledObject);
    }


    public 
void OnSerializeNetworkView(BitStream streamNetworkMessageInfo 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

        } 
    } 



dpisaev 13.06.2012 22:45

Ответ: Unity3d - сеть (M2H_2B)
 
пишет ошибку

dpisaev 14.06.2012 02:10

Ответ: Unity3d - сеть (M2H_2B)
 
Could not open port for debugger. Another process may be using the port.

is.SarCasm 19.06.2012 22:09

Ответ: 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;

}
убрал вообще, но информация о объекте всеравно сообщается О_О

pax 20.06.2012 16:10

Ответ: Unity3d - сеть (M2H_2B)
 
Цитата:

Сообщение от is.SarCasm (Сообщение 230765)
Эм, что-то тут не так.

убрал вообще, но информация о объекте всеравно сообщается О_О

А в NetworkView что указывал, трансформ или скрипт?


Часовой пояс GMT +4, время: 19:18.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot