SDL - Gráficos encima y debajo

Tratamos sobre el manejo de APIs frecuentemente utilizadas en el desarrollo de videojuegos, como SDL, pygame o SFML.

SDL - Gráficos encima y debajo

Notapor kreezii » Mié Oct 04, 2006 11:06 am

Buenas estoy empezando a programar en SDL (que por cierto es muy sencillo empezar e ir aprendiendo cosas) pero tengo una pequeña duda y es la siguiente: supongamos un juego estilo Final Fight (varios personajes que se mueven por un suelo en todas las direcciones posibles) la cosa es que si un personaje está más abajo que otro éste se tiene que dibujar encima de él ¡lógico!, para dibujar los gráficos hay que llamar a SDL_Blitsurface por orden, es decir, primero cargamos el fondo, y después los personajes, al inicio no hay problema pero cuando se empiecen a mover las posiciones cambiarán, me explico:
Un enemigo se dibuja por debajo del personaje principal pero el personaje principal sube, entonces el enemigo tendría que dibujarse encima ¿cómo hago eso? comprobando la posición y de cada uno de los dos eso sí pero me refiero en el código tengo algo así (pongo pseudocódigo que será más rápido):
Cargo las Imágenes;
Blit_Surface del Fondo;
Blit_surface del enemigo;
Blit_Surface del personaje principal;

De este modo el fondo queda en el fondo ^_^, después se dibuja el enemigo y finalmente el personaje principal estará por encima de todos, pues bien mi pregunta es ¿no hay una función en SDL que pueda indicar que el enemigo se dibuje encima del personaje principal en ciertos momentos?
No sé si me explicado bien, mi problema es que mientras escribo estoy pensando maneras de solucionarlo y se me ocurre una pero lo mismo es una burrada, una función que compruebe la coordenada y del enemigo y del personaje y en función de donde esté hacer un Blit_surface de uno y después de otro pero la cosa es que cuando haya más enemigos será un caos.

En fin... ¿alguien me puede ayudar?, un saludo.
kreezii
 
Mensajes: 1
Registrado: Mié Oct 04, 2006 10:51 am

Re: SDL - Gráficos encima y debajo

Notapor hugoruscitti » Jue Oct 05, 2006 1:10 am

kreezii escribió:No sé si me explicado bien, mi problema es que mientras escribo estoy pensando maneras de solucionarlo y se me ocurre una pero lo mismo es una burrada, una función que compruebe la coordenada y del enemigo y del personaje y en función de donde esté hacer un Blit_surface de uno y después de otro pero la cosa es que cuando haya más enemigos será un caos.


Sí, ha quedado claro. Lo que me temo es que SDL no cuenta con una función que realice lo que necesitas. Dado
que ese requisito es muy propio del juego que buscas conseguir.

Aún así, existen varias formas de lograr este efecto en SDL. Lo que puedes
hacer es almacenar todos tus personajes en una estructura de datos en memoria
como un vector o una lista. De cada personaje puedes almacenar su posición
junto con la superficie que lo representa en pantalla.

Al momento de mostrar los personajes en pantalla puedes comenzar a imprimirlos
siguiendo un orden de profundidad, primero imprimes aquellos que "están mas
alejados de la pantalla" y luego aquellos que "están mas cerca". Una forma de
lograr esto es reordenar todos los elementos de tu estructura justo antes de
comenzar a imprimir (puedes ordenarlos en base al valor de su coordenada "y").
Una vez que están todos ordenados los imprimes.

Aquí te dejo un pequeño ejemplo de ello utilizando objetos en C++, si programas
en otro lenguaje como C será un poco mas complicado de hacer, pero de todas
maneras se le parecerá, consulta nuevamente si quieres.

Una vez que compiles el programa verás en pantalla algo así:

Imagen

los cuadrados de color azul representan a los enemigos del juego (hay que tener
imaginación ...) mientras que el cuadrado blanco representa el personaje
protagonista que se puede mover en pantalla utilizando los direccionales del
teclado. Al mover los cuadrados todos se imprimen "ordenados por profundidad",
como se esperaría de un juego como Final Fight.

A continuación te dejo el código fuente de este programa, ten en cuenta que
las estructuras de datos se manejan mediante STL, una biblioteca que nos
facilita el manejo e implementación de listas, vectores etc...

Código: Seleccionar todo
/*
* Ordenar elementos en pantalla al imprimir
*
* Este programa muestra varios rectángulos en pantalla y simula
* como deberían imprimirse en pantalla si estuvieran sobre un
* plano con profundidad, similar al que se encuentra en videojuegos
* como Final Fight.
*
* Puede encontrar una discusión acerca de este programa en el
* foro:
*    www.losersjuegos.com.ar/foro
*
*/

#include "SDL.h"
#include <list>

/* Representa las características mas elementales
* de un personaje que se debe imprimir en pantalla
*/
class Sprite
{
   public:
      Sprite (int x, int y);
      virtual void actualizar () = 0;
      void imprimir (SDL_Surface * screen);
      int get_y (void);

   protected:
      SDL_Rect rect;
      Uint32 color;
};


