Hola chicos,
necesito de vuestro consejo o ayuda. Estoy desarrollando un videojuego de navecillas, y desearía que el movimiento de las naves fuera totalmente independiente a los FPS del juego. Para un "movimiento rectilineo uniforme" no hay dudas, pero si la nave acelera, y rota estoy viendo que he de implementar cosas que en estos momentos desconozco.
Por otro lado también está el problema de las colisiones, ya que si en un ordenador va a 1FPS o menos (exagerando un poco), cabe la posibilidad, si el calculo de movimiento se realiza por tiempo, al usar collision algunas veces los disparos atravesarían la nave. Así que también necesito algo para calcular trayectorias de intercepción.
Así que si alguno de vosotros ha hecho algo parecido o bien, existe algún ejemplo por ahí, o funciones en alguna librería, os estaría muy agradecido.
el movimiento rectilineo uniforme, es en linea recta...
Quote from: SplinterGU on March 08, 2011, 08:59:04 PM
el movimiento rectilineo uniforme, es en linea recta...
Si, para ese no hay problema. El problema está en el movimiento no uniforme, ni rectilineo :)
si, yo tampoco entendi muy bien el problema
En mi manualillo hay varios ejemplos de movimiento curvilíneo, acelerado, etc
Quote from: DCelso on March 08, 2011, 10:16:31 PM
si, yo tampoco entendi muy bien el problema
Oks, voy a intentar describirlo con un ejemplo:
*Tenemos el PC A, con 4fps y el PC B con 1fps. Queremos conseguir que las naves se muevan a misma velocidad en el tiempo, independientemente de los FPS. Si implementamos un algoritmo como el siguiente:
<pseudocodigo>
LOOP
* contador = calcular tiempo entre frame actual y anterior.
* avanza 5 pixels * contador.
* gira 5 grados * contador.
END
Resultado (aproximado):
PC A
FPS = 1, Tiempo ultimo frame=0, angulo=0, avance=0.
FPS = 2, Tiempo ultimo frame=250, avance=1250, angulo= 1250
FPS = 3, Tiempo ultimo frame=250, avance=1250, angulo= 2500
FPS = 4, Tiempo ultimo frame=250, avance=1250, angulo= 3750
FPS = 5, Tiempo ultimo frame=250, avance=1250, angulo= 5000
PC B
FPS = 1, Tiempo ultimo frame=0, angulo= 0, avance= 0
FPS = 2, Tiempo ultimo frame=1000, avance=5000, angulo= 5000
Si visualizáis este ejemplo, comprobaréis que el PC A ha desplazado el proceso formando una "curva" compuesta de 4 rectas ya que ha avanzado 1250 pasitos cada vez, y añadiendo al giro 1250. El PC B en cambio, ha avanzado 5000 y posteriormente ha girado 5000, de manera que la totaldidad del movimiento ha sido recto, no girando.
El mismo problema me surge en la aceleración, ya que no quiero que mi nave salga de 0 a velMAX en 1ms.
¿¿Se entiende mejor ahora??
¿¿Es posible que alguien se haya encontrado antes con esto y haya creado las funciones pertinentes??
Gracias por adelantado.
Quote from: osk on March 08, 2011, 10:22:50 PM
En mi manualillo hay varios ejemplos de movimiento curvilíneo, acelerado, etc
Excelente!! lo reviso mañana y te cuento!
Yo sigo diciendo, como opinión personal, que un juego en un divlike que no dependa de los FPS es un error, porque todo está lligado a los FPS.
Se puede plantear un escenario como este, en el que los procesos no son dependientes de los FPS, pero tarde o temprano te enfrentarás a algo que sí esté sincronizado, ya que el sistema en sí mismo lo está.
Si en un PC te va a 4FPS y en otro a 1FPS, optimiza o usa frameskip.
Como digo, es una opinión personal. Si aun así quieres seguir, sólo tienes que consultar los apuntes de física del colegio o buscar "movimiento rectilíneo uniformemente acelerado" o "movimiento curvilíneo" por internet.
yo creo que no se trata de tiempos o frame, si sabemos cuantos frames necesitamos por segundo y nuestro juego esta pensado haciendo uso de eso, quizas necesitamos usar frameskip para que los personajes se muevan en el tiempo que necesitamos pero a costa de perder frames de dibujo.
Osk, no encontré los ejemplos que comentas :(
Os explico el motivo para que podáis ayudarme a encontrar una solución. Estoy intentando hacer un videojuego en red, en el pasado ya hice mis "pinitos" con CDIV y logré comunicar un sencillo juego. En aquel momento, decidí sincronizar en cada frame la posicion de todos los jugadores, el resultado fue que en LAN funcionaba más o menos bien, pero a través de Internet la cosa iba muy lenta. Ahora trato de resolver el problema simplemente sincronizando eventos: el jugador a pulsado avanzar, el jugador a pulsado girar,... de manera que no tenga que preocuparme de sincronizar cada frame, liberando la red de tráfico inutil.
El problema es que para que este protocolo funcione, antes debo conseguir sincronizar el juego independientemente al rendimiento de la máquina donde se ejecute. Y de aquí las preguntas anteriores.
¿Alguna sugerencia?
A ver, os cuento:
Si haces:
x = x + 5;
Eso está MAL
Sobre todo en un juego online, si depende del FPS, unos jugadores corren más que otros.
Para solucionarlo existe un factor llamado deltaTime, que equivale al tiempo en segundos que tardó el último frame en dibujarse.
No sé si ese valor puede obtenerse en Bennu correctamente... Ya que es un float... Una vez lo tengas deberías hacer:
x = x + ( 5 * deltaTime);
Y eso teniendo en cuenta que la x es int, deberías usar una imagen intermedia.
¿Cómo aprendí esto? Pues os dejo la fuente:
http://unity3d.com/support/documentation/ScriptReference/Time-deltaTime.html
Quote from: Windgate on March 10, 2011, 09:18:46 PM
A ver, os cuento:
Si haces:
x = x + 5;
Eso está MAL
Sobre todo en un juego online, si depende del FPS, unos jugadores corren más que otros.
Para solucionarlo existe un factor llamado deltaTime, que equivale al tiempo en segundos que tardó el último frame en dibujarse.
No sé si ese valor puede obtenerse en Bennu correctamente... Ya que es un float... Una vez lo tengas deberías hacer:
x = x + ( 5 * deltaTime);
Y eso teniendo en cuenta que la x es int, deberías usar una imagen intermedia.
¿Cómo aprendí esto? Pues os dejo la fuente:
http://unity3d.com/support/documentation/ScriptReference/Time-deltaTime.html
Parece excelente!
Karma+
Por cierto, cuando dices:
"Y eso teniendo en cuenta que la x es int, deberías usar una imagen intermedia."
Has querido decir "variable intermedia", ¿verdad?
¿Sería apropiado leer al inicio del frame el tiempo desde ejecución con get_time() y restarlo al valor del frame anterior para obtener el deltaTime?
Usando este modo, ¿como se evalua el tema de colisiones para ordenadores muy lentos?
la unica forma de sincronizar bien el tiempo, en maquinas chicas, tenes que usar el parametro frameskip del set_fps.
SplinterGU, me parece más elegante la solución de Windgate ya que como dices, el frameskip penalizaría las máquinas omitiendo frames que podrían perfectamente pintarse y añadir suavidad al movimiento del juego.
Además, la sincronización del modo que comentas SplitnerGU, dependería tal y como la he entendido del resto de máquinas que esten en partida. Me imagino también que haría falta sincronizar este parametro muy amenudo entre los jugadores, ya que podría darse el caso de que se ejecute en cierto momento el antivirus y caigan los FPS de golpe, generando un desfase muy grande en la partida. Si puedo omitir ese tráfico en la red, creo que es interesante estudiar el rollo del tiempo.
Ahora bien, quizas sea imposible obtener el lapso entre el útlimo frame y el actual, pero por la definición de get_time(), parece apropiado para ello, ¿no?
no, no, no, grave error... frameskip no penaliza, todo lo contrario, frameskip son frames maximos (de dibujado) que se pueden llegar a saltar si no alcanza la velocidad de proceso necesaria para cumplir con los fps deseados, o sea, la logica del juego funcionara al tiempo y fps deseados, solo que no todos los frames se dibujaran, se podran saltear hasta el maximo de fps definidos por frameskip, pero solo si la velocidad no alcanza...
todo lo que mencionas del antivirus y caidas de fps, se soluciona con el frameskip (que no indica saltar constantemente X frames, sino saltar tantos frames sean necesarios hasta un maximo de X frames si no se llega al fps deseado)
los frames se sincronizan por tiempo...
yo no creo que windgate haya dicho eso de que el frameskip penalizaria en maquinas chicas, si lo dijo, esta mal... yo entiendo que windgate quiso decir otra cosa.
Hombre, ¿ves? eso del x=x+5 es una de las cosas de las que hablaba: esa asignación es dependiente de los FPS, ya que a más FPS, más distancia recorre en el mismo tiempo real. En todo caso tendrías que multiplicar los pixels que se recorren en una unidad de tiempo, por el número de unidades de tiempo transcurridas (decimales incluidos).
Lo elegante es tener un frameskip adecuado, como te dice Splinter ¿nunca has jugado en red y, en un momento dado, tu PC ha hecho un extraño y los personajes se han quedado congelados un momento y después se han teletransportado a donde deberían estar? eso ha sido un frameskip: ha dejado de dibujar algunas imágenes (solo que en lugar de ser el propio ordenador el que va calculando el movimiento, recibe del servidor la posición, gráfico, etc de todos los elementos del juego).
Y en Bennu porque tienes los FPS como referencia, no quiero ni pensar en sincronizar juegos en C donde tú mismo debes definir el tiempo de retardo entre imagen e imagen según la cantidad de cálculos realizados :S
Quote from: SplinterGU on March 11, 2011, 12:01:20 AM
yo no creo que windgate haya dicho eso de que el frameskip penalizaria en maquinas chicas, si lo dijo, esta mal... yo entiendo que windgate quiso decir otra cosa.
Humm, no Windgate no ha dicho eso. He sido yo que he malinterpretado el funcionamiento de frameskip y de hecho trás la explicación, sigo teniendo dudas:
SplinterGU corigeme si me equivoco (o cualquiera), si deseo hacer una sincronización que vaya desde máquinas a 60fps a máquinas a 10fps, ¿debo poner set_fps(60,6); asegurando que dentro de ese rango de FPS SI estará sincronizado? En caso de haberlo entendido correctamente, ¿Contabilizará collisions y otras historias en esos frames no dibujados?
Gracias de nuevo por todos los comentarios.
si, no se si 6 fps sera lo que te dara 60fps de logica en maquinas donde tiene 10fps de render, eso depende, pero posiblemente si, y si funcionaran todas las colisiones y todo.
yo estoy deacuerdo con usar fps.
Debes de poner en todas las máquinas el mismo valor de fps y sincronizar tus movimientos con éste.
Pon el valor de fps más bajo que te den todas las máquinas que van a implicarse en tu juego y punto, ya todas irán a ese mismo fps y todo se moverá a la vez. frame, hace pausas haciendo así que todos los procesos acaben su frame antes de seguir.
El problema se encontraría sí y solo sí una máquina fuese tan mala que no fuera capáz de correr a ese fps asignado, con lo que usando frameskip harías que se saltase algunos frames para poder ir al fps asignado.
Hablando en números: si pones fps a 25 y usas la palabra frame en todos tus procesos, cada frame durará 1/25 segundos, así que si las instrucciones que hay antes de la palabra frame son más rápidas que eso, pues frame hará que se espere hasta pasar justo 1/25 segundos antes de continuar.
El problema radicaría sí y solo sí, como dije antes, las instrucciones antes de la palabra frame fuesen muchísimas y muy lentas y durasen más de 1/25 segundos, por eso si sacas el rendimientó máximo de frames por segundo que te da el juego en todas las máquinas puedes usar este para usarlo en la función set_fps y hacer que todos esperen a estas intrucciones tan lentas que pusiste en determinado proceso.
Al final, dado que es tan sencillo de implementar estoy probando el frameskip y tiene buena pinta. El contador FPS a veces muestra 59 otras hasta 62, pero es bastante estable, así que creo que usando esto y sincronizando todo de tanto en tanto funcionará bastante bien.
Karma SplinterGU ;D
El frameskip lo que hace es saltarse las rutinas de dibujado, sólo eso, por lo que los demás cálculos se harán. Pero ojo, si esos cálculos superan el tiempo como te ha indicado XCelso, ni el frameskip te librará, se retrasarán e intentará sincronizarse cuando haya momentos de menos cálculos.
Por eso se recomienda optimizar el juego para que funcione en la máquina más pequeña. Es más, se recomienda que el servidor sea una máquina potente para que realice todos los cálculos, de forma que los clientes sólo se limiten a mostrar los gráficos tal como se lo indique el servidor, y que dicho servidor sea rápido en las comunicaciones, para manejar todo el volumen de datos entrantes y salientes.
Por ejemplo: un cliente hace un salto, pues se lo dice al servidor, que realiza los cálculos del movimiento parabólico con complejas ecuaciones físicas, y luego le dice al cliente "píntate en las coordenadas (x,y)".
De todas formas, ten en cuenta que hay cosas peores que un ordenador lento en la red, y es que hay que contar con el retardo de la propia línea, el tiempo que pasa entre el envío y la recepción de datos, y la posibilidad de que algunos paquetes se pierdan por el camino. Por eso se dice que es difícil hacer un juego en red, pero vamos, no te asustes, que hay librerías que ya tratan con algunas cosas de estas, y a menos que estés haciendo un juego en el que el tiempo sea crítico (léase carreras con tiempos muy ajustados), tampoco pasa nada por tener un poco de lag ;)
umn, hombre un lag en un juego es la diferencia entre estar vivo o muerto :D.
Lo que se debería de hacer es que el servidor mida los lags de todos los usuarios involucrados en el juego y sabiendo el del más lento, ajuste el envío a los otros demendiendo de éste para que todos reciban la orden al mismo tiempo (o casi al mismo tiempo :D).
Quote from: DCelso on March 11, 2011, 06:16:45 PM
umn, hombre un lag en un juego es la diferencia entre estar vivo o muerto :D.
Lo que se debería de hacer es que el servidor mida los lags de todos los usuarios involucrados en el juego y sabiendo el del más lento, ajuste el envío a los otros demendiendo de éste para que todos reciban la orden al mismo tiempo (o casi al mismo tiempo :D).
Aun no he empezado con la tortura de red a nivel del juego, antes quería que los PC's estubieran sincronizados, ya que los calculos NO quiero que los haga el servidor. Quiero que el servidor sea únicamente el puente para comunicar clientes, pero deberán ser los clientes los que tengan en cuenta sus latencias y tal. De hecho, estoy valorando que los clientes no ejecuten una orden, hasta un segundo después de recibirla, de modo que el resto ya esté al tanto de dicho cambio antes de que suceda.
De todas maneras, esta es otra guerra y es probable que merezca un nuevo post si necesito ayuda. Por lo pronto, el frameskip parece la más sencilla solución al problema de sincronismo. Relamente me sorprende muchisimo lo que hace dicha función, y aparentemente funciona.
Saludos!
no se como lo tenes pensado, pero la logica deberia estar en el servidor, sino que cada cliente se sincronice y mantenga logica de cada otro cliente y otras tantas cosas mas, no solo te vas a volver loco, sino que va a ser una tarea titanica ver algo sincronizado.
sin contar lo facil que va a ser trucar el juego...
Ya estaba Splinter tardando demasiado ;D
Hombre, trucar el juego siempre es "fácil", pero como alguien dijo hace poco, si el sistema es de código abierto, pues mucho más :D :D :D
En este caso, la solución es sencilla: jugar con amigos y gente de confianza :D
drumpi, no... en un juego con logica bien desarrollada en el servidor no es simple trucarlo... y ahi no importa que se tenga o no el codigo fuente... la cuestion radica en que la logica esta protegida fisicamente fuera de nuestra alcance... y es el servidor quien decide que asignar o no (dinero, objetos, niveles de experiencia, energia, muerte, etc...)
Hombre, claro, si el servidor se encarga de todo y los cliente sólo se dedican a enviar los botones pulsados, las coordenadas de destino o cosas así, es casi imposible de trucar, pero entonces se necesita una máquina que sea (n_clientes+1)*bucle_juego veces más potente que las demás, y en ocasiones eso no es posible.
Imagina el Echo en red: o cada WIZ hace sus propios cálculos, o la WIZ servidor explota :D
no es tan asi como enviar botones, coordenadas destino y cosas asi...
el servidor se encarga de la logica del juego, que asignar, que dar, que eventos disparar, etc.
el cliente se encarga de hacer todas las animaciones secundarias (escenarios, efectos climaticos, etc), recoger pulsaciones y procesar las coordenadas (que despues seran validadas o no por el servidor), realizar por si mismo todo lo que no sea critico para la logica y seguridad del juego.
Me había perdido la conversación, en lo último que escribí, sí, quise decir "variable" intermedia xD
Splinter, lo del frameskip no me gusta usarlo, prefiero la solución del deltaTime porque te asegura exactitud ante cualquier situación. Pero a ver si es que yo estoy equivocado, ¿Tú quieres decir que si deseas un framerate de 60 tendrías que hacer set_mode ( 60 , 60 ) para que sincronice perfectamente en el peor de los casos?
lo de los deltaTime no es un buen metodo, no solo en situacion normal, sino en situacion donde estamos faltos de fps, porque no solo puede ser un problema de dibujado, sino tambien de procesamiento, y en ese caso podemos incluso calcular menos, y un juego no es solo el dibujado, la fluidez logica es lo mas importante cuando necesitamos sincronia.
es un poco complicado de explicar... pero los delta servirian en un esquema donde trabajamos con set_fps(0,0), y donde no nos importa nada salvo el tiempo para dibujar y procesamos a la mayor velocidad posible, pero eso puede ser muy complicado de implementar para muchos usuarios.
perdon, si no logro explicarlo correctamente.
Recuperando este hilo, quería comentar una cosa:
Dado que el frameskip funciona bastante bien, ¿no se podría hacer totalmente perfecto?
Me explico:
Si fijas un juego a 60fps, siempre que la máquina pueda, representará 60, no 61 ni 59. Con el frameskip he visto un rango de valores de 59 a 62, lo cual provoca que se necesite sincronizar varios ordenadores cada cierto tiempo, ya no por seguridad ni por integridad sino por ese pequeño desfase que ocurre con el frameskip en ambos ordenadores.
Gracias!
Arcontus, juro que no entiendo que es lo que planteas? cual es tu necesidad en base a tu ultimo post?
A ver si me explico mejor,
si uso frameskip en mi juego, lo que he conseguido es efectivamente que las máquinas donde lo ejecute llego aproximadamente a los 60fps que es lo que deseo, pero es un número aproximado, es decir no siempre es 60, a veces 59 otras 61 otras (mas raro) 62, ¿me explico?
Que sería lo suyo, pues que fueran siempre 60fps, que no calcule 61 o 59, sino 60.
¿Me explico?
claro, es que veo no se entiende que es el frameskip y el set_fps...
el sistema cuando le decis 60 fps con un skip de 2, significa que hara lo que pueda para llegar a 60fps... pudiendo saltar hasta 2 frames... si salta 1 frame y no llega, entonces salta otro... pero puede que si saltando 1 no le daba los 60fps, saltando 2, le sobro tiempo y entonces corrio a una velocidad de 61 fps... ahora el caso contrario... ahora que en el paso anterior, llego a 61fps, intentara estabilizar a 60, y por ende metera un poco mas de pausa, pero como la granularidad de los temporizadores del sistema operativo para las pausas no tiene la precision que necesitamos entonces se nos pasa la pausa un poquito y hacemos 1 o 2 frames menos... normalmente la granularidad de los timeres en los sistemas operativos es de 10 o 20ms... depende...
1 o 2 frames arriba o abajo no deberia hacer diferencia... mas que nada porque tambien pueden ser errores de precision de calculo, al hablar de milisegundos...
quizas es dificil entenderlo... pero lamento decirte que lo que propones no se puede hacer... si quieres lo puedo fakear y poner que diga 60fps, pero no es la idea hacer fake con los numeros.
Hola SplinterGU,
me imaginaba que por ahí andaban los tiros, pero creia oportuno hacer la pregunta.
Muchas gracias de todos modos, se entiende que no se pueda añadir más precisión a la función y por supuesto falsear los números aun llevaría a más confusión que otra cosa.
Un saludo.
no esta bien que preguntes, siempre y cuando se entienda el concepto, esta bueno preguntar...
lo de falsear los fps era obviamente un comentario con una respuesta logica... no es valido falsear los fps...
si no se entendio, pregunta sin miedo...
Quote from: osk on March 08, 2011, 10:22:50 PM
En mi manualillo hay varios ejemplos de movimiento curvilíneo, acelerado, etc
:o yo tengo el manual, no lo he terminado de leer!!... pero lo hare prontoooo!! no sabia de esos ejemplos!! ;D