GDD PIÑA MOTOR - PinaYoryi/P32021 GitHub Wiki
ENGINE DOCUMENT DESIGN - PIÑA MOTOR
https://drive.google.com/file/d/1zV0viBBMxYCqXBbTf3ktaWArTQD5mN6m/view?usp=sharing
De momento dejo el link ahí, porque aquí habrá que organizarlo todo y si hay cambios se van a liar
- ESTRUCTURA DEL MOTOR 2
- ENTRADA/SALIDA 2
- TECLADO/RATÓN 2
- LECTURA ARCHIVOS 2
GRÁFICOS 3
ENTIDADES 3
COMPONENTES 3
TRANSFORM 3
UITRANSFORM 4
RIGIDBODY 4
RENDERER 4
COLISIÓN 5
IA 5
CÁMARA 5
TEXTO 5
IMAGEN 5
ANIMACIÓN 5
DROPDOWN 6
BOTÓN 6
SISTEMA DE PARTÍCULAS 6
AUDIO SOURCE 6
AUDIO LISTENER 6
ESCENAS 7
SCENEMANAGER 7
LUA 7
IA 7
TRASLADARSE SIN PATHFINDER 7
ORIENTARSE 7
LOOP 8
START 8
INPUT 8
UPDATE 8
FIXED UPDATE 8
RENDER 8
INTERFAZ 8
FÍSICA 9
BULLET 9
AUDIO 9
FMOD 9
RENDERIZADO 10
OGRE 10
SDL 10
PIPELINE 10
ESTRUCTURA DE ARCHIVOS 11
PATRÓN DE DISEÑO OBSERVER 12
ESTRUCTURA DEL MOTOR Piña Motor es un motor de videojuegos en tres dimensiones multipropósito, que utiliza el motor gráfico de Ogre, el motor físico de Bullet y el motor de audio de FMOD.
ENTRADA/SALIDA TECLADO/RATÓN Detectamos la entrada de tanto teclado como ratón mediante SDL. En el motor existe una clase Input que se encarga de mantener actualizadas las estructuras de teclado y ratón y tiene unos métodos de acceso a estas estructuras para facilitar la comprobación de la entrada: GetXY, donde X es Key o Mouse, e Y es Hold (se mantiene verdadero mientras se pulse la tecla), Down (es verdadero solamente durante el frame en el que se pulsó la tecla) y Up (es verdadero en el frame en el que se suelta). Además, tiene métodos de acceso al movimiento o posición del ratón o girar la rueda del mismo. Existe una única instancia de Input en el motor, utilizando el patrón de Singleton. LECTURA ARCHIVOS Utilizamos LUA para la lectura de los archivos pertenecientes al juego como por ejemplo mapas, audio, etc para posteriormente pasar los datos al núcleo del motor.
GRÁFICOS Usamos los gráficos implementados por el motor Ogre para representar los modelos 3D desarrollados por el equipo, y además para las imágenes.
ENTIDADES Son la unidad de objeto del motor. Tienen una lista de componentes que les dan comportamiento (y un componente forzado: Transform). Tienen métodos de interacción con el loop del juego, que hacen que itere por todos los componentes que tenga añadidos llamando a sus respectivos métodos. La funcionalidad de estas clases viene definida únicamente por los componentes que contienen.
COMPONENTES El motor está estructurado en entidades y componentes. Las entidades son objetos sin función que lo que hacen es llamar a su lista de componentes. Los componentes son clases con funciones que se asignan a las entidades. Tienen una interfaz compuesta por: Start(), Update(), FixedUpdate(), TriggerStart(), TriggerEnd(), TriggerStay(), CollisionStart(), CollisionEnd(), CollisionStay() que son virtuales y visibles al programador, y Render() que es visible solo para el motor. Tienen un puntero a la Entidad a la que pertenecen. Los componentes heredan de una clase base Componente sin funcionalidad que sirve como interfaz para los métodos. No pueden haber dos instancias del mismo componente en una entidad, pero sí dos componentes que heredan uno de otro.
TRANSFORM Se encarga de manejar la posición, rotación y escala de las entidades. Tiene métodos para mover, rotar y escalar. Las entidades comienzan con este componente incluido al crearlas. Tiene un atributo Parent que, si está activo, hace que las coordenadas, orientación y escala sean locales a su Parent. Tiene métodos de Moverse, Rotar, Escalar (local o global de todos), MakeChild(). La posición, rotación y escala son relativos a los atributos del padre de este Transform, de forma que un cambio en el padre cambia al hijo en el sistema de coordenadas global. UITRANSFORM Es un componente exclusivo con Transform que tiene un sistema de coordenadas en dos dimensiones utilizado para incluir entidades en la interfaz de usuario. Tiene también métodos de Moverse(), Rotar(), Escalar(), PonerParent(); pero además tiene atributos (y métodos para editar) de ancla (sobre una posición de la ventana o un rectángulo) que sirve para que se coloque desde ese punto relativo de la pantalla. En caso de ser hijo de otro objeto con UITransform, las coordenadas están respecto al rectángulo que forma su padre. Los atributos tienen como unidades los píxeles de la pantalla o, en caso del ancla, están normalizadas, de forma que (0,0) está en la esquina inferior izquierda. RIGIDBODY La posesión de este componente dicta si se ve afectado por las físicas establecidas o no. Trata, por ejemplo, con velocidades y aceleraciones. Tiene una dependencia con Transform. Tiene método para aplicar fuerzas (con modos para impulso, velocidad instantánea…) que modifica parámetros del transform y propios. Tiene fricción con el aire, masa, un puntero a la fuerza de gravedad, si le afecta la gravedad o si es cinemático. Si es cinemático no le afectan las fuerzas y no se le puede añadir fuerza. Sirve como interfaz para la librería Bullet. RENDERER Se comunica con Ogre y envía al motor gráfico las mallas, texturas y la posición para que este renderice ese objeto en la escena cada frame. Tiene un atributo para la malla que carga, el/los material/es. Actúa como una caja negra para el programador. Tiene métodos para enviar información a Ogre para renderizar. Depende de Transform. COLISIÓN Es una interfaz para el sistema de colisiones de Bullet, que se encarga de manejar las colisiones entre objetos y los métodos desencadenados por ellas. Si una entidad con este componente intersecta con otra con este mismo componente, se hacen llamadas a los métodos de colisión o activador en ambas entidades. Depende de Transform. Tiene atributos para modificar el tamaño del colisionador, modificar el comportamiento físico (trigger o collider). Hay un único componente / varias versiones del componente para las distintas formas de collider (depende de Bullet). IA La tenencia de este componente dota a la entidad de la IA básica del motor. Depende de Transform, Rigidbody. Tiene atributos para la velocidad de rotación, de movimiento, aceleración angular y lineal. CÁMARA Se encarga de mostrar el mundo que se va a renderizar. Depende de Transform. La posición (0,0) de la cámara se corresponde con la posición de abajo a la izquierda de la pantalla. Se puede modificar su viewport y su resolución. TEXTO Renderiza cualquier cadena de caracteres que quieras en la posición que quieras. Forma parte de la interfaz de usuario. Se puede modificar su fuente, tamaño, color tanto de los caracteres como del resaltado y alineación (izquierda, central o derecha). IMAGEN Renderiza una imagen en la posición que se quiera. Se puede modificar su tamaño y posición. Acepta diversos formatos como .png y .jpg. ANIMACIÓN Se encarga de realizar las animaciones que se quiera. Se puede elegir entre elegir entre usar una animación que tiene la entidad de ogre o crear una animación. Se da la opción de transicionar entre diferentes animaciones que previamente se han creado, realizarse en bucle o una sola vez, elegir la animación por defecto y parar de animar. Para crear una animación hay que seleccionar diversos frames claves, el tiempo entre cada frame clave, el transform que se quiere tener y el nombre de la animación. DROPDOWN Depende de Transform y Renderer. Detecta eventos de teclado o ratón y abre una lista con las opciones que contiene, cada elemento es pulsable y al hacerlo, la opción pulsada se mantiene en el dropdown y se cierra la lista. Emite eventos de pulsación al abrir la lista, cerrarla y pulsar una de las opciones de la lista. BOTÓN Forma parte de la interfaz de usuario. Depende de Transform y Renderer. Detecta eventos de teclado o ratón. Una vez pulsado otras otras entidades reaccionan y hacen lo que les corresponde. SISTEMA DE PARTÍCULAS Se da la opción de crear un sistema de partícula a partir de un archivo .particle, para ello hay que darle un nombre al sistema de partículas y el nombre donde coger todos los parámetros. Se puede activar o desactivar. AUDIO SOURCE Carga un archivo de audio y, utilizando FMOD, lo reproduce según diferentes atributos: espacial o global (que se emita desde un punto o se oiga en cualquier lugar), volumen de reproducción, si se loopea el audio… (incluyendo todas las opciones de reproducción que tiene disponible FMOD). Tiene métodos de acceso y modificación de sus atributos, de Play(), Pause(), Stop(), Unpause(). El archivo de audio se mantiene cargado mientras este componente siga cargado. AUDIO LISTENER Utiliza la posición de Transform para averiguar si debe escuchar o no los diferentes sonidos que se crean en sus posiciones. Los sonidos globales los escucha siempre que estén reproduciendo.
ESCENAS Son una lista de entidades con una jerarquía de Padre-Hijo, un mundo físico y una serie de objetos que se encargan de ser una interfaz con el motor, como Input o SceneManager.
SCENEMANAGER Es un objeto, al igual que Input, es un Singleton. Tiene métodos para cargar y descargar escenas. LUA Usamos lenguaje LUA para interpretar los distintos niveles de cada videojuego. Usaremos el intérprete de LUA 5.4.2 para interpretar las escenas codificadas y cargarlas en tiempo de ejecución. El formato de los archivos de escena utiliza el estándar JSON, con objetos JavaScript para representar las entidades de la escena.
IA Codificamos nuestra inteligencia artificial integrada en el motor, para dotar de comportamientos básicos de inteligencia a las entidades mediante componentes que tienen desarrollados dichos comportamientos.
TRASLADARSE SIN PATHFINDER Permite trasladar a la entidad que se quiera de un punto a otro, aunque solo se da la opción de ser en línea recta, sin evitar obstáculos. Dadas las dos posiciones, encuentra el vector dirección y se mueve en dicho sentido a una velocidad. ORIENTARSE Permite orientar a la entidad que se quiera para que mire a un punto concreto. Dada una velocidad máxima de rotación, calcula cuánto ha de girarse y realiza el giro durante el periodo de tiempo apropiado.
LOOP Es el bucle principal que hay en el motor. Input-Fixed Update-Update-Render. Este bucle recorre todas las entidades invocando a sus respectivos métodos con el mismo nombre.
START A este método se le llama la primera vez que se instancia un componente. Cada componente tiene su propio método Start y son independientes entre sí. INPUT Este método es privado para los desarrolladores que utilicen el motor, se encarga de actualizar las estructuras de entrada que proporciona el motor al desarrollador. Se llama una vez en cada frame para detectar si hay input. UPDATE A este método se le llama una vez cada frame a cada entidad de la escena, y estas a cada componente suyo, actualizando sus valores conforme pasa el tiempo y las entidades actúan. FIXED UPDATE Es una actualización que ocurre tras una cierta cantidad de tiempo real fija; lo que implica que puede ocurrir en un rango de cero a varias veces en un frame. Este método es recomendable utilizarlo para actualizaciones físicas, o actualizaciones que ocurran cada cierto tiempo real. RENDER Este método se llama una vez cada frame, y es privado para el desarrollador del motor. Se encarga de hacer llamadas al motor gráfico renderizando todos los objetos de la escena.
INTERFAZ El motor permite crear elementos que existan fuera de la escena, en una interfaz, haciendo que de esta forma se encuentren siempre en la cámara superpuestas a los demás elementos.
FÍSICA Usamos una librería externa de física, que va a tratar los eventos relacionados con aceleraciones, inercias, momentos, detección de colisiones, etc. Usando una librería nos aseguramos de que los cálculos físicos son correctos y están unificados y son compatibles entre sí. Decidimos usar Bullet v3.0.9.
BULLET Bullet es la librería más conveniente para este motor debido a que es efectiva, habiendo sido usada con éxito en grandes proyectos como Blender y es software libre de código abierto que además es relativamente sencillo de implementar.
Ver también: Página oficial
AUDIO La librería externa de audio que da soporte a diferentes extensiones, más de una pista de audio, a cargar, reproducir, pausar y parar el o los audios que están sonando. La librería a usar es FMOD que es la que más nos conviene para este proyecto porque, al igual que Bullet, es software libre y gratuito, que nos facilita la implementación de sonidos en el motor.
FMOD Se utilizará porque reproduce y mezcla sonidos de diversos formatos en varios sistemas operativos. Su licencia permite que el software no destinado a la distribución comercial utilice FMOD de forma gratuita, al igual que Ogre y Bullet, lo cual es conveniente para este proyecto.
Ver también: Página oficial
RENDERIZADO Para el renderizado en pantalla de las entidades y efectos se va a usar una vez más una librería externa. Por motivos similares a los casos anteriores, vamos a usar Ogre por su versatilidad y por ser de uso gratuito en el caso de este proyecto.
OGRE Ogre (es la base del motor, se encarga de la parte gráfica de este) es un motor gráfico en tres dimensiones que permite la integración de otras librerías ajenas a este. A pesar de ser puramente un motor de renderizado, cuenta con características convenientes, como clases propias de vectores y matrices, por ejemplo, manejo de memoria, etc.
SDL Ogre incluye la librería de SDL2, que aparte de ser necesaria para Ogre también se utilizará, por ejemplo, para tratar los inputs del motor.
Ver también: Página oficial
PIPELINE El proceso para la creación e implementación de una historia es la siguiente: Se fragmenta el proyecto a realizar en historias, que se etiquetan en base a sus características (si están relacionadas con Ogre, Bullet… por ejemplo) y a su proyecto (motor, primer juego, segundo juego...) Se puntúa la historia siguiendo el principio de la mayoría simple siguiendo en cierto modo el sistema del scrum póker, pero simplificado por conveniencia (sin usar cartas). Una vez puntuadas se dejan en el Icebox. Los integrantes del grupo se asignan de forma individual o colectiva historias de forma autónoma y llevan a cabo el desarrollo. Una vez terminan, crean una rama nueva para su historia, hacen commit en ella y hacen deliver. El elegido de la asignación de revisiones avisa a dos integrantes para que lleven a cabo esta tarea, uno revisa que el código sigue un estándar establecido y el otro la funcionalidad, y una vez hecho esto se pasa la historia a accept/reject. Si ambas revisiones son válidas, se hace merge a main y se acepta la historia, si se rechaza se intenta arreglar y se revisa de nuevo. En casos excepcionales se podría descartar la historia.
Para el control de versiones utilizaremos Git (GitHub). Para el código usaremos Visual Studio Community 2019. Para la organización y saber las tareas a hacer usaremos PivotalTracker.
ESTRUCTURA DE ARCHIVOS Organización de las carpetas: archivo .gitignore. LICENSE README archivo solución.sln Dependencies Projects: Games Games.vcxproj Games.vcxproj.filters Motor Motor.vcxproj Motor.vcxproj.filters src: Games Games.cpp Games.h Motor Motor.cpp Motor.h
PATRÓN DE DISEÑO OBSERVER El patrón de diseño observer se basa en la “suscripción” de unas entidades que esperan eventos a otras que crean dichos eventos, como un botón. Se implementa mediante métodos que añaden o retiran entidades de una lista que posee la entidad trigger, y cuando esta produce un evento, se lo notifica a todas las suscritas.
La ventaja principal de este sistema es que las entidades son independientes y actúan de forma propia dado un evento que les interesa. En caso de que deje de ser relevante este evento para ellas, dejan de estar en la lista que se recorre en caso de una actualización, por lo que es un patrón eficiente. La mayor desventaja es llevar la cuenta de cuándo hay que dejar de actualizar una entidad que se había suscrito previamente, que puede potencialmente reducir el rendimiento del motor.