para hashtags fotografia estudio arquitectura architecture oop

architecture - hashtags - ¿Qué hay de malo con la arquitectura de un objeto de juego dibujando y actualizando?



hashtags para fotografia de arquitectura (6)

¿Cuáles son los motivos a favor y en contra de que un objeto del juego dibuje y se actualice? Por ejemplo, si tienes un juego donde el jugador tiene una posición en la pantalla, ¿por qué no tener una clase que lo abarca todo?

public class Player { private int x, y, xVelocity, yVelocity; private Sprite s; //... public Player() { // load the sprite here, somehow? } public void draw(CustomGraphicsClass g) { g.draw(s, x, y); } public void update(long timeElapsed) { x += (xVelocity * timeElapsed); y += (yVelocity * timeElapsed); } }

¿Qué hay de malo con este diseño? ¿Cuáles son las caídas o las preocupaciones? ¿Cómo sería mejor escribir algo como esto, o mejor diseñar este tipo de cosas en un juego?

Además, algo conectado, ¿cómo implementarías la carga de esa imagen de Sprite?

Y, además, ¿cómo implementarías la colisión entre dos Player ?

(Probablemente debería separar estas dos preguntas adicionales en nuevas preguntas, ¿eh?)


Es útil observar la posibilidad de que la mayoría de los objetos en un sistema solo modifiquen los descriptores específicos del motor (velocidad, animación activa) y permitan que el motor se encargue del efecto real. Hay algunas excepciones a esto (generalmente viñetas y otros efectos de un solo tilde), pero en general estos sistemas se basan en un único tic universal que actualiza el juego. La razón de esto es principalmente, como mdma señaló en su comentario sobre la respuesta de Roman, que el motor real hace mucho más que simples operaciones individuales de renderizado. De manera similar, un motor de física actualizará todo el mundo, calculando los volúmenes de colisión teniendo en cuenta el movimiento de sub-tick.

Cargar un sprite suele ser una cuestión de cargar los recursos de un mapa completo y luego abordar ese sprite por su nombre dentro del repositorio de recursos del mapa.

La colisión generalmente es manejada por un motor de física separado, ver arriba.


Está bien, pero si tiene muchos objetos diferentes, todos con sprites, posiciones y velociites que necesitan actualización, habrá mucha replicación. Puedes empujar la ubicación, la velocidad a una clase base, pero esto dificulta el tipo de movimiento. Mejor es separar el movimiento del objeto mismo.

Por ejemplo, considere una pelota que rebota hacia arriba y hacia abajo. No es fácil modelar solo con la velocidad. En su lugar, cree una clase Motion, con ConstantMotion (para velocidad) y BounceMotion para rebote. La clase de movimiento se encarga entonces de actualizar el estado de posición del objeto de cuadro a cuadro.


Supongamos que cada vez que se actualiza su objeto (es decir, el reproductor) debería

1) redibujar a sí mismo

2) notificar a otras unidades que está actualizado

3) escribe "acción-actualización" en el historial / logaritmo / lo que sea (quizás desees tener la posibilidad de reproducir todo el juego una vez terminado, como una película).

....

n) cualquier otra interacción entre su jugador-objeto y su entorno.

En todos estos casos, deberá cambiar su método de actualización, como:

public void update(long timeElapsed) { dosmth(); redraw(); notifyUnits(); updateHistory(); }

Es muy molesto. Es por eso que en tales casos se debe usar el patrón Observer. Su objeto debe notificar a todos los oyentes que fue actualizado. Los oyentes (GraphicsContext, History, units) reaccionarán de forma adecuada y su programa será fácil de mantener porque todas sus partes serán responsables solo de una tarea concreta.


Un posible inconveniente podría ser una violación de la separación de preocupaciones. Pensaría que, idealmente, los objetos no deberían saber cómo se renderizan, de modo que el motor de representación pueda ser ajustado por separado de los objetos del juego ... aunque, en la práctica, puede ser que estas cosas a menudo sean demasiado interdependientes ser separado de esta manera.


Combina todos sus códigos lógicos y de representación cuando tienen poco en común más allá de estar conceptualmente vinculados a la misma "entidad". A medida que su clase crece, puede encontrarse con un enorme Player monolítico que es una pesadilla para mantener. Partir a lo largo de los límites del dominio (renderizado, AI) lo hace más manejable sin tener que renunciar a mucho ya que esos dominios no tienen mucha superposición.

Más allá de la mantenibilidad, hay algunas otras consideraciones:

  1. Si desea procesar el procesamiento y la IA en diferentes subprocesos, mezclar su estado en la misma clase es simplemente pedir problemas desagradables de subprocesos múltiples.

  2. Si está usando un lenguaje como C ++, las clases altamente acopladas como esta pueden matar sus tiempos de compilación.

  3. Según la forma en que el código y los objetos se distribuyan en la memoria, dividir los objetos en componentes separados para cada dominio puede proporcionarle una mejor coherencia de caché y un rendimiento mucho mejor.

Aquí hay mucha más información si tienes curiosidad.


Habiendo caído por este patrón antes de aquí es mi entrada:

Para un juego, el rendimiento será el mayor inconveniente. Es probable que desee mantener todos los contextos de dibujos, objetos, etc. en un solo lugar y optimizar un bloque de código más grande.

Si por alguna razón desea renderizar en diferentes plataformas, entonces este enfoque falla debido a la falta de separación, de nuevo, un procesador de plug-in es un mejor enfoque.