MLAPI系列 - 02 - HelloWorld

1 构建 “你好,世界”

在本指南中,我们将在已经在Hello World中完成的工作的基础上增加一些功能,我们将涵盖以下内容:

  • 向对象添加脚本
  • 在游戏中添加编辑器模式(主机服务器和客户端)
  • 基本玩家移动
  • 许可
  • 基本RPC使用
  • Adding scripts to your objects
  • Adding editor modes inside your game (Host Server and Client)
  • Basic Player Movement
  • Permissions
  • Basic RPC use

2 要求

教程需要支持 Netcode 的Unity版本(2020.3+)

我们建议您在开始这一个之前完成你的第一个网络游戏“ MLAPI - 01 - 你好世界 ”指南。

3 向Hello World添加脚本

本部分将向Hello World添加一些脚本,这些脚本将包含我们将在教程中介绍的新功能。

1 单击“Assets”文件夹。
2 创建一个新文件夹,并命名为Scripts

4 添加脚本 HellowWorldPlayer.cs

1 创建一个新的脚本HelloWorldPlayer
2 打开HelloWorldPlayer.cs脚本。
3 编辑HelloWorldPlayer.cs脚本以匹配以下内容。

using Unity.Netcode;
using UnityEngine;

namespace HelloWorld
{
    
    
    public class HelloWorldPlayer : NetworkBehaviour
    {
    
    
        public NetworkVariable<Vector3> Position = new NetworkVariable<Vector3>();

        public override void OnNetworkSpawn()
        {
    
    
            if (IsOwner)
            {
    
    
                Move();
            }
        }

        public void Move()
        {
    
    
            if (NetworkManager.Singleton.IsServer)
            {
    
    
                var randomPosition = GetRandomPositionOnPlane();
                transform.position = randomPosition;
                Position.Value = randomPosition;
            }
            else
            {
    
    
                SubmitPositionRequestServerRpc();
            }
        }

        [ServerRpc]
        void SubmitPositionRequestServerRpc(ServerRpcParams rpcParams = default)
        {
    
    
            Position.Value = GetRandomPositionOnPlane();
        }

        static Vector3 GetRandomPositionOnPlane()
        {
    
    
            return new Vector3(Random.Range(-3f, 3f), 1f, Random.Range(-3f, 3f));
        }

        void Update()
        {
    
    
            transform.position = Position.Value;
        }
    }
}

5 添加 HelloWorldManager.cs

1 创建一个空的GameObject并将其重命名为HelloWorldManager
2 创建一个名为HelloWorldManager的脚本。
3 打开HelloWorldManager.cs脚本。
4 编辑HelloWorldManager.cs脚本以匹配以下内容。
5 添加HelloWorldManager脚本作为组件。


using Unity.Netcode;
using UnityEngine;

namespace HelloWorld
{
    
    
    public class HelloWorldManager : MonoBehaviour
    {
    
    
        void OnGUI()
        {
    
    
            GUILayout.BeginArea(new Rect(10, 10, 300, 300));
            if (!NetworkManager.Singleton.IsClient &&
            	!NetworkManager.Singleton.IsServer)
            {
    
    
                StartButtons();
            }
            else
            {
    
    
                StatusLabels();

                SubmitNewPosition();
            }

            GUILayout.EndArea();
        }

        static void StartButtons()
        {
    
    
            if (GUILayout.Button("Host")) NetworkManager.Singleton.StartHost();
            if (GUILayout.Button("Client")) NetworkManager.Singleton.StartClient();
            if (GUILayout.Button("Server")) NetworkManager.Singleton.StartServer();
        }

        static void StatusLabels()
        {
    
    
            var mode = NetworkManager.Singleton.IsHost ?
                "Host" : NetworkManager.Singleton.IsServer ? "Server" : "Client";

            GUILayout.Label("Transport: " +
                NetworkManager.Singleton.
                NetworkConfig.NetworkTransport.GetType().Name);
                
            GUILayout.Label("Mode: " + mode);
        }

		static void SubmitNewPosition()
        {
    
    
            if (GUILayout.Button(
            	NetworkManager.Singleton.IsServer ? 
            		"Move" : "Request Position Change"))
            {
    
    
                if (NetworkManager.Singleton.IsServer && 
                	!NetworkManager.Singleton.IsClient )
                {
    
    
                    foreach (ulong uid in NetworkManager.Singleton.ConnectedClientsIds)
                        NetworkManager.Singleton.SpawnManager.
                        	GetPlayerNetworkObject(uid).
                        		GetComponent<HelloWorldPlayer>().Move();
                }
                else
                {
    
    
                    var playerObject = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject();
                    var player = playerObject.GetComponent<HelloWorldPlayer>();
                    player.Move();
                }
            }
        }
    }
}

6 增加编辑模式

