Quiero desarrollar un gran mapa mundial; al menos 8000 × 6000 píxeles de tamaño. Lo he dividido en una cuadrícula de 10 × 10 de imágenes PNG de 800 × 600 píxeles. Para evitar cargar todo en la memoria, las imágenes deben cargarse y descargarse según la posición del jugador en la cuadrícula.
Por ejemplo, aquí está el jugador en posición (3,3)
:
A medida que se mueve hacia la derecha (4,3)
, las tres imágenes del extremo izquierdo se desasignan mientras que las tres imágenes de la derecha se asignan:
Probablemente debería haber un umbral dentro de cada celda de la cuadrícula que active la carga y descarga. La carga probablemente debería ocurrir en un hilo separado.
¿Cómo diseño un sistema así?
Respuestas:
Hay algunos problemas para resolver aquí. El primero es cómo cargar y descargar fichas. ContentManager de forma predeterminada no le permitirá descargar piezas específicas de contenido. Sin embargo, una implementación personalizada de esto:
El segundo problema es cómo decidir qué mosaicos cargar y descargar. Lo siguiente resolvería este problema:
El último problema es cómo decidir cuándo cargar y descargar. Esta es probablemente la parte más fácil. Esto podría hacerse simplemente en el método Update () una vez que se determinó la posición de la pantalla del jugador:
Por supuesto, también necesitaría dibujar los mosaicos, pero dado el ancho de mosaico, la altura de mosaico y la matriz Tiles [], esto debería ser trivial.
fuente
Lo que quieres hacer es bastante común. Para un buen tutorial sobre esta y otras técnicas comunes, consulte esta serie de motores de mosaico .
Si no has hecho algo así antes, te recomiendo ver la serie. Sin embargo, si lo desea, puede obtener el último código de tutoriales. Si haces lo posterior, mira el método de dibujo.
En pocas palabras, debes encontrar tus puntos X / Y mínimo y máximo alrededor del jugador. Una vez que tenga eso, simplemente recorra cada uno y dibuje ese mosaico.
Como puede ver, están sucediendo muchas cosas. Necesita una cámara que cree su matriz, necesita convertir su ubicación de píxeles actual en un índice de mosaico, encuentra sus puntos mínimo / máximo (agrego un poco a mi MAX para que se extienda un poco más allá de la pantalla visible) ), y luego puedes dibujarlo.
Realmente sugiero ver la serie de tutoriales. Cubre su problema actual, cómo crear un editor de mosaicos, mantener al jugador dentro de los límites, animación de sprites, interacción con IA, etc.
En una nota al margen , TiledLib tiene esto incorporado. También podría estudiar su código.
fuente
He estado trabajando en algo muy similar para mi proyecto actual. Este es un resumen rápido de cómo lo estoy haciendo, con algunas notas al margen sobre cómo hacer las cosas un poco más fáciles para usted.
Para mí, el primer problema fue dividir el mundo en trozos más pequeños que serían apropiados para cargar y descargar sobre la marcha. Dado que está utilizando un mapa basado en mosaicos, ese paso se vuelve significativamente más fácil. En lugar de considerar las posiciones de cada objeto 3D en el nivel, ya tiene su nivel bien dividido en mosaicos. Esto le permite simplemente dividir el mundo en trozos de mosaico X por Y, y cargarlos.
Vas a querer hacer eso automáticamente, en lugar de hacerlo a mano. Como está utilizando XNA, tiene la opción de usar Content Pipeline con un exportador personalizado para su contenido de nivel. A menos que conozca alguna forma de ejecutar el proceso de exportación sin volver a compilar, honestamente lo recomendaría. Si bien C # no es tan lento para compilar como C ++ tiende a ser, aún no desea tener que cargar Visual Studio y recompilar su juego cada vez que realice un cambio menor en el mapa.
Otra cosa importante aquí es asegurarse de utilizar una buena convención de nomenclatura para los archivos que contienen los fragmentos de su nivel. Desea poder saber que desea cargar o descargar el fragmento C y luego generar el nombre de archivo que necesita cargar para hacerlo en tiempo de ejecución. Finalmente, piense en cualquier pequeña cosa que pueda ayudarlo en el futuro. Es realmente agradable poder cambiar qué tan grande es un fragmento, volver a exportar y luego ver los efectos de eso en el rendimiento de inmediato.
En tiempo de ejecución, sigue siendo bastante sencillo. Necesitará alguna forma de cargar y descargar asincrónicamente fragmentos, pero esto depende en gran medida del funcionamiento de su juego o motor. Su segunda imagen es exactamente correcta: debe determinar qué fragmentos deben cargarse o descargarse, y hacer las solicitudes apropiadas para que ese sea el caso si aún no lo está. Dependiendo de cuántos fragmentos haya cargado al mismo tiempo, puede hacer esto siempre que el jugador cruce un límite de un fragmento a otro. Después de todo, de cualquier manera, debes asegurarte de que se cargue lo suficiente para que, incluso en el peor (razonable) tiempo de carga, el trozo todavía se cargue antes de que el jugador pueda verlo. Probablemente querrás jugar mucho con este número hasta que obtengas un buen equilibrio entre rendimiento y consumo de memoria.
En lo que respecta a la arquitectura real, querrá abstraer el proceso de cargar y descargar los datos de la memoria del proceso de determinar qué se debe cargar / descargar. Para su primera iteración, ni siquiera me preocuparía por el rendimiento de la carga / descarga y solo obtendría lo más simple que podría funcionar, y me aseguraría de que está generando las solicitudes adecuadas en el momento adecuado. Después de eso, puede ver cómo optimizar la carga para minimizar la basura.
Me encontré con mucha complejidad adicional debido al motor que estaba usando, pero eso es bastante específico de implementación. Si tiene alguna pregunta sobre lo que hice, comente y haré lo que pueda para ayudarlo.
fuente