Sprites como actores

12

No tengo experiencia en preguntas de desarrollo de juegos, pero como programador. En el lenguaje Scala, puedes tener multitareas escalables con actores, muy estables, según tengo entendido. Incluso puede tener cientos de miles de ellos ejecutándose a la vez sin ningún problema.

Así que pensé, tal vez puedas usarlos como una clase base para 2D-Sprites, para salir del juego que requiere pasar por todos los sprites y moverlos. Básicamente se moverían ellos mismos, impulsados ​​por eventos.

¿Tendría sentido para un juego? ¿Tenerlo multitarea así? Después de todo, se ejecutará en la JVM, aunque eso no debería ser un gran problema hoy en día.

EDITAR:

Después de incursionar por un tiempo, noté que solo hay una ventaja real para esta idea: soporte multinúcleo. Un bucle de juego simple solo se ejecutará en un núcleo y funcionará todo secuencialmente.

Dado que las computadoras modernas, incluso en casa, hoy en día tienen dos o más núcleos incorporados, creo que es una buena idea permitir que los programadores de juegos usen eficientemente los otros núcleos. Después de todo, creo que generalmente el jugador solo tendrá el juego ejecutándose en su máquina de ocho núcleos, entonces, ¿por qué no?

La otra ventaja que veo es que en Scala, puede tener RemoteActors, que puede tratarse de la misma manera pero ejecutarse en otra computadora. Entonces, quizás esto también pueda simplificar los juegos en red.

Tengo la intención de construir eso en mi motor Scala 2D tan pronto como pueda.

Lanbo
fuente
Me interesaría mucho saber cómo resulta esto. He visto a Scala un par de veces, pero nunca me he sumergido en él antes.
Davy8
Muchos argumentarían que para un soporte explícito de múltiples núcleos, es mejor usar hilos en lugar de procesos (y procesos de modelo de actores Scala). Esto se debe a que puede aprovechar la memoria compartida en los subprocesos. Por supuesto, eso es propenso a errores en formas que el modelo de actor no lo es.
Kylotan
Los actores de Scala se multiplexan en la parte superior de un grupo de subprocesos, por lo que podrían ser más livianos que los subprocesos. Esto significa que pueden manipular la memoria compartida para comunicarse, siempre que esté sincronizada correctamente. Si usa actores remotos, entonces podrían estar en diferentes procesos, y la única forma de comunicarse es enviando mensajes.
axel22

Respuestas:

7

No lo intenté, pero soy un programador de Scala, y diría que este no es el mejor enfoque. Los sprites necesitan ser animados sincrónicamente. Los actores no tienen garantías de que se ejecutarán de manera justa: algunos sprites pueden ser más rápidos que otros, lo cual no es lo que quieres. Es posible que desee utilizar una barrera para sincronizarlos, pero entonces, ¿por qué usar actores? Si solo confía en la transmisión de mensajes, implementar este tipo de sincronización (implementar una barrera para más de 1000 actores) es una exageración.

Otro problema es: ¿para qué usarías el paso de mensajes? ¿Necesitas tus sprites para comunicarte? Podría enviar un mensaje del actor principal, diciéndole a cada sprite que se mueva al siguiente cuadro, pero en términos de rendimiento, eso es magnitudes y magnitudes más que invocar métodos directamente e iterar a través de un conjunto de sprites.

Me parece que lo que necesita aquí es una especie de multitarea muy liviana, y ningún mensaje pasa en absoluto. Implementar su propia implementación similar a la de un actor que garantiza la equidad es probablemente la mejor manera de hacerlo si desea garantizar esto, pero eso es demasiado trabajo para muy poca ganancia. Otra cosa a tener en cuenta es la programación reactiva funcional y scala.react, creo que es una mejor combinación para este caso de uso.

He implementado un motor de juego isométrico 2D en Scala. Solo he usado 1 actor global para actualizar sprites visibles que fueron animados.

Es posible que desee implementar su lógica de juego utilizando actores, por ejemplo, para distribuir cálculos en diferentes partes de su mapa de juego a diferentes actores, de modo que actualicen el estado del juego en paralelo, y ganen una ganancia de rendimiento. No usaría un solo actor por objeto de juego, sino un actor por región. Si va demasiado fino, el rendimiento se ve afectado.

Aún así, si fuera tú, lo intentaría, solo para ver qué pasa.

axel22
fuente
1

Así que pensé, tal vez puedas usarlos como una clase base para 2D-Sprites, para salir del juego que requiere pasar por todos los sprites y moverlos. Básicamente se moverían ellos mismos, impulsados ​​por eventos.

¿Cuál sería el evento que los conmueva?

¿Sería un evento que emites una vez por cuadro?

Y si es así, ¿cómo ha cambiado esto el sistema de manera práctica?

Cuando estudié originalmente la orientación a objetos en el contexto de C ++, aprendí que a algunas personas les gustaba pensar en una declaración xyz.doThis(x)como `` enviar el mensaje doThis a xyz (con una carga útil de x) y esperar una respuesta inmediata ''. Cuando se ve en este nivel, no hay diferencia intrínseca entre un sistema basado en eventos o mensajes y uno normal de procedimiento.

