Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

P3 - UNET [Networking] - Sistema de Salud

Iniciado por francoe1, Febrero 04, 2016, 06:53:18 PM

Tema anterior - Siguiente tema
Febrero 04, 2016, 06:53:18 PM Ultima modificación: Febrero 04, 2016, 10:28:43 PM por francoe1
Bienvenidos a otro tutorial de UNET.Como vimos en anteriores tutoriales, para poder sincronizar una variable en nuestro jugador locas debemos primero asignarla y luego enviar ese valor al servidor. EJ : (P-Local) Cambió su posicion --(Envia a traves de comando su nueva posicion al servidor)--> (SERVER) El servidor recibe estos datos y los envía a todos los Clientes.
Teniendo esto en cuenta, para lograr un Sistema de Salud funcional debemos primero tener el valor de la salud actual, un evento que se llame cuando muere, 2 funciones una de daño y la otra de recuperación, y por ultimo el comando para enviar el estado de nuestra salud.Vemos... Primero creamos lo básico.
public const int MaxHealt = 100;
[SyncVar]
public int Healt;

public delegate void d_Death();
[SyncEvent]
public event d_Death EventDeath;

[Client]
public void TakeDamage(int value)
{
    Healt -= value;
    Healt = Mathf.Clamp(Healt,0,MaxHealt);
}

[Client]
public void TakeCure(int value)
{
    Healt += value;
    Healt = Mathf.Clamp(Healt,0,MaxHealt);
}
bien con esto ya tendríamos nuestro Sistema de salud casi terminado, pero debemos tener algunas cosas en cuenta.
  1. Jamás un jugador va a poder infringir directamente daño a otro, de esto se encarga el servidor, pero existe una problemática, cuando nosotros ejecutamos un disparo, este evento es gestionado por el servidor, entonces es el Servidor en nombre de X Cliente dueño del disparo, supongamos que este impacta con otro jugador, ¿Quien resta la salud?, La respuesta es el Servidor. Es decir, si nosotros llamamos una funciona cualquiera desde un comando estamos haciéndolo en nombre del servidor.

    (CLIENTE) ---> Ejecuta ---> COMMAND ---> (SERVIDOR) ---> Ejecuta Funcion ---> TakeDamage();
     
  2. Dicho lo anterior, podremos darnos cuanta de que no existe interacción Cliente/Cliente por lo que esto se denomina Cliente/Servidor. ¿Cual es realmente la problemática?, Aunque existan varios problemas relacionados solo con un sistema de salud, deberíamos destacar el mas importante. El Jugador local solo debe enviar su estado, no hay que confundir, es decir, el servidor no se debe de encargar de procesar si está muerto o no, para eso creamos nuestro sistema. Vi muchos errores a la hora de implementar funciones incoherentes, por ejemplo, que todos los jugadores comprueben si la salud es menor o igual a cero entonces esta muerto.
     
    void Update()
    {
        if(Healt <= 0)
        {
            IsDeath = true;
        }
    }
    Esto es un grave error, porque los tiempos de sincronización pueden variar según el Ping (Tiempo de Envío y Recibo de Datos) que el Cliente y servidor tengan. vamos a dar un Ejemplo: 
    Tenemos 4 Clientes en un servidor, Cliente 1 dispara y le quita 100 de salud al Cliente 2 Esta acción tomó un tiempo de.
    1- Cliente 1 (Enviar Datos del disparo al Servidor y Retornar Resultados) : 2s
    2- Cliente 2 (Recibe la noticia de que se le a impactado, el servidor llama a su función TakeDamage(), luego, el Cliente 2 envía los dato de su estado al Servidor) : 4s
    3- Clientes (Servidor Actualiza el Estado del Cliente 1 en todas las instancias del juego, diciendo que el valor de Healt es cero) 1s

    Vemos que en el Punto 1 el Cliente 1 ya sabe que le infligió daño al Cliente 2, pero aun el Cliente 2 no se enteró, suponiendo que el primer paso Duro solo 1s, ya que el segundo añadido es el tiempo que el Servidor tardó en enviar esa información al Cliente 1, el Cliente 2, por lo tanto recibe daño, y envía el valor de Healt al servidor, 4s + 1s que el servidor toma para enviar los datos de este evento al Cliente 3, 4 es el retardo que existiría, suponiendo así, que cada instancia debería comprobar aún si el Cliente 2 está vivo, pero qué pasa si en ese lapso de 4 segundo el Cliente 2 sobrevive, es decir, un ejemplo, lo reviven estilo BF, el Cliente 1,3,4 tendrían una mala información. en destiempo.
  3. Aunque el ejemplo en cierta forma parece no tener coherencia el problema se presenta cuando múltiples clientes con distintos tiempos de respuestas se conectan al servidor, este error puede llegar a hacernos ver el jugador muerto disparando. 
¿Cómo lo solucionamos?La solución en cierta parte, sería utilizar Eventos, va a seguir existiendo un tiempo de retardo, es normal, pero la información de las instancias de cada cliente va a ser más clara.
 
[SyncVar]
internal bool IsDeath;
[SyncEvent]
public event d_Death EventDeath;

void Update()
{
    if(!isLocalPlayer)return;
   
    if(Healt <= 0 && !IsDeath)
    {
        IsDeath = true;
        if(EventDeath != null)EventDeath();
        Cmd_SendInfo(Healt,IsDeath);
    }
}

[Command]
private void Cmd_SendInfo(int healt, bool isDeath)
{
    Healt = healt;
    IsDeath = isDeath;
    if(IsDeath)if(EventDeath != null)EventDeath();
}
De esta manera estamos enviando de una manera, quizas un poco desprolija nuestra información al servidor,  pero si prestaron atención en la función Update, se agregó un condicional para saber si es el jugador local, ya que solo él, podrá gestionar su salud y avisar al servidor su estado.Hay que entender, que aunque Unet Serialize nuestros datos y los optimice podemos ayudar también nosotros, a que esta tarea sea aun mas optima, por ejemplo enviando un string formateado de una manera para guardar el valor de nuestras variables. 
string Data = "100/0";

[Command]
private void Cmd_SendInfo(string data)
{
    string[] values = data.Split('/');
    Healt = int.Parse(values[0]);
    IsDeath = int.Parse(values[1])? false : true;
    Data = data;
}

de esta manera optimizamos el paquete, ya que solo enviamos un dato.
Bueno eso es todo por ahora, espero les sirva. Para tener un poco más organizados mis tutoriales abrí un Blogger donde encontraran todo mi material y podrán seguir mis tutoriales de UNET.http://unitydoc.blogspot.com.ar/">http://unitydoc.blogspot.com.ar/Saludos 

Etiquetas: