5

Ich habe ein Spielerobjekt, das mehrere Waffen ausrüsten kann. Wenn eine Waffe ausgerüstet ist, wird der Elternteil der Verwandlung auf seine Hand gesetzt. Ich habe mich schon seit geraumer Zeit damit beschäftigt und kann das sowohl für den Gastgeber als auch für den Kunden nicht schaffen. Gerade jetzt versuche ich die Waffe auf dem Server auszustatten und sage allen Clients, dass sie ihre Eltern transformieren sollen.Unity 5.1 Networking - Spawn ein Objekt als Kind für den Host und alle Clients

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; 
    } 

Und in dem Update Ich bin Aktualisierung der Waffen

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; 
      } 
     } 
    } 

verwandeln Ich weiß, das ist nicht die Art und Weise optimiert jetzt zu tun this..but ich nur versucht, mich zu bekommen das funktioniert so gut wie möglich und dann daran arbeiten, es zu optimieren. Es scheint, als sollte es eine einfache Aufgabe sein.

Antwort

10

Wir machen eine ähnliche Sache in unserem Multiplayer-Spiel. Es gibt ein paar Dinge, die Sie tun müssen, damit das funktioniert. Erstens, das Konzept:

Einstellung der Waffe Eltern auf dem Server ist trivial, wie Sie gefunden haben. Legen Sie einfach das übergeordnete Element der Transformation wie normalerweise in Unity fest. Nachdem dieses Objekt auf dem Server mit NetworkServer.Spawn erstellt wurde, wird es jedoch später auf Clients im Stammverzeichnis der Szene generiert (die Hierarchie außerhalb des generierten Prefab ist nicht synchronisiert).

Also, um die Hierarchie auf dem Client einstellen würde ich vorschlagen, dass Sie:

  • ein SyncVar Verwenden Sie die netID des übergeordneten Objekts zwischen dem Server und dem Client zu synchronisieren.
  • Wenn das Objekt auf dem Client generiert wird, suchen Sie das übergeordnete Element mit der synchronisierten netID und legen Sie es als übergeordnetes Element Ihrer Transformation fest.

Deshalb würde ich Ihren Code in etwa so aussehen einzustellen. Stellen Sie zuerst die Eltern-NetId der Waffe ein, bevor Sie sie spawnen. Dadurch wird sichergestellt, dass die NetId festgelegt wird, wenn sie auf Clients generiert wird.

[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 
} 

Und dann in die Waffe Klasse:

  • eine parentNetId Eigenschaft hinzufügen.
  • Markieren Sie es als [SyncVar], damit es zwischen Server- und Clientkopien synchronisiert.
  • Suchen Sie bei der Ausführung auf einem Client das übergeordnete Objekt mithilfe der netId und legen Sie es als übergeordnetes Element für die Transformation fest.

Vielleicht so etwas wie:

[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); 
} 
+0

Ich versuche, diese Methode zu verwenden. Gibt es einen Grund, warum sich die "NetId" ändern würde? Ich setze es nur wie im Beispiel in 'OnStartClient'. –

+0

Kann nicht glauben, dass dies der Weg ist, dies zu tun .. verdammt! –

+0

Warum hast du meine Bearbeitung rückgängig gemacht? Ich habe die Code-Hervorhebung hinzugefügt, um Ihren Code viel besser zu lesen. – derHugo

4

fand ich diesen Beitrag wirklich nützlich, aber ich habe einen kleinen Nachtrag.

Die NetId befindet sich im Wurzelverzeichnis der Hierarchie, daher ist es nützlich zu wissen, dass Sie die Hierarchie mithilfe von transform.Find durchsuchen können.

So etwas wie ..

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

    transform.SetParent(parentObject.transform.Find(pathToWeaponHolder)); 
0

Nachdem Andy Barnards Lösung zu lesen, kam ich mit dieser leicht modifizierte Lösung auf. Anstelle einer SyncVar gibt es einen Client-RPC, mit dem der Server jederzeit anrufen kann, wenn ein NetworkIdentity die Eltern ändern muss. Dies erfordert, dass das übergeordnete Element auch über NetworkIdentity verfügt (obwohl es kein registriertes Prefab sein muss).

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); 
} 

Diese beiden sind Teil eines NetworkBehavior, was offensichtlich RequiresComponent(typeof(NetworkIdentity)). Wenn Sie dieses Verhalten wirklich auf einem Client vom Server benötigen, würde ich vorschlagen, einen Befehl zu erstellen, der die NetworkIdentity an den Server übergibt, der einfach die öffentliche Methode des Servers aufrufen würde. Es ist eine Reihe von Netzwerk-Nachrichten mehr als optimal, aber meh.

Verwandte Themen