2015-11-02 6 views
4

Я занимаюсь изучением некоторых основ Unity 5, UNET и сетей. Я сделал простую 3D-игру, в которой вы идете и меняете цвета объектов. Но сейчас я хочу сделать это многопользовательской, и у меня много проблем с выяснением того, как отправлять изменения по сети, чтобы все игроки могли видеть изменение цвета одного игрока.Как синхронизировать свойства Game Player в Unet/Unity5?

Часть вопроса состоит в том, что было трудно найти ответ, используя новый сетевой механизм UNET. И иногда я сталкиваюсь с ответами, которые для более старшего.

Итак, главный вопрос заключается в том, как изменить свойства свойства GameIbject, не являющегося игроком? Цвет, форма, размер и т.д ..

Вот код, я сейчас - и у меня было много разных версий, так что я просто выкладываю текущий:

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

Я пытался набор дополнительных решений, включая написание отдельного сценария для объектов, цвет которых я хочу изменить, включая функции [SyncVar] и hook. Я также попробовал Debug.Log по каждой из функций, которые я ожидаю обновить на объектах, и они выполняются с ожидаемыми данными.

Я действительно не знаю, что еще делать. Я чувствую, что это ОЧЕНЬ простая вещь, которую я хочу сделать, но я не сталкивался с синхронизацией non-player GameObject в любых вопросах, учебниках или других ресурсах. Любые идеи вообще были бы полезны, спасибо.

+0

«Я чувствую, что это очень простая вещь, которую я хочу сделать, но я не встречал синхронизируется неигровых GameObject в любой вопросы, учебники и другие ресурсы.» Мои разочарования ТОЧНО. –

ответ

11

Я нашел свой ответ. И это было очень сложно, так как почти каждый вопрос, пост, пример и т. Д. Я мог бы найти информацию об объектах игроков, а не о не-игровых объектах.

Итак, мне нужно было использовать функцию AssignClientAuthority. Который я пробовал пару раз, но не использовал его правильно. Вот функционирование C# скрипт, чтобы применить к игроку:

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

!!! Важно !!! Каждый объект, который вы хотите повлиять должны иметь компонент NetworkIdentity, и он должен быть установлен в LocalPlayerAuthority

Так что этот сценарий просто изменить случайный цвет, но вы должны быть в состоянии изменить фактический материал, чтобы применить это на любые изменения в материалах или что-либо еще, что вы хотите подключить к объекту, отличному от игрока. «Должно быть« оптимальным »- я еще не пробовал с какой-либо другой функциональностью.

EDIT - добавлено больше комментариев для учебных целей.

+0

Это ответ, который я искал! Спасибо. AssignClientAuthority и RemoveClientAuthority были существенными, и я также использовал их неправильно. –

+1

Отличный !! Я рад, что смогу помочь! Я был серьезно удивлен, что не смог найти этот ответ в любом месте в Интернете. Я также пробовал этот же скрипт, просто заменив функциональность, чтобы изменить размер, а не «перерисовать», и он работал так же просто. –

+0

@MichaelS я могу получить краткое изложение того, как это работает, поскольку у меня есть объект в игре, на который игрок может смотреть, а другой объект перемещает местоположение, пока они смотрят на него, когда затем отводится в сторону, он возвращается к оригиналу должность. После многих часов я не могу заставить это синхронизировать с обоими игроками или иметь его так, чтобы любой игрок мог реально повлиять на объект. –

2

Unity 5.3.2p3 Присвоить Client Орган Non-плеер объекты

Для тех, кто заинтересован в ее настройке это мой подход

сторона клиента OnLocalPlayer компонент -> Вызов команды для назначения и удаления объекта полномочий по проходя через объекты NetworkInstanceId. Вы можете добавить любой пользовательский интерфейс, чтобы вызывать эти методы на этом компоненте

стороне сервера

[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 Side 3.Компонент Object ->
OnStartAuthority() - разрешено отправлять команды на сервер OnStopAuthority() - не разрешено отправлять команды на сервер

Это все есть на него!

0

Я делаю небольшую модификацию этого кода и добавляю возможность сценария, если мы поместим игрока, он может внести изменения через raycasting.

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