Примеры кода

Основы Netcode for GameObjects

Настройка базовой сетевой архитектуры и подключение клиентов.

using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;

public class NetworkManagerUI : MonoBehaviour
{
    [Header("UI элементы")]
    public Button hostButton;
    public Button clientButton;
    public Text statusText;
    
    void Start()
    {
        hostButton.onClick.AddListener(StartHost);
        clientButton.onClick.AddListener(StartClient);
        Debug.Log("Network Manager UI инициализирован");
    }
    
    public void StartHost()
    {
        if (NetworkManager.Singleton.StartHost())
        {
            statusText.text = "Хост запущен успешно";
            Debug.Log("Хост-сервер запущен");
        }
        else
        {
            statusText.text = "Ошибка запуска хоста";
        }
    }
    
    public void StartClient()
    {
        if (NetworkManager.Singleton.StartClient())
        {
            statusText.text = "Подключение к серверу...";
            Debug.Log("Клиент подключается");
        }
        else
        {
            statusText.text = "Ошибка подключения";
        }
    }
    
    void Update()
    {
        if (NetworkManager.Singleton.IsHost)
        {
            statusText.text = $"Хост - Клиентов: {NetworkManager.Singleton.ConnectedClients.Count}";
        }
        else if (NetworkManager.Singleton.IsClient && NetworkManager.Singleton.IsConnectedClient)
        {
            statusText.text = "Подключен как клиент";
        }
    }
}
                            

NetworkObjects и синхронизация

Работа с сетевыми объектами и их синхронизация между клиентами.

using Unity.Netcode;
using UnityEngine;

public class NetworkPlayer : NetworkBehaviour
{
    [Header("Настройки игрока")]
    public float moveSpeed = 5f;
    
    private NetworkVariable<Vector3> networkPosition = new NetworkVariable<Vector3>();
    private NetworkVariable<Color> playerColor = new NetworkVariable<Color>(
        Color.white, 
        NetworkVariableReadPermission.Everyone, 
        NetworkVariableWritePermission.Owner
    );
    
    public override void OnNetworkSpawn()
    {
        playerColor.OnValueChanged += OnColorChanged;
        networkPosition.OnValueChanged += OnPositionChanged;
        
        if (IsOwner)
        {
            playerColor.Value = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f));
        }
        
        GetComponent<Renderer>().material.color = playerColor.Value;
        Debug.Log($"Сетевой игрок создан. Владелец: {OwnerClientId}");
    }
    
    void Update()
    {
        if (IsOwner)
        {
            HandleMovement();
        }
        else
        {
            transform.position = Vector3.Lerp(transform.position, networkPosition.Value, Time.deltaTime * 10f);
        }
    }
    
    void HandleMovement()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        
        Vector3 movement = new Vector3(horizontal, 0, vertical) * moveSpeed * Time.deltaTime;
        transform.Translate(movement);
        
        networkPosition.Value = transform.position;
        
        if (Input.GetKeyDown(KeyCode.C))
        {
            playerColor.Value = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f));
        }
    }
    
    void OnColorChanged(Color previousColor, Color newColor)
    {
        GetComponent<Renderer>().material.color = newColor;
        Debug.Log($"Цвет игрока изменен на: {newColor}");
    }
    
    void OnPositionChanged(Vector3 previousPos, Vector3 newPos)
    {
        if (!IsOwner)
        {
            Debug.Log($"Позиция обновлена: {newPos}");
        }
    }
}
                        

RPC и сетевая связь

Удаленные вызовы процедур для мгновенной связи между клиентами.

using Unity.Netcode;
using UnityEngine;

public class NetworkCommunication : NetworkBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            SendMessage($"Игрок {OwnerClientId}: Привет!");
        }
        
        if (Input.GetKeyDown(KeyCode.F))
        {
            NotifyAction("прыгнул");
        }
    }
    
    public void SendMessage(string message)
    {
        if (IsOwner)
        {
            SendMessageServerRpc(message);
        }
    }
    
    [ServerRpc]
    void SendMessageServerRpc(string message)
    {
        Debug.Log($"Сервер получил: {message}");
        ReceiveMessageClientRpc(message);
    }
    
    [ClientRpc]
    void ReceiveMessageClientRpc(string message)
    {
        Debug.Log($"Сообщение: {message}");
    }
    
    public void NotifyAction(string action)
    {
        if (IsOwner)
        {
            NotifyActionServerRpc(OwnerClientId, action);
        }
    }
    
    [ServerRpc]
    void NotifyActionServerRpc(ulong playerId, string action)
    {
        NotifyActionClientRpc(playerId, action);
    }
    
    [ClientRpc]
    void NotifyActionClientRpc(ulong playerId, string action)
    {
        Debug.Log($"Игрок {playerId} {action}");
    }
}
                        

NetworkVariables и состояние

Синхронизация состояния игры через NetworkVariables.

using Unity.Netcode;
using UnityEngine;

