2010-07-17 15 views
5

Estoy programando un gran juego en Java y estoy tratando de optimizar el código, pero también para mantener el código limpio y bien organizado. Ahora no estoy seguro de si debería usar el campo público estático de clases individuales que tienen un par de variables que muchas instancias usan.Uso del campo público estático, buena práctica de programación/rápido?

Por ejemplo, la cámara de clase tiene una posición xey que define qué parte del mapa está mirando el usuario y qué debe dibujarse en la pantalla. Actualmente estoy evaluando con 50 000 unidades y tengo las siguientes opciones para dibujarlas.

1: almacenar una referencia a la instancia de la cámara en cada unidad y llame a getX() y getY() cuando se debe elaborarse:

public void paint() 
{ 
    paint(x - camera.getX(), y - camera.getY()); 
} 

2: Fuente de las coordenadas de la cámara como argumentos a cada unidad cuando se debe elaborarse:

public void paint(int cameraX, int cameraY) 
{ 
    paint(x - cameraX, y - cameraY); 
} 

3: Hacer las variables x e y de la clase de cámara estática:

public void paint() 
{ 
    paint(x - Camera.x, y - Camera.y); 
} 

Me interesa lo que generalmente se considera la mejor solución y si afecta el rendimiento. Tal vez hay más formas de hacer esto en las que todavía no he pensado.

Gracias!

+0

Cuando reescribí mi código para usar campos públicos estáticos noté un descenso en la velocidad de fotogramas de aproximadamente 60 fps. Retrocediendo, aumenté el rendimiento a los niveles anteriores pero no descubrí qué causó la caída. Así que supongo que me tomaré un poco más de tiempo extra para configurar todas las referencias y olvidarme de las cosas del campo estático. Gracias por las respuestas! – ArmoredSandwich

Respuesta

3

me gustaría sugerir que crea una clase Pintor y hacer lo siguiente:

public void paint(Painter painter) 
{ 
    painter.draw(x, y, unit_sprite); 
} 

De esta manera las unidades no tienen que preocuparse por la existencia de una cámara. No es asunto de la unidad cómo funciona eso. La unidad solo necesita saber cómo dibujarse en el esquema de coordenadas global y el pintor entenderá cómo se relaciona con las coordenadas de pantalla reales.

¿Por qué es esta una buena idea?

  • Reducción de código, cada unidad no tiene que preocuparse por la traducción al marco de coordenadas correcto. Todo ese código existe una vez en una sola ubicación.
  • Facilidad de cambio. Por ejemplo, supongamos que decide implementar una función de zoom. Si cada unidad hace su propia traducción, eso sería un dolor. Sin embargo, si toda esa lógica está en el pintor, puede modificar el pintor para que se encargue de reajustar las imágenes y determinar los desplazamientos correctos.
  • Disminución de las dependencias, las unidades no saben lo que es una cámara, son más simples porque no se preocupan por eso.

En cuanto a sus propuestas de solución:

  1. Almacenamiento de una referencia a la cámara en el objeto asume que sólo habrá alguna vez una cámara. ¿Qué pasa si implementa algo así como una vista dividida? Esto puede ser poco probable, pero al almacenar la referencia innecesariamente se encerrará en una perspectiva.
  2. El problema con la división de las variables es que lógicamente las dos piezas son un elemento. Esto hace que sea un poco más difícil averiguar qué está sucediendo, causará problemas si algún día necesita más parámetros, y también brinda información a la unidad que realmente no necesita.
  3. Esto tiene los mismos problemas que el # 1, lo encierra en una sola cámara que se usa en todas partes. La unidad no debería ser responsable de definir cómo se usa la cámara.

En cuanto al rendimiento:

La diferencia va a ser casi nada. No estoy seguro de qué método va a ganar en una batalla de rendimiento, pero puedo decirte que si tienes problemas de rendimiento van a estar en otro lado (supongo que en realidad las funciones de blitting). Al combinar todo el código que relaciona las compensaciones es una sola ubicación, mi método propuesto facilitará la implementación de una optimización. Por ejemplo, una optimización común no es dibujar cosas que están fuera de pantalla. Si tiene 20 funciones, todas calculan desplazamientos e invoca funciones de dibujo, tendrá que ir a cada una de esas funciones y cambiarlas. Si usa un pintor, puede simplemente cambiar la clase del pintor para ignorar la solicitud de dibujar fuera del área visible y listo.

