08 enero 2010

JR to the Rescue

Después de haber realizado el juego Pequepon Adventures, necesitaba pasar el motor a 1024x768 y a 60 fotogramas por segundo, pero no quería tirarme otros 8 meses realizando un juego nuevo. Así que me propuse hacer un videojuego muy pequeño a una sola pantalla y basado en las antiguos videojuegos electrónicos más conocidos como los Game & Watch de Nintendo, a modo de homenaje para recordar como comenzaron las primeras consolas portátiles de videojuegos electrónicos.

Me he basado en concreto en la máquina Donkey Kong JR:

El apartado gráfico lo hemos hecho para que el usuario pueda elegir en las opciones la versión moderna y la clásica:


Esta sería la pantalla de juego en la versión moderna:

Y este sería exactamente igual en modo clásico simulando las pantallas de cuarzo:

El objetivo del juego es guiar al pequeño mono a la parte superior de la pantalla y rescatar a su padre que está encerrado. Para ello hay que saltar (con la barra de ESPACIO o la tecla Z) y coger la llave que liberará un trozo de los 4 que hay en la jaula hasta rescatarlo del todo. Cuando estemos delante de la jaula debemos pulsar la tecla ARRIBA para introducir la llave en la misma. También funciona con el joystick.

EL DESARROLLO DEL JUEGO

No os vayáis a pensar que un juego de estos se hace en dos tardes (eso pensaba yo). He tardado unos tres meses programando a ratos. No os podéis imaginar los quebraderos de cabeza que puede dar intentar reproducir una maquinita de estás. Han salido un total de 4600 líneas de código incluyendo las 1700 del motor 2D con polígonos.

Los recursos utilizados son exactamente igual que para el videojuego anterior: Delphi 7, SDL y OpenGL. Este sería el núcleo del juego donde he cambiado la rutina de temporización para controlar los fotogramas por segundo:

var
iFPS: Integer; // frames por segundo
iTmpInicial: Cardinal; // Tiempo al inicio del bucle
iTmpPrevio, iTmpActual: Integer; // Tiempo previo y actual

{$R *.res}

begin
InicializarSDL('Junior to the Rescue');
CargarOpciones;
ModoVideo(1024, 768, 32, True);
Teclado := TTeclado.Create;
Temporizador := TTemporizador.Create;
Joystick := TJoystick.Create;
Raton := TRaton.Create;
ControlSonido := TControlSonido.Create;
FijarVolumen;
InicializarLogotipo;

iTmpInicial := SDL_GetTicks;
iTmpPrevio := SDL_GetTicks;
iFPS := 0;

while not bSalir do
begin
iTmpActual := SDL_GetTicks;

if iTmpActual - iTmpPrevio > 1000 div 60 then
begin
Teclado.Leer;
Joystick.Leer;
Raton.Leer;
ControlarEventos;
ComenzarRender;
DibujarSprites;
FinalizarRender;
Temporizador.Incrementar;
Inc(iFPS);
if SDL_GetTicks - iTmpInicial >= 1000 then
begin
//SDL_WM_SetCaption(PChar(IntToStr(iFPS)), nil);
iFPS := 0;
iTmpInicial := SDL_GetTicks;
end;

iTmpPrevio := iTmpActual;
end
else
SDL_Delay(1);
end;

DestruirSprites;
FinalizarJuego;
Raton.Free;
Joystick.Free;
ControlSonido.Free;
Temporizador.Free;
Teclado.Free;
FinalizarSDL;
end.

La función que he desactivado es la que me mostraba los fotogramas por segundo en la barra de título cuando jugamos en modo ventana:

SDL_WM_SetCaption(PChar(IntToStr(iFPS)), nil);

Así tengo un control de como funciona en distintos PC y sistemas operativos. Es esta línea la que realmente controla los 60 fotogramas:

if iTmpActual - iTmpPrevio > 1000 div 60 then

Después de procesar 60 los fotogramas por segundo le devuelvo el control a Windows con:

SDL_Delay(1);

De este modo no tenemos que consumir el 100% del procesador como hacen otros juegos casuales que no se complican la vida. Hay que pensar que un juego que consuma mucho procesador más otros programas ejecutándose a la vez como Emule y Bittorrent pueden fundir la batería de un portátil en muy poco tiempo y no hay necesidad de ello.

El motor 2D es exactamente el mismo que utilicé para Pequepon Adventures salvo en lo que respecta a la resolución, donde hay que hacer algunos cambios al inicializar el modo de vídeo:

ModoVideo(1024, 768, 32, True);

Y la función más importante es la que establece el punto de vista en OpenGL:

procedure InicializarOpenGL(iAncho, iAlto: Integer);
var
rRatio: Real;
begin
rRatio := CompToDouble(iAncho) / CompToDouble(iAlto);

// Suavizamos los márgenes de los polígonos
glShadeModel(GL_SMOOTH);

// Ocultamos las caras opuestas
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);

// Ponemos el negro como color de fondo
glClearColor(0, 0, 0, 0);

// Configuramos el zbuffer
glClearDepth(1);

// Establecemos la perspectiva de visión
gluPerspective(60, rRatio, 1.0, 1024.0);

// Habilitamos el mapeado de texturas
glEnable(GL_TEXTURE_2D);

// Activamos el z-buffer
glEnable(GL_DEPTH_TEST);
glDepthMask(TRUE);

// Sólo se dibujarán aquellas caras cuyos vértices se hallen en sentido
// de las agujas del reloj
glFrontFace(GL_CW);

glViewport(0, 0, iAncho, iAlto);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, iAncho, 0, iAlto, -100, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
iUltimaTextura := 0;

// Para el log
iNumTexCre := 0;
iNumTexDes := 0;
iMemoriaVideo := 0;
end;

El resto del motor es exactamente igual que utilicé en los artículos anteriores.

DESCARGA DEL JUEGO

Como es natural en un juego tan pequeño, lo he publicado con licencia Freeware y puede descargarse de estos servidores:

http://www.filefront.com/15309069/Install_JR.exe

http://hotfile.com/dl/23267794/e747a02/Install_JR.exe.html

http://www.mediafire.com/download.php?yzmwzrkzhyy

El más rápido para descargar es HotFile. Esta es la página web oficial:

http://www.divernovagames.com/jrtotherescue.html

CONCLUSIONES

Una cosa que he aprendido en esto de la programación de videojuegos es que hay que comenzar con pequeños proyectos y distintos, de modo que nuestra librería se vaya enriqueciendo poco a poco pero intentando separar el motor 2D puro y la dinámica del juego, para poder reaprovecharlo en futuros proyectos. Mi siguiente objetivo es hacer un juego arcade para poner el motor a tope para ver hasta donde llega.

Pruebas realizadas en Delphi 7.

Publicidad