proyecto - pacman java descargar
Pacman en Java preguntas (10)
Esto puede sonar obvio, pero su problema de rendimiento se debe a que está redibujando todo el laberinto, lo cual no es necesario, sino que solo necesita volver a dibujar las partes cambiadas de su laberinto.
La forma en que he abordado este tema antes es separando la actualización del laberinto del rediseño real en diferentes hilos (algo así como un MVC enhebrado). Cada vez que cambie una celda en su laberinto lo marcará como "sucio", su hilo de redibujado comprobará de vez en cuando para volver a dibujar las celdas sucias.
Perdón por el consejo extremadamente genérico
Para mi tarea en la universidad, tengo que hacer una versión en red de pacman. Pensé que sería mejor abordar este problema haciendo una copia local de pacman primero y luego extender esta funcionalidad para jugar en la red.
Tendría que decir que soy relativamente nuevo en el desarrollo de la GUI de Java y que utilizo esas funciones dentro de Java.
Empecé a seguir los enlaces anteriores con respecto al desarrollo de juegos dentro de Java y un ejemplo del juego pacman.
Decidí representar el laberinto como una matriz int con diferentes valores que significan cosas diferentes. Sin embargo, cuando se ejecuta el método de pintura dentro del bucle principal del juego, estoy redibujando todo el laberinto con este método.
for (int i : theGame.getMaze())
{
if (i == 4)
{
g.setColor(mazeWallColour);
g.fillRect(curX, curY, cellSize, cellSize);
curX += 25;
}
else
{
curX += cellSize;
}
index++;
// Move to new row
if (index == 25)
{
index = 0;
curX = 10;
curY += cellSize;
}
}
Sin embargo, esto me proporciona menos de 1 fps. Aunque me he dado cuenta que el ejemplo vinculado anteriormente utiliza una forma similar de redibujar cada vez que se llama al método de pintura y creo que lo hace en una imagen que no se puede ver (como el doble búfer [He usado una BufferStrategy como el primer enlace explica]) ¿Cuál sería una mejor manera de redibujar el laberinto?
Cualquier sugerencia / consejo con esto sería útil.
Gracias por tu tiempo.
http://pastebin.com/m25052d5a - para la clase de juego principal.
Editar: Acabo de notar que sucedió algo muy extraño después de intentar ver qué código tardaba tanto en ejecutarse.
En el método paintClear (Graphics g) he agregado
ocean = sprites.getSprite("oceano.gif");
g.setPaint(new TexturePaint(ocean, new Rectangle(0,t,ocean.getWidth(),ocean.getHeight())));
g.fillRect(10, 10,getWidth() - 20,getHeight() - 110);
que hizo que todo funcionara sin problemas, sin embargo, cuando eliminé estas líneas, ¿todo se ralentizó? ¿Qué pudo haber causado esto?
No soy desarrollador de juegos, pero ese framerate parece muy lento.
No estoy seguro de cómo está funcionando su código, pero una posibilidad para mejorar el rendimiento del renderizado sería encontrar aquellas partes de la pantalla que no cambian demasiado (como las paredes del laberinto) y evitar recrearlas para cada cuadro.
Crea una Imagen Buffered que contenga los elementos constantes (laberinto ?, de fondo) y luego vuelve a dibujarla primero para cada cuadro. En la parte superior de esta imagen almacenada en búfer, dibuja los elementos variables (PacMan, fantasmas, puntos, etc.).
Esta técnica, junto con muchos otros consejos de rendimiento de Java2D, se analiza en el excelente libro de Romain Guy Filthy Rich Clients .
Wow, ese es un problema bastante difícil para alguien que acaba de aprender Java.
¿Mi consejo? Piensa en términos de objetos. ¿Puedes escribir algo SIN una interfaz de usuario que imita el comportamiento del juego en sí? Una vez que funcione, puede concentrarse en los problemas especiales de la interfaz de usuario. Sí, comience con una versión local antes de la pieza en red.
No soy un jugador. Me pregunto qué ofrecería Java2D API para mejorar tu vida.
¿Cuánto tiempo tienes para terminarlo?
El código que mencionó anteriormente no puede ser la fuente del problema de 1 fps ... Tengo un código que hace mucho más que esto y que se ejecuta mucho más rápido.
¿Puede comparar ese código y asegurarse de que sea la raíz del problema?
En primer lugar, le recomiendo que use constantes con nombre en lugar de tener números mágicos al azar en su código y considere el uso de enumeraciones para sus tipos de células. Si bien no hará que su código se ejecute más rápido, sin duda lo hará más fácil de entender. Además, ''i'' se usa normalmente como contador, no por un valor de retorno. Probablemente deberías llamarlo cellType
o algo similar. También te recomiendo que uses una matriz 2D para tu mapa escénico, ya que hace que una cantidad de cosas sea más fácil, tanto logísticamente como conceptualmente.
Dicho esto, he aquí algunas cosas para probar:
Tire del setColor()
fuera del ciclo y hágalo una vez. El compilador podría realizar un levantamiento invariable de bucle y, por lo tanto, hacer esto por usted (y probablemente lo haga), pero conceptualmente, probablemente debería hacer esto de todos modos, ya que parece que desea que todas las paredes tengan un color.
Intenta llamar a drawRect()
lugar de fillRect()
y ver si se dibuja más rápido. No creo que lo haga, pero vale la pena intentarlo, aunque parezca más feo. Del mismo modo, puedes intentar crear una Image
y luego dibujar eso. Esto tiene la ventaja de que es muy fácil decirle a tu objeto Graphics que implemente una transformación en tu imagen. Además, considere sacar esto por completo y asegúrese de que se trata de un golpe de rendimiento significativo.
Además, normalmente no es necesario que pregunte al padre por su objeto Graphics e implemente la pintura directamente en él. Por el contrario, debe anular su método paintComponent()
y simplemente utilizar los gráficos que se le entregan (posiblemente llamando a los métodos de ayuda como lo hace). Los componentes Swing tienen doble buffer por defecto, por lo que no es necesario que lo implemente usted mismo; simplemente deja que el objeto columpio haga su trabajo y deja que sepas cuándo pintar.
Además, terminas volviendo a pintar toda la pantalla, lo cual es algo exagerado. Si llama a repaint(Rectangle)
, Swing puede elegir volver a dibujar solo las secciones de su tablero que están explícitamente marcadas como sucias. Cuando actualice uno de sus sprites, llame a repaint (r) solo en el área de las ubicaciones antiguas y nuevas del sprite. Cuando completa un nivel y necesita una nueva placa, puede llamar a repintado () (sin parámetros) para volver a dibujar todo el mapa.
También debe consultar el tutorial de Sun para obtener algunos consejos sobre la eficacia en Swing.
Java / Swing double-buffers por defecto. Si está utilizando Swing, no necesita duplicar el búfer por separado, como sugieren otras respuestas.
Estoy de acuerdo con Allain, que el código que enumeró no puede ser la causa de 1 fps. He escrito un código de animación Java / Swing altamente ineficiente que se ejecuta mucho más rápido de lo que describes. Haga más pruebas para reducir la causa de la lentitud.
Para que no se preocupe de que sea Java, trabajé en un analizador de espectro (como un O-scope) donde toda la parte de la GUI (el rastreo, los menús, el botón y el manejo de la rueda) se realizó en Java. Cuando llegué, estaba recibiendo 1 fps, cuando me fui eran 12-20. Eso tuvo un montón de procesamiento y se ejecutaba en un procesador muy lento.
Mire solo la actualización de partes de la GUI que necesita actualizar. A menudo puede volver a dibujar toda la pantalla, pero simplemente configure una región de recorte para la parte que está realmente actualizada.
Tenga cuidado con los bucles internos: son The Speed Killer.
Intenta evitar asignar y liberar un gran número de objetos. No digo que no uses objetos, digo que no crees uno para cada píxel :)
Buena suerte
Si es posible, debe conservar una imagen del laberinto y dibujarla en una llamada a la biblioteca. Probablemente no necesite una resolución completa, si quieres una sensación cuadrangular de 8 bits, espero que la biblioteca gráfica esté más que feliz de obligar a 8 ^)
Además, como han mencionado otros, puede ahorrar tiempo al volver a dibujar solo aquellas partes de la pantalla que necesitan actualización. Esto puede ser molesto de implementar, pero puede permitirle mejorar significativamente su velocidad de cuadros. ¡Asegúrese de hacer algunos experimentos para asegurarse de que este sea el caso antes de ejercer el esfuerzo requerido!
Todavía me considero un principiante con Java, pero recientemente desarrollé un juego Frogger-esque con mapa dinámico y editor usando algunas de las técnicas que ha mencionado, y estoy muy feliz de brindarle alguna ayuda.
Como se mencionó, las enum son el camino a seguir. Establecí mi mapa como una matriz bidimensional y establecí una enumeración para cada tipo diferente, escribiendo un método dentro de mi clase de mapa para tomar una imagen y dividir cada cuadrado en el mapa para cada valor en mi enumeración.
Un tutorial que me ayudó con el mapeo se puede encontrar en Coke and Code . Todo el código fuente está allí si necesitas una mano con algo de eso, aunque pareces tener una comprensión decente de lo que estás haciendo. Si aún necesita ayuda, siempre podría arrastrar algún código fuente.
Parece que su llamada a Thread.sleep no hace lo que pretendía, pero no creo que sea la fuente de su problema. Tienes:
Thread.sleep(Math.max(0, startTime - System.currentTimeMillis()));
startTime siempre será menor que System.currentTimeMillis (), por lo que startTime - System.currentTimeMillis () siempre será negativo y, por lo tanto, su suspensión siempre será de 0 milisegundos. Es diferente del ejemplo que mostró porque el ejemplo incrementa startTime en 40 milisegundos antes de hacer el cálculo. Está calculando cuánto tiempo dormir para rellenar el tiempo de dibujo a 40 milisegundos.
De todos modos, volviendo a tu problema. Recomiendo la medición para descubrir dónde se está gastando su tiempo. No tiene sentido optimizar hasta que sepa lo que es lento. Usted ya sabe cómo usar System.currentTimeMillis (). Intenta usar eso para medir dónde va todo el tiempo. ¿Está todo gastado dibujando las paredes?
EDITAR - Veo que esto se marcó como aceptado, así que ¿debo inferir que el problema desapareció cuando arregló el tiempo de suspensión? No tengo mucha experiencia en la GUI de Java, pero puedo especular que tal vez su código estaba eliminando otros hilos importantes. Al configurar su hilo para tener la máxima prioridad y solo llamar a suspensión (0), usted garantiza que ningún otro hilo en su proceso puede hacer nada. Aquí hay una publicación del blog de Raymond Chen que explica por qué.