¿Patrón común para escalar "unidades reales" a píxeles?

10

Esta es una pregunta de seguimiento a esta otra .

Me gustaría saber si hay un patrón común / típico / mejor para escalar mi representación del mundo (actualmente 160Kmx160Km) para que se ajuste al área de dibujo (actualmente 800x600 píxeles).

Puedo pensar en al menos cuatro enfoques diferentes:

Una ingenua (como lo hice hasta ahora). Implementé una función global sc(vector)que simplemente devolverá una copia reducida del vector pasado. Esto, por supuesto, funciona, pero me obliga a escribir código como:

drawCircle(sc(radius), sc(position))

Funciones de envoltura . Podría definir varias funciones, cada una de ellas envolviendo el middleware original. Por ejemplo, podría definir myDrawCircleque primero escalaría los argumentos que necesitan escalarse, y luego llamar drawCirclecon el último. Esto haría que mi código sea más legible y fácil de mantener, pero debería escribir muchas funciones de ajuste, que suenan tontas.

Decorador de funciones . Podría simplemente decorar las funciones de middleware existentes, proporcionando escala automática para todos los parámetros que son una instancia de la clase Vector3D, pero el problema es que esas funciones también trabajan con los mismos parámetros de estar listo Vector2Dtambién, y el decorador no tendrían ninguna manera de saber qué listas deben escalarse (el radio, por ejemplo) y cuáles no (los valores RGB).

Inicialización de superficie . Al definir la superficie en la que voy a dibujar, podría definir el factor de escala (para luego usar metros y no píxeles como parámetros). Esto funcionaría de manera transparente para mí y sería mi solución preferida, pero, por supuesto, debería implementarse en el middleware, por lo que no es una opción real.

... de todos modos: dado que este es un problema muy común, me pregunto si hay un patrón establecido que resuelva elegantemente este problema que no pude encontrar.

PD: Para este proyecto, estoy usando python (con pygame ), pero, aunque una respuesta específica de python / pygame es muy apreciada, estoy más interesado en la descripción general / de alto nivel del patrón en lugar de su implementación concreta.

Gracias de antemano por su tiempo y experiencia.

Mac
fuente

Respuestas:

6

La forma estándar de hacerlo es configurar una matriz de transformación para realizar la conversión durante el renderizado. Para el renderizado en 3D, es la matriz de transformación de vista para la cámara la que lo hace.

La mayoría de las API 2D también tienen una forma de especificar una transformación de vista, ya sea como una matriz de 2x3 o como una escala, traslación y rotación separadas.

Un vistazo rápido a la documentación de pygame sugiere que tendrá que implementar una matriz de transformación de vista usted mismo. ¿Le permite derivar su propia clase de su clase de superficie para permitirle agregar esa funcionalidad?

Adán
fuente
Tu respuesta es muy útil (+1). Puedo subclasificar mi clase de superficie, pero necesito más tiempo para explorar si puedo lograr lo que se indica en tu publicación. Soy muy nuevo en la programación de juegos y los gráficos en general, ¿tiene algún enlace para recomendar que explique este enfoque de matriz (o incluso solo las matemáticas involucradas usando una matriz para escalar una superficie?). ¡Gracias!
mac
1
Dado que es 2D y no hay rotación involucrada, @mac básicamente está diciendo que ajuste las funciones y puede usar su división de escala simple en esos contenedores. La razón por la que normalmente se usa una matriz completa es que la mayoría de las API tienen una matriz que controla la ventana gráfica, pero parece que pygame no lo hace, por lo que debe hacerlo usted mismo una capa hacia arriba.
Patrick Hughes
2

Dado que este es un problema muy común, me pregunto si hay un patrón establecido que resuelva elegantemente este problema que no pude encontrar.

Por lo general, las personas no intentan escalar en tiempo de ejecución en juegos 2D. No estoy de acuerdo con que sea un problema común. Si las personas desean un minimapa o algún otro cambio de escala fijo, a menudo se hace un nuevo conjunto de gráficos para este propósito. Es raro que necesites una rutina única para correr a 2 niveles de zoom diferentes en un juego 2D.

Si usa una API 3D, puede obtener esta funcionalidad de forma gratuita, solo cambie los parámetros de la cámara / ventana gráfica.

PyGame es una API muy antigua y desafortunadamente solo es realmente adecuada para 2D. Incluso si pudiera encontrar sistemas de escala adecuados para los diferentes niveles de zoom, el rendimiento no será lo suficientemente bueno y es probable que la apariencia sea inaceptablemente mala.

Aconsejaría que si desea acercarse y alejarse mucho, cambie a una API 3D moderna lo antes posible. Recomendaría Pyglet, pero es probable que también haya otros.

Kylotan
fuente
Gracias por tu respuesta (+1). Ya lo usaba pygletsen el pasado para una simulación 3D. Seguramente es más capaz que eso pygame, pero el soporte para 2D es bastante más bajo que el de adentro pygame. La documentación / ejemplos disponibles también son menos detallados, lo cual es una molestia para mí, ya que soy un principiante en el desarrollo de juegos, y realmente necesito entender la base de las operaciones más comunes. :) En cuanto a la "edad" del pygame: tienes razón. ¡Sin embargo, hay una modernización en progreso! :)
mac
En cuanto a: "Es raro que necesites una rutina única para ejecutar en 2 niveles de zoom diferentes" ... Pensé que eso era lo que se usaría al cambiar el tamaño de una ventana / la resolución de un juego de pantalla completa. Por su comentario, entendí que no es: ¿algún indicador de lo que es "común" en su lugar?
mac
¿Qué operaciones 2D estás realizando donde pyglet es más de bajo nivel que pygame? Ambos te permiten dibujar un sprite con 1 línea de código. Cuando cambia el tamaño de la ventana de un juego 2D, la relación píxel a unidad mundial casi siempre se mantiene constante. Entonces terminas dibujando más sprites: no los dibujas de manera diferente.
Kylotan
En el lado de bajo nivel de las cosas: no soy realmente un experto en ninguna de las dos bibliotecas, pero en pyglets no pude replicar fuera de la caja los comportamientos de representación grupal ofrecidos por pygame (como en pygame.sprite.LayeredUpdatespor ejemplo). En cuanto a la relación inmutable: tengo lo que quieres decir. El comportamiento que describe no es el que quiero replicar, pero entendí lo que quiere decir, ¡gracias por la aclaración! :)
mac
pyglet tiene objetos OrderedGroup - los documentos están aquí si usted o alguien más está interesado: pyglet.org/doc/programming_guide/displaying_images.html#sprites
Kylotan