如何在Unity网络中的两台设备上显示新创建的对象?

时间:2017-05-30 23:36:03

标签: unity3d networking multiplayer spawn

我正在使用Unity3D网络开展网络游戏。我是网络编程的新手。

假设我创建了对象并将它们附加到播放器(在服务器或客户端上)。我需要继续在另一台设备上显示这些对象。我见过很多材料,但我还没有找到解决方案。

看来NetworkServer.Spawn是一种方法。这是正确的,还有其他更好的方法吗?给这个新手一些建议^^谢谢。

2 个答案:

答案 0 :(得分:0)

如果您正在使用NetworkServer.Spawn,则需要在NetworkManager中注册预制件。

如果您不希望任何新人加入您的服务器,您也可以使用Command和ClientRPC生成此预制件并将其设为父级,以纠正每个客户端上的游戏对象。

答案 1 :(得分:0)

只有服务器/主机才能生成网络同步的GameObjects。

// put this component on a prefab you wish to spawn
class MyNetworkedObject : NetworkBehaviour
{
    [SyncVar]
    public int myHealth;

    void Start()
    {
        Debug.Log("My health is: " + myHealth);
    }
}

// put this component on an empty GameObject somewhere in the scene and check "Server Only" on its NetworkIdentity
class MySpawner : NetworkBehaviour
{
    public MyNetworkedObject myPrefab;

    void OnValidate()
    {
        if (GetComponent<NetworkIdentity>().serverOnly == false)
            Debug.LogWarning("This component wants NetworkIdentity to have \"Server Only\" checked (for educational purposes, not an actual requirement).");
    }

    public void SpawnObject(int withHealth)
    {
        if (!isServer)
            throw new Exception("Only server may call this! It wouldn't have any effect on client.");

        MyNetworkedObject newObject = Instantiate(myPrefab);
        // setup newObject here, before you spawn it
        newObject.myHealth = withHealth;

        NetworkServer.Spawn(newObject.gameObject);
    }
}

正如Fiffe已经提到的那样,预制件必须在NetworkManager中注册才能生成。此外,所有联网对象都必须具有NetworkIdentity组件。

一旦服务器生成了对象,服务器将告诉所有连接的客户端使用任何SyncVars的当前值以及稍后可能连接的任何客户端生成对象。如果SyncVars在服务器上发生更改,服务器将告知所有连接的客户端相应地更改值。

如果您希望客户端调用对象的产生,最简单的方法是使用Local Authority:

// put this component on the player prefab that you already assigned to NetworkManager.PlayerPrefab
class MyNetworkedPlayerObject : NetworkBehaviour
{
    void OnValidate()
    {
        if (GetComponent<NetworkIdentity>().localPlayerAuthority == false)
            Debug.LogWarning("This component requires NetworkIdentity to have \"Local Player Authority\" checked.");
    }

    public void RequestSpawnObject(int withHealth)
    {
        if (!hasAuthority)
            throw new Exception("Only the player owned by this client may call me.");

        // the following call will magically execute on the server, even though it was called on the client
        CmdSpawnObject(withHealth);
    }

    [Command]
    private void CmdSpawnObject(int withHealth)
    {
        // this code will always run on the server
        FindObjectOfType<MySpawner>().SpawnObject(withHealth);
    }
}

每个客户端都可以拥有一个或多个具有本地播放器权限的联网对象。每个联网对象或者由服务器拥有,或者由一个具有该对象的本地玩家权限的客户端拥有。客户端只能在该客户端具有本地播放器权限的对象上调用命令。命令由客户端调用,但在服务器上执行。此执行将异步发生,客户端无法知道服务器何时执行它。因此,命令可以有参数,但没有返回值。

此外:

  • 如果您希望所有客户端在网络对象上执行方法,则服务器可以在任何联网对象上调用[ClientRPC]方法,然后在客户端上执行。如果客户端稍后连接,它将调用在客户端连接之前发生的rpc调用。
  • 即使是使用本地播放机构管理员的客户也无法更改SyncVars。如果他们这样做,服务器和其他客户端将不会收到更改。只有服务器可以更改SyncVars并使其与客户端同步
  • 变换是一种特殊情况。对象可以具有NetworkTransform组件,该组件允许拥有客户端(或服务器)来控制该对象的位置和旋转,并使其与服务器和其他客户端同步。与NetworkAnimator相同。
  • 如果您想在运行时决定服务器或客户端是否拥有对象的权限,则必须为这两种情况预制一个预制件,一个具有&#34;本地播放器权限&#34;检查,一个没有。服务器永远不会是具有&#34;本地播放机构权限的对象的所有者。选中(但主机上的本地客户端可以)。
  • 客户端可以向服务器发送消息,反之亦然。

我希望这能给你一个简短的概述。