6

複数の武器を装備できるプレイヤー オブジェクトがあります。武器を装備すると、そのトランスフォームの親がその手に設定されます。私はしばらくこれをいじっていましたが、これをホストとクライアントの両方で機能させることができません。現在、私はサーバーに武器を装備しようとしており、すべてのクライアントに親の変換を設定するように指示しています。

public NetworkInstanceId weaponNetId; 

   [Command]
    void Cmd_EquipWeapon()
    {
        var weaponObject = Instantiate (Resources.Load ("Gun"),
                                        hand.position,
                                        Quaternion.Euler (0f, 0f, 0f)) as GameObject;

        weaponObject.transform.parent = hand;

        NetworkServer.Spawn (weaponObject);

        //set equipped weapon
        var weapon = weaponObject.GetComponent<Weapon> () as Weapon;

        weaponNetId = weaponObject.GetComponent<NetworkIdentity> ().netId;
        Rpc_SetParentGameobject (weaponNetId);
    }

    [ClientRpc]
    public void Rpc_SetParentGameobject(NetworkInstanceId netID)
    {   
        weaponNetId = netId;
    }

そして更新では、武器の変換を更新しています

    void Update () {

    // set child weapon tranform on clients
    if (!isServer) {
        if (weaponNetId.Value != 0 && !armed) {
            GameObject child = NetworkServer.FindLocalObject (weaponNetId);


            if (child != null) {
                child.transform.parent = hand;
            }
        }
    }

私はこれがこれを行うための最も最適化された方法ではないことを知っています。それは単純な作業であるように思われます。

4

3 に答える 3

16

マルチプレイヤー ゲームでも同様のことを行います。これを機能させるには、いくつかの作業を行う必要があります。まず、コンセプト:

サーバーで武器の親を設定するのは簡単です。Unity で通常行うように、変換の親を設定するだけです。ただし、 を使用してサーバー上でこのオブジェクトをNetworkServer.Spawnスポーンした後、シーンのルートにあるクライアント上で後でスポーンされます (スポーンされたプレハブの外部の階層は同期されません)。

したがって、クライアントの階層を調整するには、次のことをお勧めします。

  • SyncVar を使用して、サーバーとクライアントの間で親オブジェクトの netID を同期します。
  • オブジェクトがクライアントでスポーンされたら、同期された netID を使用して親を見つけ、それを変換の親として設定します。

したがって、コードを次のように調整します。まず、スポーンする前に武器の親 netId を設定します。これにより、クライアントで生成されたときに netId が設定されます。

[Command]
void Cmd_EquipWeapon()
{
    var weaponObject = Instantiate (Resources.Load ("Gun"),
                                    hand.position,
                                    Quaternion.Euler (0f, 0f, 0f)) as GameObject;
    weaponObject.parentNetId = hand.netId; // Set the parent network ID
    weaponObject.transform.parent = hand; // Set the parent transform on the server

    NetworkServer.Spawn (weaponObject); // Spawn the object
}

そして、あなたの武器クラスで:

  • parentNetId プロパティを追加します。
  • [SyncVar]サーバーとクライアントのコピー間で同期するようにマークします。
  • クライアントで生成されたら、netId を使用して親オブジェクトを見つけ、それを変換の親に設定します。

おそらく次のようなものです:

[SyncVar]
public NetworkInstanceId parentNetId;

public override void OnStartClient()
{
    // When we are spawned on the client,
    // find the parent object using its ID,
    // and set it to be our transform's parent.
    GameObject parentObject = ClientScene.FindLocalObject(parentNetId);
    transform.SetParent(parentObject.transform);
}
于 2015-07-14T21:04:51.307 に答える
5

この投稿は非常に役に立ちましたが、小さな補遺があります。

netId は階層のルートにあるため、transform.Find を使用して階層をたどることができることを知っておくと役立ちます。

このようなもの ..

GameObject parentObject = ClientScene.FindLocalObject(parentNetId);
    string pathToWeaponHolder = "Obj/targetObj";

    transform.SetParent(parentObject.transform.Find(pathToWeaponHolder));
于 2016-09-15T19:27:50.660 に答える
1

Andy Barnard のソリューションを読んだ後、このわずかに変更されたソリューションを思いつきました。NetworkIdentitySyncVar の代わりに、サーバーが親を変更する必要があるときに呼び出すクライアント RPC があります。これには、親にも が必要ですNetworkIdentity(ただし、登録済みのプレハブである必要はありません)。

public void Server_SetParent (NetworkIdentity parentNetworkIdentity) {
    if (parentNetworkIdentity != null) {
        // Set locally on server
        transform.SetParent (parentNetworkIdentity.transform);
        // Set remotely on clients
        RpcClient_SetParent (parentNetworkIdentity.netId, resetTransform);
    }
    else {
        // Set locally on server
        transform.SetParent (null);
        // Set remotely on clients
        RpcClient_SetParent (NetworkInstanceId.Invalid, resetTransform);
    }
}

[ClientRpc]
void RpcClient_SetParent (NetworkInstanceId newParentNetId) {
    Transform parentTransform = null;
    if (newParentNetId != NetworkInstanceId.Invalid) {
        // Find the parent by netid and set self as child
        var parentGobj = ClientScene.FindLocalObject (newParentNetId);
        if (parentGobj != null) {
            parentTransform = parentGobj.transform;
        }
        else {
            Debug.LogWarningFormat ("{0} Could not find NetworkIdentity '{1}'.", gameObject.name, newParentNetId.Value);
        }
    }
    transform.SetParent (parentTransform);
}

これら 2 つはNetworkBehavior明らかにの一部ですRequiresComponent(typeof(NetworkIdentity))。クライアントからサーバーへのこの動作が本当に必要な場合は、 をサーバーに渡すコマンドを作成することをお勧めしNetworkIdentityます。これは、サーバーの public メソッドを呼び出すだけです。これは、ネットワーク メッセージの 1 つのセットであり、最適ではありませんが、まあまあです。

于 2017-10-18T16:01:04.733 に答える