/* define la posición y tamaño inicial del sprite */
Sprite :: Sprite (int x, int y)
{
   this->rect = (SDL_Rect) {x, y, 40, 40};
}

/* informa la coodenada "y" en donde se deberían
* encontrar los `pies` de un personaje
*/
int Sprite :: get_y (void)
{
   return this->rect.y + this->rect.h;
}

/* muestra el objeto en pantalla */
void Sprite :: imprimir (SDL_Surface * screen)
{
   SDL_Rect rect = this->rect;   /* nota: se realiza una copia
                  dado que SDL_FillRect puede
                  modificar este rectángulo si
                  no cabe en pantalla */

   /* TODO: utilizar superficies en lugar de rectángulos
    * para que "parezca" un juego */
   SDL_FillRect (screen, & rect, this->color);
}



/* Representa un personaje que se maneja mediante del teclado.
* hereda el comportamiento y estructura de todo Sprite.
*/
class Protagonista : public Sprite
{
   public:
      Protagonista (int x, int y);
      void actualizar ();
};


/* método invocado al crear un nuevo protagonista */
Protagonista :: Protagonista (int x, int y) : Sprite (x, y)
{
   this->color = 0xffffff;
}

/* actualiza la posición del personaje atendiendo la
* pulsación de teclas */
void Protagonista :: actualizar (void)
{
   Uint8 * teclas = SDL_GetKeyState (NULL);
   int velocidad = 2;

   if (teclas [SDLK_UP])
      this->rect.y -= velocidad;
   else
      if (teclas [SDLK_DOWN])
         this->rect.y += velocidad;

   if (teclas [SDLK_LEFT])
      this->rect.x -= velocidad;
   else
      if (teclas [SDLK_RIGHT])
         this->rect.x += velocidad;
}


/* representa un enemigo (¡ un malvado cuadrado azul !)
* que se mueve de izquierda a derecha por la pantalla.
* hereda de Sprite, al igual que el protagonista.
*/
class Enemigo : public Sprite
{
   public:
      Enemigo (int x, int y);
      void actualizar ();
   public:
      int direccion;
};


/* construye al Enemigo asignándole el color azul */
Enemigo :: Enemigo (int x, int y) : Sprite (x, y)
{
   this->color = 0x0000F5;
   this->direccion = 1;
}


/* realiza el movimiento del enemigo en pantalla */
void Enemigo :: actualizar ()
{
   /* el comportamiento de un enemigo es ir de un lado a otro en
    * la pantalla */
   if (direccion == 1)
   {
      this->rect.x ++;

      if (rect.x + rect.w > 320)
         direccion = 0;
   }
   else
   {
      this->rect.x --;

      if (rect.x < 0)
         direccion = 1;
   }

}

/* informa "true" si el primer argumento "a" está mas alejado de la pantalla
* que el argumento "b"
* esta función se utiliza para re-ordenar la lista de personajes (ver
* función main)
*/
bool es_menor (Sprite * a, Sprite * b)
{
   return (a->get_y () < b->get_y ());
}


/*
* programa principal
*/
int main (int argc, char * argv [])
{
   std :: list <Sprite *> sprites;
   SDL_Surface * screen;
   SDL_Event event;
   bool salir = false;

   /* TODO: verificar errores */
   SDL_Init (0);
   screen = SDL_SetVideoMode (320, 240, 16, 0);

   /* Genera los personajes y los almanena en una lista */
   sprites.push_front (new Protagonista (30, 30));
   sprites.push_front (new Enemigo (130, 10));
   sprites.push_front (new Enemigo (220, 50));
   sprites.push_front (new Enemigo (170, 130));


   while (! salir)
   {
      while (SDL_PollEvent (&event))
      {
         if (event.type == SDL_QUIT)
            salir = true;
      }
   
      SDL_FillRect (screen, NULL,
            SDL_MapRGB (screen->format, 200, 200, 200));

      /* actualiza todos los elementos */
      std :: list <Sprite *> :: iterator iter;
      
      for (iter = sprites.begin (); iter != sprites.end (); iter ++)
         (* iter) -> actualizar ();


      /* IMPORTANTE: ordena los personajes antes de imprimirlos
       * llamando a la función "es_menor" para realizar
       * comparaciones */
      sprites.sort (es_menor);


      /* imprime a todos los personajes en pantalla */
      for (iter = sprites.begin (); iter != sprites.end (); iter ++)
         (* iter) -> imprimir (screen);

      SDL_Flip (screen);
      SDL_Delay (1);
   }

   SDL_Quit ();
   return 0;
}


y si archivo Makefile para compilarlo en GNU/Linux:

Código: Seleccionar todo
CC = g++
CXXFLAGS = `sdl-config --cflags`
LDFLAGS = `sdl-config --libs`

ejemplo: ejemplo.o


Saludos.

PD: creo que "Requeteguay" estaba trabajando en una idea similar
a la del juego que buscas hacer, buscalo en este foro, puede que
también te de una mano en tu proyecto.
Avatar de Usuario
hugoruscitti
Site Admin
 
Mensajes: 1242
Registrado: Dom Jul 30, 2006 3:57 am
Ubicación: Buenos Aires, Argentina


Volver a Sobre las bibliotecas multimedia

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados

cron