java - modelo - ¿Cómo se puede organizar el código para que un juego se ajuste al patrón MVC?
mvc java swing mysql (6)
Soy un estudiante de primer año en la universidad para obtener mi grado de informática ... He programado muchos en los últimos años, pero últimamente me he dedicado más a las ideas teóricas sobre la organización del código, los patrones de diseño, las diferencias de idiomas, etc.
Tengo una clase de Java, así que dejé mi investigación / desarrollo en C ++ y me mudé a Java y JOGL (Java OpenGL). ¡Es maravilloso! Pero eso está fuera del punto.
Quiero hacer un pequeño juego de rol, pero esta pregunta realmente se aplica a cualquier tipo de juego. ¿Cómo se organizan los objetos del juego de una manera estructurada, como el patrón Model-View-Controller? Parece ser un patrón sorprendente, muy utilizado y tiene mucho sentido, pero me cuesta descubrir cómo implementarlo.
Por ejemplo, necesito hacer un seguimiento de un objeto GL para dibujar en la pantalla. Tengo que tener clases que implementen MouseListener, MouseMotionListener, MouseWheelListener y KeyListener (o una clase, un administrador de entradas todo en uno). Y tengo que poner los datos de mi juego en algún lugar donde todas estas diferentes clases puedan acceder y modificarlo; si alguien presiona un botón en el teclado, la clase de administración de entrada necesita realizar de alguna manera la acción a la que está asignada la clave; cuando se necesita dibujar un cuadro, la clase de gráficos necesita encontrar una forma de recorrer todas las diferentes ''cosas'' y dibujarlas todas.
Y mi mayor problema, la GUI; ¿Dónde lo une todo? Es algo así como la entrada, pero no del todo, y necesita establecer y obtener datos de la simulación real del juego ... Y complicarlo aún más es si decido probar y agregar una red, que (similar a la GUI) ) también necesita tener acceso a una gran cantidad de datos para modificar y leer ...
Oh, estoy confundido. No sé cómo hacer todo esto para trabajar de forma orientada a objetos ... Es bastante fácil escribir cosas que se ajustan claramente a los patrones, pero cuando tienes muchas cosas sucediendo todas atadas a un ciclo de juego, modificándose entre sí y los datos del juego y demás, ... Ni siquiera sé nada más. Tal vez estoy haciendo esto un negocio más grande de lo que realmente es.
¿Alguien más se ha sentido de esta manera? Por favor, ofrezca algo de claridad a mi situación para que pueda pasar menos tiempo preocupándose y sin saber por dónde empezar.
-Ricket
Editar: Encontré un buen diagrama que podría ayudarme a resolver esto ... Fuente: (¡cuidado, archivo PS!) http://www.tucs.fi/publications/attachment.php?fname=TR553.ps.gz
http://img10.imageshack.us/img10/6278/mvcdiagramgamesbl5.png
Edit2: También me gusta la explicación de este tipo sobre cómo planeó su juego MVC: http://interactivesection.wordpress.com/2007/11/19/dum-de-dum-drum-my-first-mvc-game-development/
Edit3: ¡Otro gran artículo! http://dewitters.koonsolo.com/gamemvc.html
El concepto MVC de centralizar la lógica de interacción del usuario es un buen modelo para el desarrollo del juego.
He trabajado un poco con el desarrollo de juegos Flash. Here hay un artículo sobre grupos de objetos en Flash. El concepto es multiplataforma y puede darte algunas ideas.
Tiene razón en preocuparse por todo lo que sucede al mismo tiempo. Dependiendo del diseño de su juego, su ciclo de juego puede tener mucho que enfrentar. Aquí es donde aprenderá todos los trucos sucios de optimización, a menudo de la manera difícil :)
Hay muchas maneras de organizar su código: una opción podría ser escribir una clase de GameManager como Singleton. Todos los objetos del juego se vinculan para la gestión y la interacción del usuario. GameManager maneja todas las entradas de los usuarios y envía mensajes a su grupo de objetos. Puede usar interfaces para definir patrones de comunicación comunes entre los objetos del juego y el GameManager.
En cuanto a la optimización del rendimiento, el enhebrado es muy poderoso. La operación asincrónica puede garantizar que no desperdicies esos preciosos ciclos.
Mi forma de pensar en MVC es como MDUC
Modelo
Monitor
Controlador de entrada de usuario
El modelo contiene los objetos del modelo de dominio
La pantalla muestra el estado actual y el comportamiento de los objetos del modelo de dominio en pantalla.
El controlador de entrada de usuario maneja todas las entradas de usuario.
Es exactamente el mismo patrón, pero los nombres son apenas un poco más descriptivos, por lo que encuentro que las responsabilidades que tiene cada parte del patrón son más claras, por lo que el significado del patrón es más memorable.
Una vez que vea que está dividiendo los datos y las operaciones del modelo de la visualización, de las entradas del usuario, es más fácil ver dónde agrupar qué en su propio código.
Puede ayudarte a pensar en el Modelo como una especie de API de juegos. ¿A qué se reduciría tu juego si no hubiera UI en absoluto para el juego ordenado desde el principio? Mencionas que lo que tienes en mente es un juego de rol, así que en este caso puedes imaginar que el personaje jugador, su inventario, hechizos, habilidades, NPC e incluso cosas como el mapa y las reglas de combate sean parte del modelo. . Es como las reglas y piezas de Monopoly sin los detalles de cómo el juego final muestra eso o cómo el usuario va a interactuar con él. Es como Quake como un conjunto abstracto de objetos 3D que se mueve a través de un nivel con elementos como la intersección y la colisión calculados, pero sin renderizado, sombras o efectos de sonido.
Al poner todos esos en el modelo, el juego en sí mismo ahora es independiente de la interfaz de usuario. Podría estar enganchado a una interfaz de texto ASCII como los juegos Rogue, o una interfaz de línea de comando similar a Zork, o una interfaz de usuario basada en web o 3D. Algunas de esas interfaces de usuario podrían ser un ajuste terrible dependiendo de la mecánica del juego, pero todas serían posibles.
La capa Vista es la capa dependiente de la interfaz de usuario. Refleja la elección específica de la interfaz de usuario que eligió y estará muy dedicado a esa tecnología. Podría ser responsable de leer el estado del modelo y dibujarlo en 3D, ASCII o imágenes y HTML para una página web. También es responsable de mostrar los mecanismos de control que el jugador necesita para interactuar con el juego.
La capa de controlador es el pegamento entre los dos. Nunca debe tener ninguna de la lógica del juego real en él, ni debe ser responsable de conducir la capa de Vista. En su lugar, debe traducir las acciones realizadas en la capa Ver (haciendo clic en los botones, haciendo clic en las áreas de la pantalla, las acciones de la palanca de mando, lo que sea) en las acciones realizadas en el modelo. Por ejemplo, dejar caer un objeto, atacar a un NPC, lo que sea. También es responsable de recopilar datos y realizar cualquier conversión o procesamiento para que sea más fácil para la capa de Vista mostrarlo.
Ahora, tal como lo describí anteriormente, es como si hubiera una secuencia de eventos muy distinta que impulsara el juego que probablemente solo sea realmente apropiada para un juego web. Eso es porque es en lo que he pasado mi tiempo últimamente. En un juego que no está impulsado por la solicitud de un usuario y la respuesta de un servidor como la web (por ejemplo, un juego que se ejecuta en la máquina del usuario), es probable que desee asegurarse de que la capa Modelo implemente bien el patrón Observer. Por ejemplo, si las acciones se llevan a cabo en el Modelo porque el tiempo pasa, es posible que no desee que la capa de Vista esté constantemente sondeando el Modelo en busca de actualizaciones. En cambio, al utilizar el patrón Observer, el Modelo podría notificar a los observadores los cambios en los objetos del Modelo a medida que ocurran. A su vez, podría utilizarse para solicitar una actualización inmediata de la Vista para reflejar el cambio.
Luego, si pasaron 60 segundos, se produjeron algunas reparaciones para la base del jugador, la base podría efectuar las reparaciones e inmediatamente notificar a los observadores conectados que la base se ha actualizado. La Vista podría adjuntarse como un Observador y tener en cuenta que necesita volver a mostrar la base porque su estado ha cambiado. La notificación en sí podría haber incluido suficiente información para actualizar la Vista o podría tener que dar la vuelta y consultar el modelo para actualizar, pero el resultado será el mismo.
Te estás llevando bien allí. Básicamente, hágase la pregunta "¿qué código cambiaría si tuviera que cambiar alguna parte del programa?"
Si cambiara la forma en que se ve sin cambiar los datos básicos, entonces está en la vista. Si se trata de datos que se pueden ver de muchas maneras, es el modelo. Y si es así como juegas, entonces es el control.
Entonces, si se trata de dibujar un "hacha" con dos cuchillas o una, es vista. Si se trata de cuántos puntos de daño infligen con un hacha, es modelo. Y si es si balanceas el hacha escribiendo "s" o haciendo clic derecho, es control.
Todos sus oyentes y manipuladores deben ingresar dentro de la clase Controlador, el estado de los objetos en la pantalla (por ejemplo, posición, color, etc.) debe ser parte de sus clases de Modelo y cualquier código que dibuje cosas en la pantalla será parte de la vista.
Siento contigo Recuerdo cuando descubrí por primera vez el MVC. Intenté meter todo en él. De hecho, hice un juego que utilizaba el patrón MVC. Lo que más tarde descubrí fue que lo que hice fue excesivo. Traté de encajar casi todas las clases que hice en una categoría en MVC.
Lo que sugiero es leer "Patrones de diseño" por la pandilla de los cuatro. Hay muchos patrones útiles además de MVC. A veces no tiene sentido usar MVC en absoluto. Especialmente para juegos, no estoy seguro de si MVC es una buena idea. La razón es que no desea mostrar un objeto de juego de muchas maneras diferentes (vistas), pero desea reutilizar un código de dibujo para muchos tipos diferentes de objetos de juego.
Para mi propio motor de juego en 2D, utilicé el patrón de estrategia bastante activamente. El juego se opone, como el jugador y los monstruos que llamé un Sprite . Dejo que el dibujo del sprite sea manejado por un patrón de estrategia . Es entonces cuando llamé a sprite.draw () Haría algo como esto:
class Sprite {
void draw() {
this.view.draw(this.currentPosition, this.currentOrientation);
}
Point currentPosition; // Current position of this sprite
double currentOrientation; // Facing angle of sprite
};
El beneficio de este enfoque es que puedes compartir un objeto de vista entre varios sprites. Porque normalmente habrá muchos, por ejemplo, monstruos que se verán igual pero que serán posiciones diferentes y posiblemente se comporten de manera diferente.
Entonces, el comportamiento también usaría un patrón de estrategia que sería un objeto que contiene un código que describe el comportamiento. De esa forma puedo aplicar el mismo comportamiento a varios monstruos en diferentes ubicaciones. Entonces, cada cuadro que yo llamaría una función de actualización () para actualizar la orientación de posición y lo que hace el monstruo.
class Sprite {
void setUpdateAction(Action action) {
this.updateAction = action;
}
void update(double start_time, double delta_time)
{
this.prevPosition = position();
advance(delta_time); // Advance to next position based on current speed and orientation
this.updateAction.execute(this, start_time, delta_time);
}
Action updateAction;
};
Hay muchas variaciones de esto. En mi implementación actual, incluso he separado currentPosition , speed , orientation y advance () en un objeto separado llamado MotionState . Esto es para que pueda construir un árbol de búsqueda de posibles posiciones y orientaciones al hacer algoritmos de búsqueda de ruta. Entonces no quiero llevar conmigo información sobre cómo comportarme cada actualización o cómo debe dibujarse Sprite.