Hola que tal!
Estoy desarrollando un juego con la 39DLL y mi pregunta es la siguiente:
¿Cuál es el mejor método para recibir coordenadas de varias instancias del mismo objeto?
Según como lo he programado tengo del lado del Servidor un arma que ,obviamente, dispara. Sin embargo el Cliente solo recibe las coordenadas de la última instancia creada por el servidor, es decir, que a la próxima que crea se leen las coordenadas y la ya antes creada queda pegada en la pantalla sin moverse.
Entonces, ¿Cómo podría hacer para que el Cliente lea las coordenadas de todas las instancias que crea el Servidor?
Tenía en mente usar listas o arreglos , pero no sé cómo podría programarlas. Y si es, además, un método efectivo.
Saludos!
Saludos makera Silver_light:
Ante todo ¡feliz año nuevo!, te deseo mucha salud y dinero... que el resto se puede comprar... XD
Mi propuesta es que no solo envíes al cliente las coordenadas del objeto arma creado en el servidor, sino que también envíes el identificador de esa arma. Por ejemplo: (arma1, x, y), (arma2, x, y), etc. Asi sabrás de que arma es cada coordenada. Y por supuesto que el uso de arreglos es recomendado para llevar el control de todos estos datos. Tengo entendido que son más eficientes que las listas.
Cada arma creada en el servidor debe ser enviada al cliente y de esta forma es que se pueden leer. Consejo, crea una lista de las armas creadas y sus coordenadas en el cliente y en el servidor. De esta forma tendrás más control de cada arma desde ambos lados.
Espero te sirva de algo, un saludo. ;D
Ferhand, las listas son mucho más eficientes en muchos sentidos
Pero sí, básicamente necesitás ponerle un identificador a cada instancia cuando se crea y al asignar buscás con with(object) y comprobás que el identificador sea igual al que te enviaron
Saludos Makera Silver_light y Makero Texic:
Disculpa hermana si tomo tu espacio de pregunta para una corta discusión. :-*
Lo siento hermano Texic, pero estoy en desacuerdo contigo. :-[
Las listas en el tras fondo están programadas utilizando Arreglos (array[a,b]), por lo que son una interfaz para el trato con los mismos. En lo único que yo veo eficiencia en las listas es que desde el lado del programador es menos engorroso a la hora de insertar un nuevo elemento en cualquier posición de la lista, o a la hora de organizar sus elementos basados en algún criterio. Aún así el programa guarda por cada lista una serie de parámetros que muchas veces no vamos a utilizar y sin embargo ocupan espacio en memoria.
Los arreglos se pueden utilizar del mismo modo, la dificultad es que tenemos que programar las acciones que necesitamos ya sean insertar un elemento, ordenar o eliminar, etc. Lo bueno es que es una primitiva del lenguaje y no guardará parámetros extras al tiempo que se ejecutan con rapidez. 8)
Es solo mi opinión, a lo mejor estoy dejando pasar algo por alto. El problema es que me encanta discutir y vi la oportunidad para hacerlo. :P Disculpa Silver_light y Texic. Todo es para aprender y divertirnos. ;D
Jaja, no hay problema, pero no tuviste en cuenta un par de aspectos. Para buscar un valor en un array hay que recorrer con un for, que es mucho más lento que ds_list_find_index. O para ordenar los valores de un array de forma ascendente, en un array es un dolor de cabeza, para las ds_list hay una función muy simple y eficiente. Para quitar un valor en un array lo mismo, tenés que andar recorriendo con un for de vuelta y moviendo todo de lugar, en la ds_list es una sola función. La diferencia principal radica en que las funciones internas que ejecuta la ds_list están previamente compiladas, y los scripts o códigos que vos crees con tus arrays son interpretados, la diferencia de velocidad es abismal
Cita de: Texic en Enero 07, 2013, 06:24:24 PMLa diferencia principal radica en que las funciones internas que ejecuta la ds_list están previamente compiladas, y los scripts o códigos que vos crees con tus arrays son interpretados, la diferencia de velocidad es abismal
¡Anjá, yo sabía que me pasaba algo por alto! En ese caso la ejecución de lista debe ser mucho más rápida... Pido disculpas por mi error y le sugiero a Silver_light que considere tu consejo.
Hermano, particularmente estoy utilizando "arrays" en el diseño de mi juego. Los utilizo por el aquello de los índices, los necesito, pero si las listas son mejores...¿Crees que las estructuras como los "grid" sean más eficientes que un "array" 2D? Lo pregunto pues en mi diseño tengo montones de "arrays" bidimensionales en memoria ram.
Pido disculpas si ya esto se sale del tema...¿Debería crear uno nuevo...? :-[
Las grid más o menos, a mi me resultan cómodas para guardarlas y cargarlas, pero no traen demasiadas funciones útiles, la de búsqueda sería la que más destaca. Lo que uso con frecuencia para la 39dll son los stacks, resultan útiles en juegos de movimiento rpg por cuadrícula. Las list son las que más funciones útiles traen
Estoy de regreso ... con información fresca:
Saludos y al debate...
Los "arrays" son estructuras que guardan datos en "Ram" en espacios de memoria contiguos. Cuando se desea insertar otro elemento se debe crear un "array" nuevo con un elemento de más y copiarle la información que existía en el otro "array" incluyendo el cambio. Todo este trabajo es por la razón de que el sistema debe encontrar un espacio lo suficientemente grande para que quepa el nuevo "array" todo de un golpe. A la hora de ir directamente a algún indice, el sistema tiene como llegar sin mayores complicaciones.
Si embargo, las listas se guardan en la "Ram" de otra forma. Cada elemento de la lista es una estructura llamada nodo, formada por dos piezas, en una está el valor y en la otra está la dirección de memoria del próximo nodo (índice). Para alcanzar algún nodo (indice) dentro de la lista hay que recorrerla pues la dirección de memoria de dicho nodo está en el nodo anterior. Si queremos alcanzar el nodo (índice) 3 debemos acceder al nodo 2 pues en él esta la dirección del nodo 3, pero para acceder al nodo 2 debemos acceder al nodo 1 pues en él está la dirección del nodo 2. Todo esto lo hace el sistema por detrás, pero es bien lento cuando se tiene una lista muy grande.
Yo no recordaba estos detalles de cuando estudiaba progarmamción. Aún así la documentación de GM dice "They are implemented using simple arrays but, as this is done in compiled code it is a lot faster than using an array yourself." Lo cual es irrefutable por mi.
¡Por lo tanto ha usar listas....!!!! XD XD XD XD
¡Texic, tenías razón...! ;D
Saludos again!
Interesante debate, lastima que no entendí mucho el final :-[
Em... bueno de la forma en que yo lo programé era de la siguiente forma:
Al presionar el boton X, el arma dispara, entonces en ese momento envia el byte al cliente indicando que debe crear una instancia de bala:
Citar
clearbuffer();
writebyte(5);
sendmessage(global.tcp_cliente);
En el objeto que recibe los datos quedó así:
Citar
case 5:
disparo = instance_create(0,0,disparo);
break;
Luego el disparo del servidor enviaba su identificador, la coordenada X e Y:
Citar
clearbuffer();
writebyte(6);
writeuint(id);
writeshort(x);
writeshort(y);
sendmessage(global.tcp_cliente);
Despues el objeto que recibe los datos leía estas coordeanadas, con:
Citar
case 6:
disp = readuint();
disp.x = readshort();
disp.y = readshort();
Esa es la forma que opté por hacer de acuerdo a la primera respuesta de Ferhand.
Ahora, cómo implementaría la forma que dices tu, Texic?
¿Esa forma, la probaste? ¿Y funciona? Porque para que funcione, el id de las balas en el cliente y el servidor debería estar sincronizado, y es muy difícil que pase...
Yo te recomendaría lo siguiente.
Para crear la bala:
[gml]clearbuffer();
writebyte(5);
writeuint(id); // Enviás el id de la bala también.
sendmessage(global.tcp_cliente);[/gml]
Al recibir el paquete de creación de bala:
[gml]case 5:
with (instance_create(0, 0, disparo)) {
remote_id = readuint();
}
break;[/gml]
El código para enviar las coordenadas como lo pusiste en el post anterior, y el código para recibirlas:
[gml]case 6:
var recieved_remote_id = readuint();
with (disparo) {
if (remote_id == recieved_remote_id) {
x = readshort();
y = readshort();
break;
}
}
break;[/gml]
No estoy seguro de si se puede usar break en un with. Si no se puede, sacalo, el código quedaría menos optimizado pero debería seguir funcionando.
EDIT: Por cierto, ahora que me fijo esto es exactamente lo que propuso Texic su primer post en el tema.
Es para una bala? Silver, es mejor enviar la dirección, la velocidad y las coordenadas iniciales en el byte y asignarlos al crear, que el cliente saque sus propios cálculos, sino es un mambrollo de datos volando de un lado a otro y jamás te va a funcionar bien en wan
Había usado lo que coloqué y funcionaba bien, si se ponia +1 o -1 en el id que se enviaba.
Por ejemplo:
Citarclearbuffer();
writebyte(6);
writeuint(id+1);
writeshort(x);
writeshort(y);
sendmessage(global.tcp_cliente);
-Pero claro pensé que algo como eso estaría mal y podría afectar en un futuro.
Usé el metodo de Wadk, que es el que propuso Texic, y que no sabía como aplicarlo, así que gracias por contestar.
Cita de: Texic en Enero 09, 2013, 09:03:37 PM
Es para una bala? Silver, es mejor enviar la dirección, la velocidad y las coordenadas iniciales en el byte y asignarlos al crear, que el cliente saque sus propios cálculos, sino es un mambrollo de datos volando de un lado a otro y jamás te va a funcionar bien en wan
Si, son para disparos. Que el cliente o el servidor dispare y se vea en la otra pantalla.
Ok haré eso que dices así no hay tanto "embrollo de datos" haha
Cita de: Silver_light en Enero 10, 2013, 12:05:37 AMCita de: Texic en Enero 09, 2013, 09:03:37 PM
Es para una bala? Silver, es mejor enviar la dirección, la velocidad y las coordenadas iniciales en el byte y asignarlos al crear, que el cliente saque sus propios cálculos, sino es un mambrollo de datos volando de un lado a otro y jamás te va a funcionar bien en wan
Si, son para disparos. Que el cliente o el servidor dispare y se vea en la otra pantalla.
Ok haré eso que dices así no hay tanto "embrollo de datos" haha
Yo no lo recomendaría. Las balas podrían des-sincronizarse a la más mínima fluctuación de los fps de alguno de los jugadores...
Lo que podés hacer, que es lo que más se recomienda en estos casos, es enviar la posición, la velocidad y la dirección una vez cada x steps. 5, por ejemplo. Así cualquier des-sincronización solo duraría un poco y no sería muy notoria, y a la vez te ahorrás tener que enviar los datos una vez por frame.
Mejor hacer que el cálculo de movimiento tenga en cuenta los fps y listo
En wan siempre va a haber desincronización, es mejor vivir con ella que tratar de sacársela de encima enviando más y más datos (cosa que la vuelve más grande) xD
PD: El número de mensajes de Silver_light coincide con mi número de puntos :P
Cita de: Texic en Enero 10, 2013, 12:54:30 PM
Mejor hacer que el cálculo de movimiento tenga en cuenta los fps y listo
Vaya. Yo no confiaría en eso. ¿Ya lo probaste anteriormente?
Si, si se programa bien funciona de maravilla. Además no hay que ser tan pesimistas con los fps, lo que más falla en un juego online es el envío de datos, los fps son muy secundarios
Cita de: Texic en Enero 11, 2013, 01:16:52 AMAdemás no hay que ser tan pesimistas con los fps, lo que más falla en un juego online es el envío de datos, los fps son muy secundarios
No es que sea pesimista, es que no se puede asegurar que los fps van a ser constantes durante el juego entero. Incluso, por ejemplo, usando el método que proponés, el usuario servidor podría bajar sus fps deliberadamente para que el usuario cliente no vea los objetos en donde realmente se encuentran.
Por otro lado, no entiendo por qué decís que lo que más falla es el envío de datos. En mi experiencia los datos se suelen enviar sin problema ninguno. Como mucho algún paquete se puede perder, si se envía por UDP. Sería un desastre que no existiera una manera fiable de enviar un paquete por internet.
Nono, digo por el ancho de banda que consume enviar muchas cantidades de datos, imaginate la cantidad de balas que pueden llegar a haber en pantalla, sumado al movimiento sprite, etc de los personajes, sumado a cuanto dato haga falta enviar, recibir, y eso para cada jugador conectado, es mucho. Cuando hacés un juego online tenés que optimizar más que nada el envío (y recepción por ende) de datos. Puede llegar a ocurrir deincronización si los fps fluctúan mucho, si, pero mucho peor sería la desincronización si terminás con datos que tardan 1 segundo o medio segundo en llegar al receptor, una catástrofe total, porque por más que trates de sincronizar luego las balas, los datos van a seguir llegando horrendamente tarde y eso no lo podés solucionar con ningún código. Hay ventajas en reajustar la posición de las balas, pero las desventajas las superan ampliamente, no resulta conveniente para nada. No voy a decirte que tengo razón porque creo que la tengo o porque teóricamente debería ser así, lo digo porque he probado ambos métodos y para wan conviene infinitamente lo que dije, cada byte cuenta
Me parece que estás confundiendo la dessincronización con la latencia. Latencia siempre va a haber, en WAN, LAN y hasta MAN, y no es tan grave. Los jugadores más afectados tardan un poco más en recibir y enviar datos, que puede suponer una desventaja, pero nada más. En cualquier caso, la latencia rara vez se ve afectada por la cantidad de datos que envíes (a no ser que envies una cantidad realmente descomunal); más bien por la conexión de los jugadores y el ping.
En cambio la des-sincronización de datos es un verdadero problema. Un jugador puede ver una cosa y otro puede ver otra completamente distinta, aunque la conexión sea perfecta y con latencia mínima. Y la mejor manera de tratar con la des-sincronización es evitar que pase.
No he confundido nada, a lo mejor has malinterpretado la parte en la que mencioné la desincronización y la latencia al mismo tiempo, pero me refería a que un juego en tiempo real no se puede mantener sincronizado con más de 500ms y es muy común obtener esas cifras con la 39dll. Además tené en cuenta que en una conexión p2p con la 39dll no se suelen obtener altas velocidades, de una conexión con una subida de 40kbps te quedarán 5 o 10 y se dividen entre la cantidad de jugadores, si en cada step tenés que enviar más datos de los que puede la conexión entonces se embotellan y se obtiene un asqueroso efecto, mucho peor que la latencia. Los bytes no sobran, todo suma y al final hay que andar rehaciendo códigos por no optimizar el envío de datos. La optimización de fps o la mecánica de sincronía se puede hacer después, primero lo primero, que es ahorrar cada bit como si de oro se tratase
¡Esto muy bueno! XD XD XD
Sería interesante poner a prueba todas las posibilidades para determinar cual es más eficiente en cada caso.
Me interesa mucho el tema... 8)
Texic, el "asqueroso efecto" que mencionás es producido por la latencia; la des-sincronización es más grave y no se puede arreglar de forma ninguna. Si ocurre, básicamente lo único que podés hacer es reiniciar el juego y probar otra vez.
Me suena a kaillera xD
La desincronización de un juego así no es muy grave, es más que esperable, no es como en kaillera que los emuladores tienen que estar completamente sincronizados para funcionar. Con respecto al efecto que mencioné, no hablo de la latencia, hablo de datos que quedan en cola, y más datos que quedan en cola, y así infinitamente hasta que la cola es tan grande que lo que haces llega 20 segundos después a los demás. Como bien dijo ferhand, habría que hacer pruebas, pero es imposible probar lo que digo en un ejemplo dedicado, tendría que estar incrustado en un juego con mucho envío de datos, porque sino no saturarían el servidor.
PD: Con tu método sucedería otra cosa que no me gusta, recuerda que la latencia sube y baja constantemente, y la actualización de coordenadas a veces llegaría antes y a veces más tarde, produciría un efecto muy extraño en el movimiento de la bala, parecería una bala con epilepsia xD
Cita de: Texic en Enero 11, 2013, 06:42:24 PM
Me suena a kaillera xD
Sí, con Kaillera pasa seguido.
Cita de: Texic en Enero 11, 2013, 06:42:24 PMLa desincronización de un juego así no es muy grave, es más que esperable, no es como en kaillera que los emuladores tienen que estar completamente sincronizados para funcionar.
¿Cómo que no?
Cita de: Texic en Enero 11, 2013, 06:42:24 PMCon respecto al efecto que mencioné, no hablo de la latencia, hablo de datos que quedan en cola, y más datos que quedan en cola, y así infinitamente hasta que la cola es tan grande que lo que haces llega 20 segundos después a los demás.
Me pregunto cómo hiciste para lograr ese efecto...
Cita de: Texic en Enero 11, 2013, 06:42:24 PMPD: Con tu método sucedería otra cosa que no me gusta, recuerda que la latencia sube y baja constantemente, y la actualización de coordenadas a veces llegaría antes y a veces más tarde, produciría un efecto muy extraño en el movimiento de la bala, parecería una bala con epilepsia xD
Puede ser, pero el efecto no debería ser muy perceptible, a no ser que los fps de alguno de los jugadores estén muy bajos.
Bastante interesante el debate.
Me había topado, haciendo el juego, con una desincronización con los items agarrables, como ser por ejemplo las monedas.
Y mi juego solamente tiene 2 jugadores, es decir, el máximo es de 2, el Servidor y el Cliente.
Supongo que el mejor método sería el de Wadk, o no? Digo porque no son una gran cantidad de jugadores...
As you wish lady. Es velocidad contra estabilidad resumiendo, aunque a grandes razgos. Probá ambos sistemas y tomá tu propia decisión, ya tenés todos los datos sobre el funcionamiento de ambos y un largo debate sobre cuál resulta más conveniente. Lo de los items agarrables ha de haber sido un problema menor, no tienen una trayectoria movil como las balas, simplemente hay que crearlos de un lado del juego y pasar los datos al otro, lo mismo para cuando se destruyan. En ese caso se habla de un envío de datos de única ejecución, para las balas sería ejecución constante y si hay muchas balas en pantalla hay que enviar datos por cada una en cada step o intervalo de tiempo
Hoy checando la Http Dll 2 (http://gmc.yoyogames.com/index.php?showtopic=509556&st=0) me encontré que el creador de la dll hablaba de algo parecido a lo que dice texic. cito el mensaje:
CitarThe DLL also fixes an annoying bug/feature in 39dll that can cause data to be lost. With 39dll, the maximum amount of data that can be recieved as a whole is limited by the operating system. Windows will only buffer a fixed amount of data, e.g. 64KB. This might not be enough if you're trying to send large files. If too much data is buffered by the receiver, the sender has to wait to send more data. Since 39dll's sendmessage function doesn't wait, part of the data is lost if too much data is sent at once. This DLL does additional buffering to avoid this problem, so no data is ever lost. You can buffer as much data as you want on both the sending side and the receiving side.
CitarLa DLL también repara un molesto bug/carcteristica de la 39dll que puede causar perdida de datos. Con la 39dll, el máximo numero de datos que puede ser recibido en conjunto está limitado por el sistema operativo. Windows solo procesara una cantidad fija de datos, ej. 64KB. esto puede no ser suficiente si estás intentando enviar archivos grandes. Si muchos datos son almacenados por el receptor, el emisor tiene que esperar para enviar mas datos. Como la función para enviar mensajes de la 39dll no espera, una parte de la información es perdida si se envían muchos datos a la vez. Esta DLL hace un almacenado adicional para evitar esté problema, por lo que nunca se pierden datos. Tu puedes almacenar cuantos datos quieras en ambos lados el lado del emisor y del receptor.
No se bien como traducir lo de buffer, pero bue...
Por cierto yo creo que la mejor forma de hacer balas es hacerlas instantáneas es decir que solo se vean como un destello o una linea y que apenas se crean ya se sepa a que le dieron.
Bueno, el problema que citaba Texic puede ser ese, pero en este caso creo que no aplica porque según entendí, solo ocurre al mandar muchos datos en un paquete único...
Cita de: brunoxzx en Enero 17, 2013, 06:16:24 PM
Por cierto yo creo que la mejor forma de hacer balas es hacerlas instantáneas es decir que solo se vean como un destello o una linea y que apenas se crean ya se sepa a que le dieron.
Jaja bueno, eso no estaría mal, pero ya cambia el gameplay del juego :P.