public class GameStateManager : NetworkBehaviour
{
    private NetworkVariable<float> gameTime = new NetworkVariable<float>(300f);
    private NetworkVariable<bool> gameActive = new NetworkVariable<bool>(false);
    private NetworkVariable<int> playerCount = new NetworkVariable<int>(0);
    
    public override void OnNetworkSpawn()
    {
        gameTime.OnValueChanged += OnTimeChanged;
        gameActive.OnValueChanged += OnGameStateChanged;
        playerCount.OnValueChanged += OnPlayerCountChanged;
        
        if (IsServer)
        {
            UpdatePlayerCount();
        }
        
        Debug.Log("Game State Manager инициализирован");
    }
    
    void Update()
    {
        if (IsServer && gameActive.Value && gameTime.Value > 0)
        {
            gameTime.Value -= Time.deltaTime;
            
            if (gameTime.Value <= 0)
            {
                EndGame();
            }
        }
        
        if (Input.GetKeyDown(KeyCode.G) && IsHost)
        {
            if (!gameActive.Value)
                StartGame();
            else
                EndGame();
        }
    }
    
    void StartGame()
    {
        if (IsServer)
        {
            gameActive.Value = true;
            gameTime.Value = 300f;
            Debug.Log("Игра запущена!");
        }
    }
    
    void EndGame()
    {
        if (IsServer)
        {
            gameActive.Value = false;
            Debug.Log("Игра завершена!");
        }
    }
    
    void UpdatePlayerCount()
    {
        if (IsServer)
        {
            playerCount.Value = NetworkManager.Singleton.ConnectedClients.Count;
        }
    }
    
    void OnTimeChanged(float previousTime, float newTime)
    {
        Debug.Log($"Время игры: {newTime:F1} сек");
    }
    
    void OnGameStateChanged(bool previousState, bool newState)
    {
        Debug.Log($"Состояние игры: {(newState ? "Активна" : "Неактивна")}");
    }
    
    void OnPlayerCountChanged(int previousCount, int newCount)
    {
        Debug.Log($"Игроков подключено: {newCount}");
    }
}
                        

Простая мультиплеерная игра

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

using Unity.Netcode;
using UnityEngine;

public class MultiplayerGame : NetworkBehaviour
{
    [Header("Игровые объекты")]
    public GameObject collectiblePrefab;
    public Transform[] spawnPoints;
    
    private NetworkVariable<int> playerScore = new NetworkVariable<int>(0);
    private NetworkList<Vector3> collectiblePositions;
    
    public override void OnNetworkSpawn()
    {
        if (IsServer)
        {
            collectiblePositions = new NetworkList<Vector3>();
            SpawnCollectibles();
        }
        
        playerScore.OnValueChanged += OnScoreChanged;
        Debug.Log("Мультиплеерная игра инициализирована");
    }
    
    void SpawnCollectibles()
    {
        if (IsServer)
        {
            for (int i = 0; i < 5; i++)
            {
                Vector3 randomPos = new Vector3(
                    Random.Range(-10f, 10f),
                    1f,
                    Random.Range(-10f, 10f)
                );
                
                var collectible = Instantiate(collectiblePrefab, randomPos, Quaternion.identity);
                collectible.GetComponent<NetworkObject>().Spawn();
                collectiblePositions.Add(randomPos);
            }
            
            Debug.Log("Предметы для сбора созданы");
        }
    }
    
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Collectible") && IsOwner)
        {
            CollectItemServerRpc();
        }
    }
    
    [ServerRpc]
    void CollectItemServerRpc()
    {
        playerScore.Value += 10;
        Debug.Log($"Игрок {OwnerClientId} собрал предмет. Счет: {playerScore.Value}");
        
        // Создание нового предмета
        Vector3 newPos = new Vector3(
            Random.Range(-10f, 10f),
            1f,
            Random.Range(-10f, 10f)
        );
        
        var newCollectible = Instantiate(collectiblePrefab, newPos, Quaternion.identity);
        newCollectible.GetComponent<NetworkObject>().Spawn();
    }
    
    void OnScoreChanged(int previousScore, int newScore)
    {
        Debug.Log($"Счет обновлен: {newScore}");
        UpdateScoreUI(newScore);
    }
    
    void UpdateScoreUI(int score)
    {
        // Обновление UI счета
        var scoreText = GameObject.Find("ScoreText");
        if (scoreText != null)
        {
            scoreText.GetComponent<UnityEngine.UI.Text>().text = $"Счет: {score}";
        }
    }
    
    public void ResetGame()
    {
        if (IsServer)
        {
            ResetGameServerRpc();
        }
    }
    
    [ServerRpc(RequireOwnership = false)]
    void ResetGameServerRpc()
    {
        // Сброс счета всех игроков
        foreach (var client in NetworkManager.Singleton.ConnectedClients.Values)
        {
            var playerGame = client.PlayerObject.GetComponent<MultiplayerGame>();
            if (playerGame != null)
            {
                playerGame.playerScore.Value = 0;
            }
        }
        
        Debug.Log("Игра сброшена");
    }
}