Jump to content
UnitySpain
ismael999

Ascensor multijugador

Recommended Posts

Buenas a todos, antes de nada decir que estoy empezando en unity, mi problema es el siguiente, tengo un ascensor con un script muy básico con una función(void) que lo mueve y esta es llamada desde otro script, todo esto función bien, el problema viene cuando entran 2 personas al servidor (hecho con los recursos de unity) lo que pasa es que cuando el que crea el servidor pulsa para subir el ascensor todo funciona perfecto sin embargo cuando lo hace el otro jugador solo funciona en su ordenador, el movimiento del ascensor no se ve reflejado en los otros jugadores.

¿Porque puede ser? Gracias de antemano. 

Share this post


Link to post
Share on other sites

Todo es cuestión de organizar bien, todo lo que quieras que esté sincronizado debe usar el networking, es decir el script del ascensor debe heredar de NetworkBehaviour.

Después debes conocer los atributos [Server], [Command] y [ClienRpc], para que el ascensor se mueva en todos los clientes debe ser el servidor el que llame la función "mover", para esto el cliente debe usar su player para llamar la función del ascensor desde el servidor, es bastante confuso al principio, pero intenta hacerte una idea:

jugador (cliente) -> Command -> jugador (servidor)  -> ascensor (servidor) -> ClientRpc -> ascensor(local).

También puedes hacerlo llamando la función en el ascensor en el cliente y sea éste quien se comunique con el servidor, de cualquier manera la complicación está en las referencias pues la inicialización con el networking no se limita al Awake y al Start.

 

Share this post


Link to post
Share on other sites
15 hours ago, juanma_teso said:

Todo es cuestión de organizar bien, todo lo que quieras que esté sincronizado debe usar el networking, es decir el script del ascensor debe heredar de NetworkBehaviour.

Después debes conocer los atributos [Server], [Command] y [ClienRpc], para que el ascensor se mueva en todos los clientes debe ser el servidor el que llame la función "mover", para esto el cliente debe usar su player para llamar la función del ascensor desde el servidor, es bastante confuso al principio, pero intenta hacerte una idea:

jugador (cliente) -> Command -> jugador (servidor)  -> ascensor (servidor) -> ClientRpc -> ascensor(local).

También puedes hacerlo llamando la función en el ascensor en el cliente y sea éste quien se comunique con el servidor, de cualquier manera la complicación está en las referencias pues la inicialización con el networking no se limita al Awake y al Start.

 

No necesariamente tienes que heredar desde NetworkBehaviour, tambien puedes identificar cada asensor con un ID unico en la escena, y luego que el "boton" que activa el le solicita la acción al servidor, imaginemos el comando como. 

Quote

useobject=IDDelAsensor => useobject=100

El servidor interpreta el comando aplica su logica y le envia  todos los clientes el mismo comando, cuando el cliente recibe este comando activa el asensor con x id.

Edited by pioj
Por favor, usa el <> o el "quote" para pegar código.

Share this post


Link to post
Share on other sites

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;

public class Ascensor : NetworkBehaviour
{
    public bool NetActive = false;

    public GameObject moveTo;
    public Button boton;

    private Vector3 startPos;
    private Vector3 endPos;
    public float velocidad = 5;


    void Start()
    {
        startPos = transform.position;
        endPos = moveTo.transform.position;
    }
    public void OnTriggerStay(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {
            boton.onClick.AddListener(active);
        }
        if (other.gameObject.tag == "Player" && Input.GetKeyDown(KeyCode.E))
        {
            active();
        }
    }
    public void active()
    {
      if (NetActive)
      {
        NetActive = false;
      }
      else
      {
        NetActive = true;
      }
    }
    void Update()
    {
        if (NetActive)
        {
            transform.position = Vector3.MoveTowards(transform.position, endPos, velocidad * Time.deltaTime);

        }
        else
        {
            transform.position = Vector3.MoveTowards(transform.position, startPos, velocidad * Time.deltaTime);
        }
    }
}

Lo he probado todo y nada me funciona, he probado el [Command] y el [ClientRpc] pero no logro hacer que funcione. Os he dejado el código del ascensor por si me podríais decir si es que se podría hacer de otra forma o si sabéis de algún vídeo donde explique algo de esto porque ya no se que mas hacer. 

Gracias por ayudar ;)

Share this post


Link to post
Share on other sites