HelloWorldManager.cs脚本中,我们定义了两种方法来模拟播放模式下网络管理器中的编辑器按钮。

        static void StartButtons()
        {
    
    
            if (GUILayout.Button("Host")) NetworkManager.Singleton.StartHost();
            if (GUILayout.Button("Client")) NetworkManager.Singleton.StartClient();
            if (GUILayout.Button("Server")) NetworkManager.Singleton.StartServer();
        }

        static void StatusLabels()
        {
    
    
            var mode = NetworkManager.Singleton.IsHost ?
                "Host" : NetworkManager.Singleton.IsServer ? "Server" : "Client";

            GUILayout.Label("Transport: " +
                NetworkManager.Singleton.NetworkConfig.NetworkTransport.GetType().Name);
            GUILayout.Label("Mode: " + mode);
        }

网络管理器NetworkManager实现了单例模式,因为它声明了名为Singleton的单例。

  • 这是在启用MonoBehaviour时定义的。
  • 该组件还包含非常有用的属性,如IsClientIsServerIsLocalClient
  • 前两个决定了我们当前建立的连接状态,您将很快使用。

我们在OnGUI()内部调用这些方法。

void OnGUI()
        {
    
    
            GUILayout.BeginArea(new Rect(10, 10, 300, 300));
            if (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer)
            {
    
    
                StartButtons();
            }
            else
            {
    
    
                StatusLabels();

                SubmitNewPosition();
            }

            GUILayout.EndArea();
        }

NOTE

您将注意到一个新方法的引入,SubmitNewPosition();我们稍后会用到。

7 Player对象添加基本移动

HelloWorldPlayer.cs”脚本为Player添加了一些基本移动

1选择 Player 预设。
2添加脚本 ** HelloWorldPlayer** 脚本作为组件。

此类将继承自NetworkBehaviour ,而不是MonoBehaviour

public class HelloWorldPlayer : NetworkBehaviour

在这个类中,我们现在定义一个网络变量来表示这个玩家的网络位置

public NetworkVariable<Vector3> Position = new NetworkVariable<Vector3>();

HelloWorldPlayer重写了OnNetworkSpawn方法

public override void OnNetworkSpawn()
    {
    
    
        if (IsOwner)
        {
    
    
            Move();
        }
    }

任何实现NetworkBehaviourMonoBehaviour 都可以覆盖Netcode上的OnNetworkSpawn()

  • 当生成NetworkObject 并设置网络时,将触发此方法。
  • 我们覆盖OnNetworkSpawn,因为客户端和服务器在这里运行不同的逻辑。

Player实例在客户端和服务器上,我们都调用Move()方法,它将简单地执行以下操作。

        public void Move()
        {
    
    
            if (NetworkManager.Singleton.IsServer)
            {
    
    
                var randomPosition = GetRandomPositionOnPlane();
                transform.position = randomPosition;
                Position.Value = randomPosition;
            }
            else
            {
    
    
                SubmitPositionRequestServerRpc();
            }
        }

8 一些简单的RPC使用

如果这个玩家是服务器拥有的玩家,在OnNetworkSpawn()我们可以立即移动这个玩家,如下面的代码所示。

 if (NetworkManager.Singleton.IsServer)
        {
    
    
            var randomPosition = GetRandomPositionOnPlane();
            transform.position = randomPosition;
            Position.Value = randomPosition;
        }

如果我们是一个客户端,我们需要调用 ServerRpc。ServerRpc可以由客户端调用,在服务器上执行。

RPC函数需要用[ServerRpc] [ClientRpc]修饰,并且函数名必须以ServerRpc或ClientRpc结尾。

else
        {
    
    
            SubmitPositionRequestServerRpc();
        }

这个ServerRpc只是通过在平面上选择一个随机点,在这个玩家的服务器实例上设置位置网络变量。

   [ServerRpc]
    void SubmitPositionRequestServerRpc(ServerRpcParams rpcParams = default)
    {
    
    
        Position.Value = GetRandomPositionOnPlane();
    }

这个Player的服务器实例刚刚修改了位置网络变量,这意味着如果我们是一个客户端,我们需要在我们的更新循环中本地应用这个位置。

void Update()
{
    
    
	transform.position = Position.Value;
}

我们现在可以回到HelloWorldManager.cs,定义SubmitNewPosition()的内容

        static void SubmitNewPosition()
        {
    
    
            if (GUILayout.Button(
            	NetworkManager.Singleton.IsServer ? 
            		"Move" : "Request Position Change"))
            {
    
    
                var playerObject =		
               		NetworkManager.Singleton
               			.SpawnManager.GetLocalPlayerObject();
               			
                var player = 
                	playerObject.
                		GetComponent<HelloWorldPlayer>();
                		
                player.Move();
            }
        }

只要您按下GUI按钮(这取决于您是服务器还是客户端),您就会找到您的本地Player并简单地调用Move()


9 现在,您可以创建上述概念的demo。

一个构建实例可以创建一个 host ,另一个客户端可以加入 host 的游戏。

  • 两者都能够按下 GUI按钮 来移动,服务器将立即移动并在客户端上复制。
  • 客户端可以请求新的位置,这将指示服务器修改该服务器实例的位置网络变量。
  • 该客户端将在其Update()方法中应用该网络变量位置。

猜你喜欢

转载自blog.csdn.net/weixin_38531633/article/details/122921247