¿Java AWT es adecuado para renderizar juegos en 2D?

8

[Reubicando esta pregunta desde stackoverflow, ya que se señaló que encaja mejor aquí.]

Actualmente estoy transfiriendo mi motor de juego 2D a Java. Miré algunas de las bibliotecas de juegos apuntadas aquí en stackoverflow. Sin embargo, los que miré eran bastante simplistas y ni siquiera indicaban si admitían cosas como la transparencia alfa, por lo que decidí portar mi renderizador C ++ para el que ya había escrito la lógica.

Este procesador es un procesador de software puro que utiliza mosaico para evitar una nueva representación innecesaria. Optimicé su rendimiento de desplazamiento creando un "búfer fuera de pantalla" un poco más grande que mi panel de salida, y colocando este búfer fuera de pantalla en mi salida en cada fotograma. De esta manera, podría evitar volver a dibujar mosaicos innecesariamente solo porque desplacé un píxel en el mapa.

Utilicé AWT de Java para implementarlo, usando una imagen Buffered grande para el búfer fuera de pantalla. El uso de la CPU está bien (alrededor del doble de lo que tenía en C ++), pero hay un extraño problema con el desplazamiento continuo, donde cada segundo más o menos, el renderizador se retrasará durante aproximadamente 0.2 segundos.

Como no hay nada en mi propio código que ocurra en estos períodos, y dado que los picos desaparecen si no dibujo mi búfer fuera de la pantalla en la vista principal, solo puedo concluir que Java está haciendo una optimización interna propia. Sin embargo, no estoy seguro de lo que hace, ni sé cuál de mis optimizaciones tendría que eliminar para deshacerme de los picos. Además, puede ser que Java AWT no se haya hecho teniendo en cuenta el desplazamiento continuo y alto FPS, y eso es completamente inutilizable para este propósito.

¿Hay alguna forma de deshacerme de estos picos?

cib
fuente
44
¿Podría ser el recolector de basura golpeándote?
bummzack
@bummzack: Posiblemente. En el generador de perfiles se ve así: i.imgur.com/EMxkA.png Sin embargo, no estoy seguro de cómo reduciría este efecto, especialmente si es causado por mis llamadas a graphics.drawImage
cib

Respuestas:

4

Si bien no puedo estar seguro sin mirar su código, parece que su problema es el recolector de basura. En Java, tiene recolecciones de basura mayores y menores que tienen lugar de vez en cuando. El menor usa parte de su CPU pero no lo molestará demasiado. Las principales colecciones pueden ser un problema real para aplicaciones en tiempo real, como los juegos, ya que en realidad detendrán todo mientras se ejecutan.

Hay dos opciones para resolver esto. Primero puede ajustar la JVM para asegurarse de que se realicen las colecciones menos importantes. En segundo lugar (y recomendado), puede asegurarse de no dejar demasiada basura. Simplemente comprueba en qué parte de tu aplicación creas muchos objetos (en mis juegos, por lo general, son las clases de vector3) y asegúrate de reutilizarlos tanto como sea posible (especialmente en los bucles internos, etc.).

Pjotterke
fuente
2

Si.

Para juegos basados ​​en sprites 2D, AWT se puede usar para manejar el renderizado con gran efecto. Incluso puede ser acelerado por hardware , dependiendo del hardware disponible.

Sin ningún código o fragmentos de perfiles detallados, es difícil decir cuál es el problema. Lo mejor que puedo hacer es ofrecer algunos consejos básicos para trabajar con Java y AWT al crear juegos.

Trabajando con el recolector de basura

El GC en Java es algo que realmente debemos tener en cuenta al construir nuestros juegos. Se ejecutará periódicamente y buscará objetos que no tengan referencias a ellos, y los eliminará de la memoria. Este proceso de eliminación es lento y probablemente sea la causa del enganche que está experimentando.

Mi sugerencia es evitar crear referencias de objetos que no se mantendrán durante toda la ejecución (o al menos, tanto como sea posible). El objetivo ideal es asegurarse de que el GC no tenga nada que hacer cuando se ejecute.

En la práctica, puedes terminar con muchas variables estáticas que reutilizas a lo largo del juego. Aquí hay un ejemplo muy ingenioso de cómo tiendo a lidiar con eso:

public final class Resources {
    public static Map<int, String> strings;
    public static Map<int, Texture> textures;
    public static Map<int, GameObject> objects;
    public static Map<int, SoundEffect> sounds;
}

Durante la carga de pantallas es donde puede aumentar o reducir sus Mapinstancias usando la newpalabra clave. Pero durante el juego, querrás evitar eso tanto como puedas. Si algo se destruye durante el juego, coloca una bandera en el objeto para que sepas que no es algo que esté actualmente activo. Si necesita generar un nuevo objeto, revise Maphasta encontrar uno que no esté activo, configure sus propiedades y márquelo como activo.

Esto es algo que debe tener en cuenta al usar Java para aplicaciones sensibles al rendimiento, independientemente de si está usando AWT, JavaFX u OpenGL para hacer el renderizado.

Lona

Para AWT en particular, recomendaría usar la clase Canvas para renderizar todo por varias razones:

  • Tienes un mejor control de cuándo se rinden las cosas. Esto significa que puede escribir su propio ciclo de juego y hacer cosas como interpolación, extrapolación, limitación de velocidad, etc.
  • Parece funcionar mejor. Pude obtener más cosas en la pantalla a la vez a una velocidad de cuadro aceptable en lugar de intentar animar un montón de objetos de Etiqueta e Imagen.
  • Es más fácil incrustar en editores. Ser capaz de configurar un Frame con controles GUI normales y apuntar la lógica de renderizado de su juego a un Canvas significaba que podría reutilizar el código de renderizado del juego en las herramientas del editor.
  • Le da acceso fácil a la API Java2D (también conocida como la clase Graphics2D ).
Cifrar
fuente