Kylotan
fuente
Los actores son una solución multiproceso. Las comunicaciones no son sincrónicas. Los actores Scala (concepto de Erlang) permiten una programación fácil de múltiples núcleos.
Ellis
Tienes un punto allí, pero la diferencia aquí sería que el sprite basado en Actor no bloquea el ciclo del juego mientras realiza la acción, mientras que el enfoque del método espera hasta que xyz.doThis(x)se hace. Creo que esto incluso podría ayudar a acelerar la lógica del juego, especialmente en sistemas de múltiples núcleos.
Lanbo
Hace que sea más fácil distribuir el manejo de la entidad a través de múltiples núcleos, cierto. Pero el costo de eso es que no puede referirse fácilmente de un actor a otro sin mensajes adicionales o datos adicionales enviados en los mensajes. Entonces se da cuenta rápidamente de que el enfoque ingenuo aquí no lo ayuda: ¿puede formular una forma basada en actores de realizar las actualizaciones?
Kylotan
Actualmente, estoy experimentando con algún tipo de actualización distribuida: mis actores son como nodos en una estructura de árbol, y la actualización de la raíz actualiza a los hijos, por distribución de mensajes. Además, la verdadera ventaja será la creación de redes: en Scala, un Actor y un RemoteActor (Actor en otro sistema) se pueden abordar de la misma manera, con los mismos mensajes.
Lanbo
Sí, pero el problema no es la activación de la actualización como tal, es garantizar que el destinatario del mensaje tenga toda la información que necesita para actuar sobre él.
Kylotan
0

Ese es un enfoque genial para pensar en actualizar los objetos de tu juego. No conozco a Scala, pero le digo que intente y vea cómo resulta, ¡y aún mejor publique sus resultados!

Las principales preguntas que me vienen a la mente son: ¿Cómo manejas con qué frecuencia se actualizan algunos objetos del juego en comparación con otros? ¿Tendrás que preocuparte de que los actores de sprites tomen demasiados ciclos de modo que el sistema de renderizado no tenga tiempo para dibujar un cuadro cada 1/60 | 30 | | 24 de segundo?

Otra cosa a considerar es cómo esto afectará la resolución de las interacciones jugador contra IA que dependen del orden de una secuencia de eventos muy rápidos. Dependiendo del tipo de juego, esto puede no probablemente no va a importar mucho.

michael.bartnett
fuente
Lo mejor de Scala Actors es que están orientados a mensajes. Cada uno de ellos tiene su propio mensaje / cola de eventos. No estoy seguro de si 'Draw' debería ser un mensaje o un método para llamar. Creo que será lo último, por lo que un Sprite se puede dibujar en cualquier momento, sin importar el estado de su cola de eventos. Y pueden enviarse mensajes entre sí para garantizar que las cosas se hagan en un orden determinado.
Lanbo
Tenga cuidado allí, no creo que sea útil tener cada sprite con un método o evento Draw, excepto tal vez como una bandera para alternar la visibilidad. En la fase de renderizado de un bucle de juego, el orden en que los sprites se muestran en la pantalla tiene un gran efecto en el resultado. Si tiene un sprite ubicado frente al otro (la dimensión está hacia el monitor), desea que ese sea dibujado en segundo lugar. Veo que los actores de Scala son útiles para la parte de actualización / lógica del bucle del juego.
michael.bartnett
Por lo general, solo tiene un método de dibujo allí, por lo que al implementarlo de esa manera no debería haber mucha diferencia en la forma normal de tratar con los sprites.
Lanbo
Ah, está bien, no entendí lo que estabas describiendo. De alguna manera, estaba imaginando sprites que se representaban cada vez y como quisieran. ¡Háganos saber cómo resulta esto!
michael.bartnett
0

Bueno, tampoco soy un gran programador, pero no veo ningún problema en tu propuesta. Ni siquiera pensé en tal forma de desarrollar actores.

Puede ser todo un desafío, ya que la IA tiene que ser muy precisa para evitar comportamientos inesperados, pero además de eso, veo que es una muy buena propuesta

Carlos Valenzuela
fuente
0

Si por sprite te refieres a la entidad del juego, entonces seguro.

Las entidades del juego nunca deberían dibujarse a sí mismas. Deben actualizar un controlador gráfico que describa dónde y cómo deben dibujarse. El sistema de renderizado o el gráfico de escena o lo que sea que haga el dibujo real. Hay una tarjeta gráfica, además, la tarjeta gráfica debe sincronizarse cada 16 ms. Una configuración como esa simplemente no funciona bien para el procesamiento asincrónico distribuido.

El sistema de renderizado debe ser un actor (o posiblemente un par si eres complicado). Cuando las entidades del juego actualizan el controlador de gráficos, envía mensajes al sistema de representación. El sistema de renderizado puede tomar todo tipo de decisiones y / u optimizaciones, por ejemplo, renderizado por lotes, oclusión, suavizado de jitter de física, etc.

No soy un desarrollador de Scala, pero he hecho bastante con Erlang. Entonces, si parte de mi terminología Scala es incorrecta, por favor perdóname.

código_deft
fuente