Estoy haciendo un pequeño rastreador de mazmorras en el espacio, y me gustaría escuchar algunos consejos sobre cómo hacer que el motor del motor sea más agradable. Básicamente, actualmente todo se basa en una gran cantidad de gerentes:
- BackgroundManager: tiene un
AddBackground(image, parallax)
método para crear efectos de fondo geniales. - ConfigManager: lee / crea el archivo de configuración y también contiene los datos leídos de ese archivo de configuración.
- DrawManager: tiene un
Draw(sprite)
método para dibujar cosas en la pantalla y cosas comoSetView(view)
,GetView()
etc. - EntityManager: contiene todas las entidades activas y tiene métodos para agregar, eliminar y encontrar entidades.
- DungeonManager (en realidad se llama un GridManager, pero esto es por simplicidad): tiene métodos como
GenerateDungeon()
,PlaceEnemies()
,PlaceFinish()
etc.
Ahora ni siquiera estoy a la mitad de la lista de todos mis gerentes, así que creo que esto tiene que cambiar. Mi juego también se basa en pantallas, lo que lo hace más molesto porque no necesito la mitad de las cosas que mis gerentes están administrando, por ejemplo, el menú principal (no necesito física / entidades / mazmorras en mi menú principal) !)
Ahora pensé en hacer que los gerentes no sean estáticos, y darle a ScreenMainGame una instancia de todos los gerentes específicos del juego. Pero eso hace que llamar / hacer algo relacionado con los gerentes sea un gran desastre ... por ejemplo, si quisiera sacar mi mazmorra de cualquier lugar que no esté ScreenMainGame.Draw()
, tendría que hacer esto ...
((ScreenMainGame)ScreenManager.CurrentScreen).GridManager.Draw()
Eso es realmente feo.
Entonces, compañeros desarrolladores de juegos, ¿alguno de ustedes tiene una idea de cómo resolver este desastre? Se lo agradeceria!
fuente
Respuestas:
¿Qué pasa con un motor basado en componentes ?
Tendría una clase principal llamada
Engine
, que mantendría una lista deGameScreens
, que ellos mismos tendrían una lista deComponents
.El motor tiene un
Update
y unDraw
método y ambos llaman losGameScreen
'sUpdate
y losDraw
métodos, que pasan por cada componente y llamanUpdate
yDraw
.Presentado así, estoy de acuerdo en que suena como un diseño pobre y repetitivo. Pero créanme, mi código se volvió mucho más limpio mediante el uso de un enfoque basado en componentes que con todas mis antiguas clases de administrador .
También es mucho más simple mantener dicho código, ya que solo está pasando por una gran jerarquía de clases y no tiene que buscar
BackgroundManager
todos los diferentes fondos específicos. Sólo tienes unaScrollingBackground
,ParallaxBackground
,StaticBackground
, etc, todos ellos derivados de unaBackground
clase.Eventualmente construirá un motor bastante sólido que puede reutilizar en todos sus proyectos con muchos componentes y métodos auxiliares de uso frecuente (por ejemplo,
FrameRateDisplayer
como una utilidad de depuración, unaSprite
clase como sprite básico con una textura y métodos de extensión para vectores y generación de números aleatorios).Ya no tendrías una
BackgroundManager
clase, sino unaBackground
clase que se administraría sola.Cuando comienza tu juego, todo lo que tienes que hacer es básicamente esto:
Y eso es todo para el código de inicio del juego.
Luego, para la pantalla del menú principal:
Tienes la idea general.
También mantendría la referencia de
Engine
dentro de todas susGameScreen
clases, para poder agregar nuevas pantallas incluso dentro de unaGameScreen
clase (por ejemplo, cuando el usuario hace clic en el botón StartGame mientras está dentro de suMainMenuScreen
, puede hacer la transición aGameplayScreen
).Lo mismo ocurre con la
Component
clase: debe contener la referencia de su padreGameScreen
, para tener acceso tanto a laEngine
clase como a su padreGameScreen
para agregar nuevos componentes (por ejemplo, puede hacer una clase relacionada con HUD llamadaDrawableButton
que contiene unDrawableText
componente y unStaticBackground
componente).Incluso puede aplicar otros patrones de diseño después de eso, como el "patrón de diseño de servicios" (no estoy seguro sobre el nombre exacto) donde puede mantener diferentes servicios útiles dentro de su
Engine
clase (simplemente mantiene una lista deIService
sy permite que otras clases agreguen servicios ellos mismos) ) Por ejemplo, mantendría unCamera2D
componente en todo mi proyecto como un servicio para aplicar su transformación al dibujar otros componentes. Esto evita tener que pasarlo como parámetro en todas partes.En conclusión, ciertamente puede haber otros mejores diseños para un motor, pero el motor propuesto por este enlace me pareció muy elegante, extremadamente fácil de mantener y reutilizar. Yo personalmente recomendaría al menos intentarlo.
fuente
GameComponent
servicios y servicios. No hay necesidad de unaEngine
clase separada .Lo que desea hacer es separar su código en componentes y servicios. XNA ya tiene soporte incorporado para estos.
Vea este artículo sobre
GameComponents
y servicios. Luego vea esta respuesta sobre el uso de servicios en XNA, y esta respuesta más general sobre servicios en cualquier idioma.fuente
El hecho de que sean estáticos o globales no significa que siempre tengan que cargarse / inicializarse. Use un patrón Singleton y permita que los gerentes puedan liberarse y cargarse nuevamente bajo demanda.
fuente