Siempre dije que UNET haría esto...

Ese código nunca va a funcionar, si el cliente y el servidor no tienen ninguna conexión estas creando un objeto Network sin ningún sentido -

LA LÓGICA no tiene que convivir con la capa de RED. Por lo cual mezclar las dos cosas es la peor práctica posible.

Todos los Clientes activan el ascensor desde un boton, ese botón envia un mensaje al GameManager "activa el ascensor número 3", el GameManager detecta que estás en una partida en RED y le ENVÍA la solicitud al Servidor, el servidor valida la petición y envia a todos los clientes un mensaje "activar el ascensor 3", el cliente tiene un interprete para los mensajes del servidor, este reconoce el comando y hace la acción solicitada.

¿Se entiende? el Ascensor, el Botón, y el GameManager NO TIENEN herencias o dependen de componentes NetworkBehaviour.

NetworkBehaviour dejalo solo para crear una clase NetworkConn donde tengas todas las funciones necesarias como SendCommand, SendAction, RequestState, RequestEvent, etc... 

 

Share this post


Link to post
Share on other sites

Entiendo a lo que te refieres y seguro que es más eficiente, pero no creo que sea necesario que se complique tanto ni que vaya a crear tantos ascensores como para necesitar ese tipo de optimización...

Viendo tu código te aviso que es bastante complicado sincronizar bien la posición y si quieres físicas (que el ascensor mueva los jugadores) ya ni te cuento, además no veo dónde has metido los Command ni ClientRpc.

Dejando de lado que los jugadores se muevan o no con el ascensor, y viendo cómo lo tienes hecho yo haría lo siguiente:

public class Ascensor : NetworkBehaviour
{
	Vector3 inicio;
	Vector3 final;
	float velocidad;
	bool subir;
	bool bajar;
	
	
	[ClientCallback]
	void OnTriggeStay (other Collider)
	{
		if(other.gameObject.tag == "player")
		{
			//Aquí además de que pulse la tecla tienes que comprobar que el que la pulse esté dentro del ascensor
			if(Input.GetKeyDown (KeyCode.E))
				CmdActivar ();
		}
	}

	[Server]
	void Activar ()
	{
		if(transform.position == final && !subir)
			bajar=true;
		if(transform.position == inicio && !bajar)
			subir=true;
	}

	[ServerCallback]
	void Update ()
	{
		if(subir)
		{
			transform.position = Vector3.MoveTowards(transform.position, final, velocidad * Time.deltaTime);
			if(transform.position == final)
				subir = false;
			RpcActualizarPosicion (transform.position);
		}
		if(bajar)
		{
			transform.position = Vector3.MoveTowards(transform.position, inicio, velocidad * Time.deltaTime);
			if(transform.position == final)
				bajar = false;
			RpcActualizarPosicion (transform.position);
		}
	}

	[Command]
	void CmdActivar ()
	{
		Activar ();
	}
	
	[ClientRpc (channel = 1)]
	void RpcActualizarPosicion (Vector3 pos)
	{
		//Aquí podrías interpolar para que se vea mejor
		transform.position = pos;
	}
}

También estaría bien que empieces por cosas más simples antes de meterte a Networking.

Share this post


Link to post
Share on other sites
3 hours ago, juanma_teso said:

Me parece excesivo crear un GameManager para ascensores, y crear una estructura propia... no sé para eso ya está el networking de Unity, qué hay de aquello de "no reinventar la rueda"? @francoe1

No, ¡HLAPI de UNET intenta reinventar la RUEDA!. Los desarrolladores con bajos conocimientos en NETWORKING no deberían tener contacto con estas librerías sin antes entender conceptos tan básicos como el Modelo OSI, protocolos de conexión, serialización de información, y varios conceptos más necesarios para entender qué está haciendo.

Mi propuesta es que detenga el desarrollo, e intente armar cosas simples como Chats TCP luego pasarlo a UDP, intentar en JavaScripts utilizar WebSockets con Node.js y otras tantas prácticas que van a ir dando los recursos necesarios para luego saltar a una librería y comprender qué es lo que está haciendo, para poder utilizarla.

@juanma_teso Me parece interesante que propongas una idea diferente, y estaría bueno poder analizar las pro y las contras de cada situación para poder sacar una conclusión con fundamentos.

 

Saludos.

Share this post


Link to post
Share on other sites

×
×
  • Create New...