cuanto a las variables estáticas en general:

considero variables estáticas (y únicos) como variables globales y por lo tanto casi nunca se utilicen. Hacerlos estáticos me vincula a decisiones particulares. No soy lo suficientemente inteligente como para tomar todas las decisiones correctas por adelantado y entonces necesito que mi código sea flexible.

Algunas pautas:

  1. Si ves que necesitas para tener acceso a los datos dentro de un objeto, es decir, la x, valor y considerar si debe en lugar de decirle a ese objeto de hacer algo se invoca un método. Es decir. Dile no preguntar
  2. Si un objeto (como Painter) solo se utiliza para una tarea en particular por un objeto, entonces debería ser un parámetro y no una variable miembro.
+0

Guau, gracias por profundizar en responder mi pregunta. Definitivamente voy a rediseñar mi enfoque e implementar algún tipo de clase de Pintor. De hecho, me pregunto por qué no se me ocurrió esa solución hasta ahora. – ArmoredSandwich

2

Si solo tiene una cámara en todo momento, elegiría la tercera. De lo contrario, elegiría la segunda forma.

Creo que desde el punto de vista del rendimiento, usar un campo público estático es una buena idea. En cuanto a la legibilidad del código, si se entiende fácilmente que solo hay una cámara en todo momento, también debería estar bien.

0

En general, el segundo debe proporcionar un buen equilibrio; también asegurará que no guarde accidentalmente referencias a la cámara más allá cuando lo anticipe, o que no tenga conflictos con campos estáticos con estado.

Tenga en cuenta que debe seguir perfilando el rendimiento independientemente de la solución que elija, pero no anticipe que se trata de un cuello de botella hasta que tenga evidencia de que es uno.

0

En todos los lenguajes de programación, siempre se recomienda utilizar métodos get/set para miembros estáticos y de instancia. Esto permite cambiar las implementaciones internas de forma transparente para un código de cliente, si es necesario. Sin embargo, a veces estas reglas se rompen, si el rendimiento es muy importante.

+0

No es verdadero si el idioma admite propiedades. –

1

Vas a tener que referencia en su contexto para estar seguro, pero aquí es mi experiencia:

  • Paso de parámetros a funciones es generalmente el más rápido si usted tiene un pequeño número de parámetros que se utiliza mucho en un bucle interno. Esto se debe a que el JIT asignará estos a los registros
  • El acceso a las variables públicas estáticas de los miembros también es bastante rápido, solo problemas a tener en cuenta son posibles problemas de concurrencia (por ejemplo, ¿podría el motor cambiar la posición de la cámara mientras está en medio? ¿renderizando un marco?)
  • El acceso a través de una referencia de instancia es más lento, pero aún lo suficientemente rápido como para ser utilizado en un juego en tiempo real. Ayuda si su clase es final y los métodos de acceso están en línea por supuesto.
0

Móntelo y vea.

long startTime = System.currentTimeMillis(); 
for(int i=0; i<1000000; i++){ 
    // Call your code 

} 
System.out.println("Total time " + (System.currentTimeMillis() - startTime) + " ms"); 

Supongo que el JIT se ocupará de las diferencias y todas serán más o menos equivalentes. No hay sustituto para cronometrarlo usted mismo. Además, recomendaría crear perfiles de la aplicación y ver dónde se gasta el tiempo al ejecutar su aplicación antes de realizar este tipo de ajustes de microperformance.

1

Enumere y calcule en milisegundos con m.server utilizando enteros vaule.

que es invitado sin mirar ningún libro.

0

Tuve la misma pregunta por la misma razón (un gran juego de Java).

He probado dos formas para una variable que representa el tiempo transcurrido desde el último fotograma, se usa en cada instancia de cada objeto en cada fotograma.

Una forma es una estática, la otra manera es pasar esa variable como un argumento hacia abajo desde el bucle principal a cada subclase de cada objeto.

Aquí están mis resultados: http://i.stack.imgur.com/WtSue.png

que he probado en cada sentido 3 veces. Como puede ver, el resultado es bastante similar, excepto entre 130s y 210s, realmente no puedo explicar por qué.

Cuestiones relacionadas