Hola a todos,
Bienvenidos a este segundo capitulo de como implementar un game engine y no volverte loco del todo en el intento....
Ayer hicimos la base general del proyecto, hoy implementaremos la base del GraphicsManager (o Graphic Engine como querais llamarle).
Estructurando el proyecto
Dado que a cada entrega (al menos ahora en estas primeras) tendremos que ir incluyendo archivos nuevos lo mejor que podemos hacer es estructurar el proyecto. Cada uno a su gusto, yo siempre lo que hago es : una carpeta "scr" donde pongo los .cpp y una carpeta "include" donde pongo los .h y a parte una carpeta "Data" donde pongo las imagenes, sonidos, modelos,etc... Cada uno a su gusto como más le plazca y se sienta más comodo para trabajar.
Una cosa importante es que os acordeis de incluir las rutas de la carpeta de includes en el proyecto, sino no os compilará .Para los que tengais mala memoria o no lo hagais hecho nunca, para incluir al proyecto la carpeta de include es tan sencillo como :
- Desde el VC++ click derecho encima del proyecto.
- Seleccionar propiedades
- En el menú de la izquierda seleccionar C/C++ y en el submenú seleccionar General
- En la primera opción de la derecha "Directorios de inclusión adicionales" poner la ruta de nuestra carpeta include.
- Compilar y comprobar que no da error.
Creando nuestra primera ventana gráfica
Está claro que nuestros juegos se tendrán que desarrollar dentro de una ventana gráfica debido a que, sin anímo de menospreciar la consola de DOS, ésta no es la más adecuada para desarrollar la visualización de nuestros videojuegos.
La creación de la ventana gráfica, por ahora, la realizaremos mediante GLUT. Ya que nos interesa que en cualquier momento podamos quitar GLUT y usar otro sistema para crear las ventanas , estas funcionalidades de pintado las englobaremos en una caja negra que llamaremos GraphicsManager (o Graphics Engine). Este modulo es el que se encargará en el futuro de realizar el pintado por pantalla de nuestras aplicaciones tanto 2D como 3D, así que será un código que estaremos modificando constantemente.
Para instalar GLUT en vuestro ordenador (si no lo teneis instalado) hay numerosas páginas que lo explicarán mucho mejor de lo que yo seria capaz de hacer. Una de ellas es la siguiente http://informatica.uv.es/iiguia/AIG/docs/tutorial.htm. Si no os funciona para vuestro caso concreto googlead un poco y vereis la solución rapidamente.
A fin de unir el código del Core de ayer con el Graphics Manager de hoy los cambios a realizar son mínimos. Os copio el código como quedaria. La parte que hace referencia a GLUT no le hagais mucho caso, miradla si quereis, pero no lo deis más importancia.
Core.h:
Respecto a lo que teniamos el otro dia incluid lo siguiente al final de la definición de la clase
private:
//Funciones del callback de glut
static void glut_idle();
Core.cpp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// Core.cpp : Código del core manager.
/**************************************************************************************************/
#include "Core.h"
#include "MyGL.h" //Includes standar para opengl,glut y compañia
#include "GraphicsManager.h" //Inclusión del motor gráfico
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Instancia única del core manager
Core Core::instance;
//Constructor
Core::Core()
{
}
//Destructor
Core::~Core()
{
}
//Devolvemos el puntero al singleton
Core& Core::singleton()
{
return instance;
}
//Funcion para inicializar el bucle principal
void Core::Init(int* argc, char* argv[])
{
cout << "Inicializamos el Core Manager\n";
//Inicializamos el motor gráfico
GraphicsManager::singleton().Init(argc,argv);
//Asignamos todas las funciones de callback del glut
//a las funciones que definiremos posteriormente
glutIdleFunc(glut_idle);
}
//Funcion para ejecutar el bucle principal
void Core::Run()
{
//Pasamos el control del bucle principal al glut
//que nos gestionara los eventos y llamara a las
//funciones de callback.
glutMainLoop();
}
//Funcion para desinicializar el bucle principal
void Core::DeInit()
{
cout << "Desinicializamos el Core Manager\n";
}
//CALLBACKS DE GLUT
//Esta funcion se llama cuando el sistema no hace nada (por ahora gestionada por glut)
void Core::glut_idle()
{
//Repintamos la escena
glutPostRedisplay();
}
MyGL.h: Este archivo, la verdad, no recuerdo de donde lo saqué, pero es muy práctico para todo el tema de opengl,glut,etc...
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// MyGL.h : Includes para todo el tema de OpenGL
/**************************************************************************************************/
#ifndef __MyGL__
#define __MyGL__
#if defined(__APPLE__)
# include <Carbon/Carbon.h>
# include <OpenGL/OpenGL.h>
# include <GLUT/GLUT.h>
#elif defined(__linux__)
# include <GL/gl.h>
# include <GL/glut.h>
#elif defined(WINDOWS) || defined(_WIN32)
//# include <windows.h> // Header File For Windows//Se ha de quitar este include ya que si no genera errores con la raknet
# include <gl\gl.h> // Header File For The OpenGL32 Library
# include <gl\glu.h> // Header File For The GLu32 Library
# include <gl\glut.h> // Header File For The GLUT Library
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#endif // __MyGL__
GraphicsManager.h (notar que también funciona con singletons como el core)
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// GraphicsManager.h : Código del motor gráfico.
// Caracteristicas especiales: Esta clase implementa un singleton, es decir, solo podrá existir un objeto de esta clase en todo el proyecto
/**************************************************************************************************/
#ifndef __GraphicsManager__
#define __GraphicsManager__
class GraphicsManager
{
private:
// Constructor y destructor de la clase
static GraphicsManager instance;
GraphicsManager();
~GraphicsManager();
public:
static GraphicsManager& singleton();
public:
//Funcion para inicializar el motor de gráficos
void Init(int* argc, char* argv[]);
//Funcion para desinicializar el motor de gráficos
void DeInit();
private:
//Funciones que no se llamarán desde nuestro código sino desde los callbacks de glut (por ahora)
//Funcion para pintar nuestros gráficos
static void Render();
//Función para reescalar los gráficos
static void Reshape();
private:
//Aqui irán los diferentes objetos que complementen el graphicsmanager
};
#endif
GraphicsManager.cpp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// GraphicsManager.cpp : Código del motor gráfico.
/**************************************************************************************************/
#include "GraphicsManager.h"
#include "MyGL.h"
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Instancia única del graphics manager
GraphicsManager GraphicsManager::instance;
//Constructor
GraphicsManager::GraphicsManager()
{
}
//Destructor
GraphicsManager::~GraphicsManager()
{
}
//Devolvemos el puntero al singleton
GraphicsManager& GraphicsManager::singleton()
{
return instance;
}
//Funcion para inicializar el motor gráfico
void GraphicsManager::Init(int* argc, char* argv[])
{
cout << "Inicializamos el Graphics Manager\n";
//Creamos la ventana principal del programa utilizando la libreria GLUT
glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(0, 0);
glutInitWindowSize(640, 340);
int mainWindow = glutCreateWindow("Lord Pakus Engine!!!"); //Viva la originalidad!!! :)
glutSetWindow(mainWindow);
//Asignamos todas las funciones gráficas de callback del glut
//a las funciones que definiremos posteriormente
glutDisplayFunc(Render);
// glutReshapeFunc(Reshape); //Por ahora la dejamos comentada por que no nos hace falta
}
//Funcion para desinicializar el bucle principal
void GraphicsManager::DeInit()
{
cout << "Desinicializamos el Graphics Manager\n";
}
//CALLBACKS DE GLUT, por ahora
//Funcion que se ejecuta automaticamente desde glut (por ahora)
void GraphicsManager::Render()
{
//AQUI IRÁ NUESTRA FUNCIÓN DE PINTADO. Por ahora vacia
}
//Funcion que se ejecuta automaticamente desde glut (por ahora). Por el momento la dejamos comentada por que no nos hace falta
//void GraphicsManager::Reshape()
//{
// //AQUI IRÁ NUESTRA FUNCIÓN DE REESCALADO. Por ahora vacia
//}
Eliminando la consola
Una vez ya tenemos nuestra ventana gráfica funcionando a más de uno de vosotros os sobrará totalmente la consola de DOS. Eliminarla es sencillo. Lo único que teneis que hacer es copiar esta linea...
//Delete console
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
..al inicio del main.cpp, justo debajo de los includes. Esta linea es la que le dirá al compilador que no cree la consola de DOS durante la ejecución de nuestro programa. Si en algún momento os hace falta para tracear o lo que sea, es tan sencillo como comentar la linea y volveréis a tener la consola.
Probando que todo funciona ok
La primera demostración que todo está ok es que os compile a la primera :). Una vez consigáis que os compile, si ejecutáis tendríais que ver algo de este estilo:
Como os dije en el capitulo anterior, por poco lo que parezca que avanzamos, al menos avanzamos. Ya llegará el momento (de aquí a no mucho) a poder ver cosas más impresionantes.
En breve os colgaré el código en un servidor de archivos para que os los podáis bajar directamente y no tengáis que ir haciendo copy-paste.
Nos vemos, hasta el siguiente capítulo