Как ясно из названия - я собираюсь показать работу с сетью на основе примера (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# и написал порядок сборки
но должно работать)