it-swarm.com.de

Wie synchronisiere ich GameObject-Eigenschaften von Nicht-Spielern in UNit/Unity 5?

Ich arbeite und lerne einige Grundlagen von Unity 5, UNET und Networking. Ich habe ein einfaches 3D-Spiel erstellt, in dem Sie herumgehen und die Farben von Objekten ändern. Aber ich möchte es jetzt zum Multiplayer-Modus machen und habe große Probleme damit, die Änderungen über das Netzwerk zu senden, damit alle Spieler die Farbänderung eines einzelnen Spielers sehen können.

Ein Teil des Problems ist, dass es schwierig war, die Antwort mit der neueren UNET-Netzwerk-Engine zu finden. Und manchmal stoße ich auf Antworten, die älter sind.

Die Hauptfrage lautet also: Wie kann ich Änderungen an der GameObject-Eigenschaft von Nicht-Spielern vernetzen? Farbe, form, größe, etc ..

Hier ist ein Code, den ich jetzt habe - und ich hatte viele verschiedene Versionen, also schreibe ich einfach die aktuelle:

 using UnityEngine;
 using System.Collections;
 using UnityEngine.Networking;

 public class Player_Paint : NetworkBehaviour {

     private int range = 200;
     [SerializeField] private Transform camTransform;
     private RaycastHit hit;
     [SyncVar] private Color objectColor;
     [SyncVar] private GameObject objIdentity;

     void Update () {
         CheckIfPainting();
     }

     void CheckIfPainting(){
         if(Input.GetMouseButtonDown(0)) {
             if (Physics.Raycast (camTransform.TransformPoint (0, 0, 0.5f), camTransform.forward, out hit, range)) {
                 string objName = hit.transform.name;
                 CmdPaint(objName);
             }
         }
     }

     [ClientRpc]
     void RpcPaint(){
         objIdentity.GetComponent<Renderer>().material.color = objectColor;
     }

     [Command]
     void CmdPaint(string name) {
         objIdentity = GameObject.Find (name);  //tell us what was hit
         objectColor = new Color(Random.value, Random.value, Random.value, Random.value);
         RpcPaint ();
     }
 }

Ich habe eine Reihe weiterer Lösungen ausprobiert, darunter das Schreiben eines separaten Skripts für die Objekte, deren Farbe ich ändern möchte, und das Einschließen von [SyncVar] und Hook-Funktionen. Ich habe auch Debug.Log für jede der Funktionen ausprobiert, von denen ich erwarte, dass sie die Objekte auf den Clients aktualisieren und sie mit den erwarteten Daten ausführen.

Ich weiß wirklich nicht, was ich sonst tun soll. Ich denke, es ist eine SEHR einfache Sache, die ich tun möchte, aber ich bin nicht auf die Synchronisierung von GameObjects von Nicht-Spielern in Fragen, Tutorials oder anderen Ressourcen gestoßen. Irgendwelche Ideen überhaupt wären hilfreich, danke.

6
Michael S

Ich habe meine Antwort gefunden. Und es war sehr schwierig, da sich fast jede einzelne Frage, jeder einzelne Beitrag, jedes einzelne Beispiel usw. auf Spielerobjekte und nicht auf Nicht-Spielerobjekte bezog.

Also musste ich die Funktion AssignClientAuthority verwenden. Was ich ein paar Mal versucht hatte, aber nicht richtig verwendete. Hier ist das funktionierende C # -Skript, das auf den Player angewendet werden soll:

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class Player_Paint : NetworkBehaviour {

    private int range = 200;
    [SerializeField] private Transform camTransform;
    private RaycastHit hit;
    [SyncVar] private Color objectColor;
    [SyncVar] private GameObject objectID;
    private NetworkIdentity objNetId;

    void Update () {
        // only do something if it is the local player doing it
        // so if player 1 does something, it will only be done on player 1's computer
        // but the networking scripts will make sure everyone else sees it
        if (isLocalPlayer) {
            CheckIfPainting ();
        }
    }

    void CheckIfPainting(){
        // yes, isLocalPlayer is redundant here, because that is already checked before this function is called
        // if it's the local player and their mouse is down, then they are "painting"
        if(isLocalPlayer && Input.GetMouseButtonDown(0)) {
            // here is the actual "painting" code
            // "Paint" if the Raycast hits something in it's range
            if (Physics.Raycast (camTransform.TransformPoint (0, 0, 0.5f), camTransform.forward, out hit, range)) {
                objectID = GameObject.Find (hit.transform.name);                                    // this gets the object that is hit
                objectColor = new Color(Random.value, Random.value, Random.value, Random.value);    // I select the color here before doing anything else
                CmdPaint(objectID, objectColor);    // carry out the "painting" command
            }
        }
    }

    [ClientRpc]
    void RpcPaint(GameObject obj, Color col){
        obj.GetComponent<Renderer>().material.color = col;      // this is the line that actually makes the change in color happen
    }

    [Command]
    void CmdPaint(GameObject obj, Color col) {
        objNetId = obj.GetComponent<NetworkIdentity> ();        // get the object's network ID
        objNetId.AssignClientAuthority (connectionToClient);    // assign authority to the player who is changing the color
        RpcPaint (obj, col);                                    // usse a Client RPC function to "Paint" the object on all clients
        objNetId.RemoveClientAuthority (connectionToClient);    // remove the authority from the player who changed the color
    }
}

!!! Wichtig !!! Jedes Objekt, auf das Sie sich auswirken möchten, muss über eine NetworkIdentity-Komponente verfügen und auf LocalPlayerAuthority festgelegt sein.

Dieses Skript dient nur dazu, eine zufällige Farbe zu ändern. Sie sollten jedoch in der Lage sein, das tatsächliche Material zu ändern, um dies auf jede Änderung der Materialien oder auf alles andere anzuwenden, das Sie mit einem Nicht-Player-Objekt vernetzen möchten. "Sollte" das optimale Wort sein - ich habe noch keine andere Funktionalität ausprobiert.

BEARBEITEN - Weitere Kommentare zu Lernzwecken hinzugefügt.

11
Michael S

Unity 5.3.2p3 Weisen Sie Client-Berechtigungen Nicht-Player-Objekten zu

Für alle, die daran interessiert sind, ist dies mein Ansatz

Clientseitige OnLocalPlayer-Komponente -> Rufen Sie Befehle auf, um Objektberechtigungen zuzuweisen und zu entfernen, indem Sie die Objekte NetworkInstanceId durchlaufen. Sie können eine beliebige Benutzeroberfläche hinzufügen, um diese Methoden für diese Komponente aufzurufen

Serverseite

    [Command]
    void CmdAssignObjectAuthority(NetworkInstanceId netInstanceId)
    {
        // Assign authority of this objects network instance id to the client
        NetworkServer.objects[netInstanceId].AssignClientAuthority(connectionToClient);
    }

    [Command]
    void CmdRemoveObjectAuthority(NetworkInstanceId netInstanceId)
    {
        // Removes the  authority of this object network instance id to the client
        NetworkServer.objects[netInstanceId].RemoveClientAuthority(connectionToClient);
    }  

Client-Seite 3. Objektkomponente ->
OnStartAuthority () - Erlaubt das Senden von Befehlen an den Server OnStopAuthority () - Erlaubt das Senden von Befehlen an den Server nicht

Das ist alles dazu!

2
GXMark

Für 2018:

Anstatt "Objektberechtigung zuweisen" zu verwenden,

Ich empfehle wirklich einfach mit

.SpawnWithClientAuthority

Es ist wirklich sehr einfach.

In der Tat ist es so einfach!

  [Command]
  void CmdPleaseSpawnSomething() {

        GameObject p = Instantiate(some_Prefab);
        NetworkServer.SpawnWithClientAuthority(p, connectionToClient);
    }

{In diesem Code beachte, dass "connectionToClient" magisch verfügbar ist ohne Aufwand - es bedeutet "der Client", der diesen Befehl aufgerufen hat.}

Rufen Sie auf dem Client (dem Sie das Ding "besitzen" möchten) einfach CmdPleaseSpawnSomething() auf.

Ich meine - das ist alles, Gott sei Dank.

Hier gibt es eine lange klare Erklärung:

https://forum.unity.com/threads/assign-authority-to-local-client-gameobject.371113/#post-3592541

1
Fattie

ich nehme eine kleine Änderung an diesem Code vor und füge dem Skript die Möglichkeit hinzu, wenn wir den Player platzieren, kann er die Änderung durch das Raycasting vornehmen.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class Raycasting_Object : NetworkBehaviour {

    private int range = 200;
//  [SerializeField] private Transform camTransform;
    private RaycastHit hit;
    [SyncVar] private Color objectColor;
    [SyncVar] private GameObject objectID;
    private NetworkIdentity objNetId;

    void Update () {
        if (isLocalPlayer) {    
            CheckIfPainting ();
        }
    }

    void CheckIfPainting(){

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        Debug.DrawRay (ray.Origin, ray.direction * 100, Color.cyan);

        if(isLocalPlayer && Input.GetMouseButtonDown(0)) {
            if (Physics.Raycast (ray.Origin, ray.direction, out hit, range)) {
                objectID = GameObject.Find (hit.transform.name);                                    // this gets the object that is hit
                Debug.Log(hit.transform.name);
                objectColor = new Color(Random.value, Random.value, Random.value, Random.value);    // I select the color here before doing anything else
                CmdPaint(objectID, objectColor);
            }
        }

    }

    [ClientRpc]
    void RpcPaint(GameObject obj, Color col){
        obj.GetComponent<Renderer>().material.color = col;      // this is the line that actually makes the change in color happen
    }

    [Command]
    void CmdPaint(GameObject obj, Color col) {
        objNetId = obj.GetComponent<NetworkIdentity> ();        // get the object's network ID
        objNetId.AssignClientAuthority (connectionToClient);    // assign authority to the player who is changing the color
        RpcPaint (obj, col);                                    // usse a Client RPC function to "Paint" the object on all clients
        objNetId.RemoveClientAuthority (connectionToClient);    // remove the authority from the player who changed the color
    }
}
0
Julio Quintero