Tutorial de SDL (psEol Project)

Tutorial de Iniciación a las librerías SDL (Simple DirectMedia Layer)




1.-Empezamos
2.-Pintando nuestra pantallita
3.-Acabamos



1.- Empezamos

Bueno, antes que nada para que nos funcione la librería debemos tenerla correctamente instalada. El proceso de instalación es distinto en windows y linux, por lo que no entraré en ello, hay mucha documentación en la página web de SDL http://www.libsdl.org (No obstante si teneís problemas con el Visual C podeís mandarme un mail a sergiocia@ya.com , en linux no las he instalado, pero seguro que encontraís a alguien que sepa :) )


Una vez que tengamos todo instaladito hay que incluir en nuestro programa la definición de las funciones, nada mas sencillo que esto:

#include "SDL.H"


Nota: recordad configurar vuestro compilador para que encuentre el fichero sdl.h

Ahora es necesario inicializar la librería SDL,muy sencillito:


int SDL_Init(Uint32 flags);


En la variable flags podremos decidir los motores que arrancará SDL, motor de video,audio,timers,etc.....


SDL_INIT_TIMER Initializes the timer subsystem.
SDL_INIT_AUDIO Initializes the audio subsystem.
SDL_INIT_VIDEO Initializes the video subsystem.
SDL_INIT_CDROM Initializes the cdrom subsystem.
SDL_INIT_JOYSTICK Initializes the joystick subsystem.
SDL_INIT_EVERYTHING Initialize all of the above.
SDL_INIT_NOPARACHUTE Prevents SDL from catching fatal signals.

Yo lo suelo inicializar así:


int error;

error=SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO);

if(error!=0)
   {
   printf("Fallo al inicializar SDL");
   return -1;
   }


SDL_Init devuelve 0 si no hay error...

Nota: Parece ser que en windows, si no inicializamos el audio, no podemos poner pantalla completa :(

Ahora compilamos y todo perfecto, pero no nos sale nada :(, normal, no hemos creado nuestra ventanita "pa pintar"

Sin meternos en movidas de autodectar ni cosas "avanzadas" :) la manera más sencilla es la siguiente.


SDL_Surface *SDL_SetVideoMode(int ancho, int alto, int bpp, Uint32 flags);



La función SDL_SetVideoMode nos creará una ventanita (o pondrá la pantalla completa) con la resolución ancho x alto y la resolución de pantalla de bpp, en flags debemos de poner las características que tendrá nuestra ventana, las más importantes:

SDL_SWSURFACE , crea la surface(ahora hablaremos de ella) en la memoria del ordenador, no en la memoria de la tarjeta gráfica.

SDL_HWSURFACE, crea la surface en la memoria de la tarjeta gráfica

SDL_HWPALETTE, la paleta estará controlada por hardware.

SDL_DOUBLEBUF, double buffer!!! :) (más adelante, tranquilidad...)

SDL_FULLSCREEN, pues eso, pantalla completa.

SDL_RESIZABLE, podremos cambiar de tamaño la ventana (hay que controlar por nosotros mismos si nos han cambiado el tamaño, y acomodar el programa al nuevo tamaño...)

SDL_NOFRAME, no la he probado nunca (ahora mismo la pruebo)...vale, crea la pantalla sin marco.(obvio :) )




2.-Pintando nuestra pantallita



En fin, una vez creada la ventana/pantalla, pasaremos a hablar de la SDL_Surface. Una Surface es una superficie de dibujo (más o menos), en ellas podremos almacenar todos los gráficos del juego. La más importante es la surface que nos devuleve SDL_SetVideoMode, ya que es el puntero a la memoria gráfica (en cristiano: es un puntero a la pantalla "que se vé").

Una vez que tenemos nuestro flamante puntero a memoria....¿qué hacemos?, pues lo que está de moda en estos tiempos es dibujar en ella :)

Vamos a probar con cosas sencillitas, por ejemplo, rellenar nuestra pantalla de un color.(Me gusta el rojo, así que la vamos a rellenar de rojo :) )

La función con la que podremos realizar este maravilloso efecto es :


int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color);



Donde dst es nuestro puntero la memoria gráfica, dstrect es un puntero a una SDL_Rect (más adelante) y color es.... ejem...el color.


Probad con esta instrucción
SDL_FillRect( MiSurface, NULL, SDL_MapRGB(MiSurface->format,255,0,0)  );



SDL_MapRGB es una función muy útil para elegir los colores de la surface, de momento id modificando los valores R, G y B para alterar el color....en el siguiente hablaremos de ella.


Probad a ejecutarlo y vereís como ....no pasa nada. ¿y eso?, pues porque no hemos actualizado nuestra pantalla.

Se actualiza así:


SDL_UpdateRect(MiSurface,initX,initY,finX,finY);



Donde initX e initY suele ser 0(inicio de la pantalla) y finX,finY suele ser el tamaño de la ventana.

Con esta sencilla instrucción le diremos a nuestro Flamante SDL que actualize nuestra pantalla y !!!!TODO ROJO!!!! !!!!!BIEN!!!!! :) :) :)

No me deís las gracias :)



3.- Acabamos


En fins, para dejar nuestro sistema en un estado aceptable después de ejecutar el programa deberíamos liberar toda la memoria que ha cogido el SDL, simplemente con:

void SDL_Quit(void);


Soltaríamos todo lo que hemos tomado prestado....No olvideís ponerla al final de vuestros programas.


En el próximo episodio....

-SDL_MapRGB a fondo...
-¿Cómo **** pongo un pixel?
-Blittear o no Blittear
-¿Que narices es Blittear?
-Etc...


Stay Tuned!!


pd:esta tarde no podré pasarme por aquí, si teneís alguna duda dejadla por aquí o mandadme un Mensajito Privao...
[oki]

Muuy bueno... en cuando llegue a casa me pongo con ello.

Te importaria que lo pusiera en pseudo??? Con colorines y demás... te abriria una cuenta de colaborador y lo puedes modificar a tu gusto. Así junto los dmeás tutoriales hacemos base de datos.

Ya diras algo... ;)
Gracias Billy! Es mi primer programa usando las SDL!

Para que veas que soy buen alumno, adjunto el codigo que recien escribi con todo lo que explicaste... espero que les sirva a aquellos que quieren verlo funcionando sin escribir na. :)

Solo tendrian que modificar la ruta del include de las sdl, ya que yo puse las de mi linux. :D

salu2[bye]
Simplemente...

GENIAL [looco] [looco] [looco] [looco]

Muchas gracias te lo has currado, ya espero ansioso los demás capítulos. [beer] [beer] [beer] [beer] [beer]
Escrito originalmente por Rurouni


Te importaria que lo pusiera en pseudo??? Con colorines y demás... te abriria una cuenta de colaborador y lo puedes modificar a tu gusto.



Of course, pienso releasear los tutos con licencia GNU Free Documentation License, asín que no problemo. :)


pd: El primer tuto no me gustó mucho, (lo hice en 10 minutos, deprisa y corriendo), en los próximos me esforzaré mucho más :)


Un saludo y gracias por los comentarios. :)
Ok sobre la licencia GNU.

No todos los tutoriales de pseudocodigo.com seran GNU, ya que los autores prefieren exclusividad (el codigo sera GNU, pero articulo en sí no). Que cada uno haga lo que quiera ;)

P.D. a todos los que colaboreis con un tutorial o como sea tendran una cuenta de colaborador para modificarlo a gusto.
SDL_MapRGB a fondo:

Según la resolución de pantalla que hayamos escogido (8,16,24,32), nuestro programa tendrá más o menos variedad de colores para elegir. El modo de 8 bits es "paletizado", lo que significa que tenemos una paleta de colores para elegir, los demás modos son modos "directos", el color que queremos es el color que ponemos.

Intentaré explicarlo mejor:

Modo paletizado (8 bits): Suponed que ANTES de pintar nada en pantalla, teneís que definir los colores con los que vaís a trabajar, teneís un total de 256 colores para definir. Una vez elegidos, podeís pintar en la pantalla usando índices:

- Para el color 0 quiero un rojo pasión
- Para el color 1 quiero un azul celeste
- Para el color 2 quiero un negro chapapote :( !Nunca Más!
- Etc.....

Ahora, al pintar sólo tendrías que decir, pon un pixel en la posicion x=23,y=45 del color 1.

Lo que resultará en un pixel de color azúl celeste.


-Ventajas de éste modo:

-Efectos de paleta en tiempo real: Tenemos una pantalla rellena de azul celeste y queremos ponerla roja pasión (imaginaos que el enemigo os ha matado), sólo tendríamos que cambiar el color en la PALETA, no en los píxeles... es decir, cambiando el indice 1 (azul celeste) por el valor del indice 0 (rojo pasión)

-Rapidez, los fade in y los fade out se hacen en un tris....

-Juguetear con la paleta: ¿os acordaís de las cascadas animadas que aparecían en multitud de juegos? ....un simple efecto de paleta. Se pinta un dibujito con tres colores, y luego se van intercambiando, dando la apariencia de que el agua fluye

-Muchos efectos de demoscene (fuego,etc...) : estaban diseñados para modo paletizado, lo que no significa que no se puedan hacer en otros modos...

-Desventajas de éste modo:

-Intentad mostrar la foto aquella que sacasteís con vuestra nueva cámara digital de 7 MegaPíxeles en 256 colores....Cualquier parecido con la realidad es pura coincidencia.

-Los juegos de hoy en día ya casi ni lo usan, por la complejidad de sus gráficos y fondos. The Curse of Monkey Island no sería lo mismo a 256 colores (aunque el Monkey 2 era la leche con sus 256 colores, y el Monkey 1 usaba en un principio 16 colores. ¡¡¡Quiero ser pirata!!!! )



Resumiendo:

En modo paletizado, el valor del pixel se corresponde con una entrada en un array de colores. El valor del array es el color que se pondrá.


Modo NO paletizado (o color directo):


En éste modo el valor del pixel se corresponde directamente con su color. Si ponemos un pixel con el valor 240, nos aparecerá un pixel con un azul muy parecido al color de las barras de titulo de los programas de windows.

Dependiendo de las bpp escogidas (12,15,16,24 y 32) el valor del color se "empaquetará" en mayor o menor medida (esto no hace falta que lo entendaís por ahora, pensad en que si quereís meter un color en 16 bits, sólo podeís meterlo en 2 bytes, osea que hay que hacer "operaciones de bit" -And,or,etc..etc...- Como estas operaciónes todavía me dan mucha alergia, es mejor que os mireís algún tutorial sobre modos empaquetados.)


-Ventajas de éste modo:

-Muuuchos colores para elegir. Lo que resulta en mayor riqueza gráfica.

-Posibilidad de transparencias.

-Desventajas:

-Más lento que los modos paletizados (Para hacer un fade out hay que repintar TODOS y cada uno de los píxeles)

-Más lento...

-Mmmm, más dificil.




Veamos la definición de SDL_MapRGB:

Uint32 SDL_MapRGB(SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8 b);


fmt es un puntero a un SDL_PixelFormat, que viene a ser el formato que tienen los píxeles.

r,g y b son los valores rgb del color.

Para no liaros, todas y cada una de las SDL_Surface que tengamos tiene su SDL_PixelFormat particular. Por lo que para conseguir un colorcito en nuestra pantalla el código sería el siguiente.


/*Inicializo las SDL y consigo el valor de un color.

   No hay detección de errores.
*/

SDL_Surface *vga; /* Nuestro puntero a la pantalla */

Uint32 colorcito32; /* Almacenaremos nuestro colorcito aquí */

Uint32 colorcito8; /* Otro colorcito */

SDL_Init(SDL_INIT_VIDEO); /* Arrancamos las SDL */

vga=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE); /* Ponemos un modo de 32 bits */

colorcito32=SDL_MapRGB(vga->format,255,0,0,0); /* Consigo el color rojo en esta surface */;


/* Ahora cambio el modo de video a un modo paletizado */


vga=SDL_SetVideoMode(640,480,8,SDL_HWPALLETE); /* Ponemos un modo de 8 bits (paletizado)*/

colorcito8=SDL_MapRGB(vga->format,255,0,0,0); /* Consigo el color rojo en esta surface */;

SDL_Quit(); /* Saliendo..... */

printf("El color rojo en 32 bits es :%d, y en 8 bits:%d\n", colorcito32,colorcito8);



Espero que hayaís entendido el ejemplo.

Resumiendo: SDL_MapRGB() devuelve un Uint32 con el valor del pixel en modos > 8bpp, o el índice del color en modos de 8 bpp.



Poniendo Pixeles

Si hemos entendido y practicado con SDL_MapRGB(), a estas alturas ya somos unos expertos "coloreadores". Sabemos elegir cualquier color, pero no sabemos pintar un mísero pixel. ¡¡Pues ésto se va a acabar!!

Pero antes de nada, un poquito más de teoría :)

Una SDL_Surface sabemos que es nuestro puntero a pantalla y/o gráficos almacenados en memoria. Pero lo que no sabemos es que SDL_Surface es una Struct corriente y moliente. Vamos a ver algunos de sus campos con detenimiento.

typedef struct SDL_Surface {
Uint32 flags; /* Read-only */
SDL_PixelFormat *format; /* Read-only */
int w, h; /* Read-only */
Uint16 pitch; /* Read-only */
void *pixels; /* Read-write */

/* clipping information */
SDL_Rect clip_rect; /* Read-only */

/* Reference count -- used when freeing surface */
int refcount; /* Read-mostly */

/* This structure also contains private fields not shown here */
} SDL_Surface;



flags contiene los modificadores indicados al crear la surface( SDL_HWPALLETE,etc...).

format contiene nuestro SDL_PixelFormat utilizado en SDL_MapRGB y otros.

w,h pues el width y la height de nuestra surface. El tamaño x e y.

clip_rect contiene el clipping de esa surface (por donde se va a pintar, y por dónde no se va a pintar).

refcount ...no nos sirve, es el número de referencias a esa surface que hay pululando por la memoria.

pitch...mmmm más abajo.

pixels aquí tenemos nuestro puntero a memoria. Todo lo que escribamos aquí, se va a ver reflejado en la pantalla. Por lo tanto una función que pinte píxeles, tendrá que irse aquí para pintar. Notesé que si queremos acceder a este array directamente, tenemos que lockear el puntero. Muy sencillo:

if ( SDL_MUSTLOCK(screen) )
{
       if ( SDL_LockSurface(screen) < 0 )
       {
            fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
            return;
       }
}

  /* Hacemos lo que queramos con screen->pixels[] */
 
 

if ( SDL_MUSTLOCK(screen) )
{
        SDL_UnlockSurface(screen);
}
   



No en todos los casos,sistemas operativos,resoluciones,etc tenemos que bloquear la surface, pero es conveniente si queremos código multiplataforma. (En mi caso, en mi casa y en mi ordenador, no necesito lockear la surface o por lo menos no se cuelga :) )

Muy bien, aprendido esto, os voy a presentar una función que escribe píxeles en la pantalla (Cortesía de la documentación de las SDL):

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)

{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}



Como vemos, ésta funcion recibe un puntero a la surface, la coordenada "x", la coordenada "y" y el color. Primero mira a ver que resolucion tiene (recordad : 8,15,16,24,32...) para eso mira en el SDL_PixelFormat de la surface la variable BytesPerPixel.

Después calcula la posición en el array del pixel, es decir, dónde narices tengo que escribir el punto en memoria para que quede en las coordenadas x e y que me han pasado.

un poquito de dibujitos.
Imagen

Con ésto espero que entendaís un poco el funcionamiento de putpixel.

Ya que éstamos, también vamos a ver el getpixel (de nuevo cortesía de la doc) :


Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
   int bpp = surface->format->BytesPerPixel;
   /* Here p is the address to the pixel we want to retrieve */
   Uint8 *p = (Uint8 *) surface->pixels + y * surface->pitch + x * bpp;

   switch (bpp)
   {
      case 1:
         return *p;
      case 2:
         return *(Uint16 *) p;
      case 3:
         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
         else
            return p[0] | p[1] << 8 | p[2] << 16;
      case 4:
         return *(Uint32 *) p;
      default:
         return 0;   /* shouldn't happen, but avoids warnings */
   }
}



Una vez que hayamos entendido ésto. Ya podremos realizar casi cualquier cosa con las SDL, el límite es tu imaginación... :)


Para abrir boca, vamos a intentar crear un campo de estrellas. Es un efecto muy simple, pero nos valdrá para poner en práctica el putpixel y la paleta.

Aquí os dejo el código, no creo que haya muchos problemas en entenderlo. La única función que no hemos visto es esta:

int SDL_SetPalette(SDL_Surface *surface, int flags, SDL_Color *colors, int firstcolor, int ncolors);



Que sirve para poner nuestra propia paleta.
surface es la surface a modificar
flags es para decidir si cambiamos la paleta SW o la paleta HW....lo mejor es modificar las dos, modificar la SW sirve para conseguir efectos de luz y tal. Pero no nos interesa
colors es un array de SDL_Color, osea, la paleta en sí.
firstcolor, ncolors el primer color de la paleta a cambiar (en nuestro caso el 0) y el número de colores a cambiar(en nuestro caso todos)

Hemos creado una paleta formada por un fundido de negro a blanco.Los indices bajos darán un color oscuro, mientras que los índices altos nos darán un blanco polar :)


SDL_Color colors[256]; /* La paleta */

for(i=0;i<255;i++)  /* Apaño una paleta que vaya degradándose */
{
colors[i].r=i;  /* De negro */
colors[i].g=i;  /* a blanco*/
colors[i].b=i;
}


Por cierto SDL_Color es una struct que contiene lo siguiente:

typedef struct{
  Uint8 r;
  Uint8 g;
  Uint8 b;
  Uint8 unused;
} SDL_Color;


Nada nuevo....

Así que, sin precipitarse y sin acritud aquí va nuestro código.

#include <stdio.h>
#include <conio.h>
#include "SDL.H"

#define MAX_STARS 500

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);

struct star_Struct
{
   int x;
   int y;
   int z;
   
};



int main( int argc, char* argv[] )
{
   /*Declaro las variables de nuestro programa */
   
   
   SDL_Surface *vga; /* Como siempre */
   SDL_Color colors[256]; /* La paleta */

   struct  star_Struct stars[MAX_STARS]; /*Nuestro array de estrellitas */

   /* Variables utiles */
   int i;   
   int xpos,ypos;
   int vel=1;
   
SDL_Init(SDL_INIT_VIDEO); /*Arranco las sdl */

vga=SDL_SetVideoMode(640,480,8,SDL_HWPALETTE); /*Pongo modo paletizado */

for(i=0;i<255;i++)  /* Apaño una paleta que vaya degradándose */
{
colors[i].r=i;  /* De negro */
colors[i].g=i;  /* a blanco*/
colors[i].b=i;
}

/* Le digo a SDL, que la Surface vga va a utilzar la paleta que acabo de crear */

SDL_SetPalette(vga, SDL_LOGPAL|SDL_PHYSPAL, colors, 0, 256);

   /* Inicio las estrellas */;

for(i=0;i<MAX_STARS;i++)
{
   stars[i].x=(rand()%640)-320;   /* Valores entre -320 y 320 */
   stars[i].y=(rand()%480)-240;   /* Valores entre -240 y 240 */
   stars[i].z=rand()%256+1;      
}


while(!kbhit() ) /*mientras no toque ninguna tecla */
{
   for( i=0;i<MAX_STARS;i++)
      {
      
         if(stars[i].z>vel)   /*Si puedo restar vel a las z*/
            stars[i].z-=vel;
         else
         {
            stars[i].z=rand()%256+1; /*Si no puedo es que tengo que crear una nueva */
            stars[i].x=(rand()%640)-320;
            stars[i].y=(rand()%480)-240;
         }
         /*Formulita mágica para pasar de 3d a 2d */

         xpos=(256* stars[i].x/stars[i].z)+320;

         ypos=(256* stars[i].y/stars[i].z)+240;
         
         /*Si la posición final se sale de los bordes tengo que crear una nueva */
         if(xpos<0 || xpos> 639 || ypos <0 || ypos >479)
         {
            
            stars[i].x=(rand()%640)-320;
            stars[i].y=(rand()%480)-240;
            stars[i].z=rand()%256+1;
         }
         else
         {   /*Sino,pongo un pixel con el color de la z. A mayor z, más blanco*/
            putpixel(vga,xpos,ypos,stars[i].z);
         }
      

      }
SDL_UpdateRect(vga,0,0,0,0);
SDL_FillRect(vga,NULL,SDL_MapRGB(vga->format,0,0,0) );
   }

         
      
   return 1;
}


void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)

{

   
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
   
    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}



Una captura del experimento:
Imagen

En la siguiente entrega......Bitmaps y amigos... [poraki] [poraki]
[tadoramo] gran billyberjas

Que cacho curso te estas currando. A ver si saco tiempo y hago experimentos con SDL, tomando lo tuyo como base, por supuesto ;)

Si al final lo poneis en pseudocodigo a rurouni le va a venir la mar de bien [oki]

Saludos! [bye]
Pues yo en linux nada de sdl hasta que los drivers de nvidia se lleven bien con estas librerías... cauen to. Hasta para jugar al frozen-bubble tengo que cambiar a los drivers opengl de las X.

salu2
Briareos_H Si q se llevan bien, yo tengo los drivers de nvidia y puedo hacer experimentos con SDL.
Pregunta ( voy oxidado de c) , la funcion kbhit ( q es la q nos dice si han tocado o no una tecla), en q libreria esta definida en linux?

gracias
mmm, en bindows es en el conio.h, pero en linus....... [ayay] [ayay]

si te da problemas el kbhit(), usa while(2), es un bucle infinito, así q tendrás que matar el proceso o cerrar la ventanita o apagar el ordenador, o algo parecido :) :) :) :)
Escrito originalmente por billyberjas
mmm, en bindows es en el conio.h, pero en linus....... [ayay] [ayay]

si te da problemas el kbhit(), usa while(2), es un bucle infinito, así q tendrás que matar el proceso o cerrar la ventanita o apagar el ordenador, o algo parecido :) :) :) :)


lo q queria era encontrar esa libreria q ya no me acuerdo qual era ( desde mi epoca de estudiante en 1 de carrera q no tocaba "c"), la solucion q me das tu ya la habia sacado yo, gracias de todos modos.
pues esa no es (stdlib) , y el apaño ese q me has dicho esta bien , sino fuese pq al cerrar la ventanita.... como q no se lo toma muy bien :P me parece q no descarga de memoria los recursos.


A ver si alguien sabe q libreria es.... SergioX?
Escrito originalmente por escufi
pues esa no es (stdlib) , y el apaño ese q me has dicho esta bien , sino fuese pq al cerrar la ventanita.... como q no se lo toma muy bien :P me parece q no descarga de memoria los recursos.


Cuando lleguemos al capítulo de los eventos.... :) podrás cerrar la ventana [boing] [boing] [comor?] [comor?] [reojillo] [reojillo]
Escrito originalmente por escufi

A ver si alguien sabe q libreria es.... SergioX?


Esa funcion pertenece a conio.h y conio.h es una libreria de borland. Por lo tanto no esta en linux. En linux se usa la libreria ncurses (curses.h) que tiene una finalidad similar.

$man ncurses

salu2
Tutorial 3. Bitmaps, Blitting y tal...



Perdón por el retraso en la aparición de ésta entrega. Pero mi perro se comió los apun..... estooo, bueno, que no he tenido tiempo. :)


Vamos a definir conceptos:

-Bitmap: Mapa de bits, el dibujito, la imagen, el sprite, el héroe,etc. En nuestro caso será una surface corriente y moliente.

-Blitting (o Blitear) : Dicesé del proceso que vuelca el bitmap en una Surface. Debería ser lo más rápido posible para que no vaya a saltos nuestro programa.

-Canal Alpha: Dicesé del cuarto canal que puede haber en una surface (Los otros tres son RGB, Rojo ,Verde y Azul). Con los datos de éste canal podríamos dibujar un bitmap(o sprite, o surface) con transparencia. Ej: Unas gafas para ver tendrían una transparencia total, o casi total (podremos ver los ojos de la persona que las lleva puestas). Pero unas gafas de sol no. El blit con transparencia es uno de los procesos mas costosos... así que, usadlo con precaución :)

-Color Key: No confundir con canal alfa. El color key es el color que NO se dibujará al blitear la surface. Todo el mundo habrá visto que el presentador/a de los informativos es grabado/a sobre un fondo azul. Ese fondo luego se transforma en una bonita imagen con el mapa de tu país y sus solecitos... Nuestro Guybrush es un muñequito pintado sobre un fondo rosado. Ese color rosa no saldrá al pintar al sprite en el fondo. Un blit con color key es más lento que un blit sin color key, pero en casi todos los sprites vamos a tener que utilizarlo...


Imagen


Obviamente, necesitamos cargar algún tipo de gráfico para poder mostrarlo en la pantalla. Para ello lo mejor es usar la función SDL_LoadBMP:
SDL_Surface *SDL_LoadBMP(const char *file);


Esta función nos devuelve un puntero a la surface, y acepta un char * con la ruta del fichero.

Ej:

SDL_Surface *imagen1;

imagen1=SDL_LoadBMP("prueba.bmp");

   if(imagen1==NULL)
   {
   printf("la cagamos al abrir\n");
   return -1;
   }
   else
   {
   printf("Fichero cargado sin problemas");
   }


Nota: hay librerías específicas para cargar otros tipos de formatos (png,jpeg,etc...), SDL sólo soporta BMP, pero como ésto es un tutorial de SDL.... os buscaís la vida. http://www.libsdl.org

Una vez tengamos nuestro sprite en memoria, podremos volcarlo a la surface principal con SDL_BlitSurface. Su definición es la siguiente:

int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);


De momento no nos vamos a preocupar por las SDL_Rect, más adelante las explico. Para poder ver vuestro pedazo de bitmap en pantalla, no teneís más que hacer.


SDL_BlitSurface(imagen1,NULL,vga,NULL); /* Bliteo la imagen */

SDL_UpdateRect(vga,0,0,0,0); /* Actualizo la pantalla */



vga se supone el puntero a nuestra memoria gráfica, (El que nos dá SDL_SetVideoMode() )

En éste ejemplo, ponemos nuestro sprite en la posicion 0,0 de nuestra ventanita. Para modificar ésta posición no nos vá a quedar más remedio que explicar las SDL_Rect. Prestad atención que no lo pienso repetir:

Nota: Traducido de la doc

[B]Nombre[/B]

[I]SDL_Rect [/I] -- Define un área rectangular

[B]Definición de la estructura[/B]


typedef struct{
  Sint16 x, y;
  Uint16 w, h;
} SDL_Rect;


[B]Datos de la estructura[/B]

x, y Posición de la coordenada superior izquierda del rectángulo.
w, h El ancho (w) y el alto(h) del rectángulo.


[B]Descripción[/B]
Una SDL_Rect define un área rectangular de pixels. Es usado por SDL_BlitSurface para definir regiones de blitting y por varias funciones de video.



Con lo que vemos que SDL_Rect es una struct que tiene la posición x e y, y el ancho y alto de un rectángulo ficticio.

Para colocar el sprite anterior en el punto x=150, y=50 usaremos una SDL_Rect


SDL_Rect rectadestino;

rectadestino.x=150;
rectadestino.y=50;

SDL_BlitSurface(imagen1,NULL,vga,&rectadestino);

SDL_UpdateRect(vga,0,0,0,0);



Como vimos en SDL_BlitSurface:

int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);


srcrect es la SDL_Rect que definirá DE DONDE vamos a coger los píxeles para pintar.

dstrect es la SDL_Rect que definirá A DONDE vamos a pintar.

Nada mejor que un ejemplo:

Imagen


Color Keys y tal


Para seleccionar nuestro key color (el color que no se va a pintar en los blit) usamos SDL_SetColorKey



int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key);



Donde Surface es la surface a la que vamos a aplicar el color.

Flag Puede ser:

SDL_SRCCOLORKEY y/o SDL_RLEACCEL

SDL_SRCCOLORKEY : Se lo pasamos a la función para indicar que queremos poner el color key. No hay más explicación

SDL_RLEACCEL : Activa la aceleración RLE para los blit, es útil si tenemos una imagen con muchas lineas horizontales del mismo color, este flag puede acelerar su blit. Si teneís alguna duda de ésto, por 10 Euros os la soluciono en mi Hot-Line :)

Imaginemos nuestro bichejo:

Imagen


Obviamente, el color key será el rosado. Y ésta imagen si podría ser acelerada con RLE, (fijaos en la cantidad de línea rosadas )

para seleccionar el colorkey:


SDL_SetColorKey(imagen1,SDL_SRCCOLORKEY | SDL_RLEACCEL,SDL_MapRGB(imagen1->format,255,255,255) );



Obviamente, hemos instruído a nuestro grafista para que el color RGB 255,255,255 sea el que siempre use para los color key. O se podría hacer que el primer pixel de los sprites fuese siempre dibujado con el color key, o se podría.......etc.

Canal Alpha o cómo hacer transparentes a nuestros muñecotes.


Sencillo:


int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha);



Surface la surface a "Alphear" :)

Flag parecido a SDL_SetColorKey

SDL_SRCALPHA : Se lo pasamos a la función para indicar que queremos un canal alpha para ésta surface

SDL_RLEACCEL : Activa la aceleración RLE para los blit.

alpha un entero (de 0 a 255) que define el grado de transparencia. Como puede cambiar de versión en version, (0 puede ser transparente en ésta versión, pero en la siguiente puede ser opaco), lo mejor es usar los define que SDL trae :
SDL_ALPHA_TRANSPARENT y SDL_ALPHA_OPAQUE. Hay un caso especial, que es el 128, (medio transparente, medio opaco) que va más acelerado que los demás.

Esta operación es costosa, así que usadla con cautela. Y también echad un vistazo a la documentación de ésta función, os puede sacar de problemas :)


DisplayFormat, o cómo acelerar las cosas

SDL es una librería fácil de utilizar y muy Permisiva. Ésto significa que podremos blitear una surface de 8 bits en una surface de 32 bits, o al revés.

Naturalmente, éste es un proceso que requiere una conversión de formatos CADA VEZ que se ejecuta un blit. Por ello , lo ideal es utilizar siempre surfaces del MISMO tipo.

Para asegurarnos de que TODAS las surfaces que bliteamos son del mismo tipo que la surface principal(la pantalla), lo mejor es utilizar éstas funciones:


SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface);

SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface);



Cuyo uso resulta obvio:


SDL_Surface *imagenmala,imagenbuena;

imagenmala=SDL_LoadBMP("prueba.bmp");

imagenbuena=SDL_DisplayFormat(imagenmala);

;

Con éstas sencillas líneas, tendríamos imagenbuena lista para hacer "fast blit" a la pantalla. Antes de convertir la surface, deberíamos darle los valores de color key y cana alpha. Si usamos un canal alpha, la función a la que tendremos que llamar para convertirla es SDL_DisplayFormatAlpha



Y con ésto ya podremos trastear un poquillo con el SDL, en la próxima entrega veremos los eventos. Muy útiles para que el héroe se mueva a nuestra voluntad.

Si quereís hacer un ejercicio, podeís probar con un sprite que se mueva por un fondo, el sprite debe tener color key y transparencia. :) Mandad un mensaje al 5505 con la palabra SDL y entraréis en un sorteo de.... :)

pd: Si alguien tiene dudas de esto, puede mandarme un MP.
Venga, saludos.
Muy bien!!!

^__^x te lo estas currando mucho.

En breve tendras una seccióncita en pseudo... solo falta escoger que cable cortar: el rojo o el azul... SOLO QUEDAN 10 SEGUNDOS!!!






bum.



Hasta mañana...
Escrito originalmente por Rurouni
solo falta escoger que cable cortar: el rojo o el azul...



ein?


cada día tas mas tonto.... [burla2]
cada día tas mas tonto....

:-|
Configuración de las SDL bajo Windows y Visual C++ 6.0.


Aunque muchos de vosotros no os habeís quejado, sé de buena tinta que a muchos no os funcionan bien vuestras pruebas de SDL bajo windows. Para remediar la situación, me veo obligado (¿?¿?) a crear un pequeño anexo al tutorial de SDL para vosotros, amigos, que veís impotentes cómo vuestro flamante Visual C++ 6.0 (con vuestra flamante licencia, espero :) ) os insulta y os grita que le faltan librerías, que encuentra el SDL_Main, que no le vé sentido a la vida,etc...

Para resolver todos esos problemas, lo más sencillo es seguir los siguientes pasos:


1.- Crear un nuevo proyecto del tipo "Win32 Console Application".
2.- Crearlo vacío(Empty WorkSpace). No nos hace falta nada,gracias.
3.- Irnos a Project/Settings.
Pestaña C/C++: Categoría-> Code Generation Elegir la librería run time "Multithreaded DLL"
Pestaña C/C++: Categoría-> Preprocessor En Additional Include Directories añadir el directorio de SDL/Include
4.- Añadir al proyecto los ficheros :SDL.LIB y SDLmain.LIB

5.- Crearnos nuestro archivo main.c y copiar en él lo siguiente:
        #include "SDL.H"
       
        int main( int argc, char* argv[] ) {  }


El int main vá a ser a partir de ahora nuestra función de inicio. No jugueteís mucho con los parámetros ni con el retorno, que entonces os dará un error al linkar.

6.- Pogramar!!!!!!! :)


Nota: Si al ejecutar el programa os salta un error de que no encuentra el archivo Sdl.Dll, es porque no lo teneís en el path, lo más util es meterlo la carpeta raíz del proyecto, o bien meterlo a capón en Windows\system


Un saludo, y si alguien se anima a crear otro anexo para otros compiladores (Borland, DevC++...) y otros S.O's pues que se ponga en contacto conmigo.
Bueno, primero felicitarte por el tutorial... y quien haya leido ya mi mensaje, pues mala suerte... :P

Como compilar con Dev-C++ (probado con la version 4)

1º.Bajamos las librerias para Dev-C++ desde... [URL=http://www.libsdl.org/release/SDL-devel-1.2.5a-mingw32.tar.gz]
SDL-devel-1.2.5a-mingw32.tar.gz[/URL]

Como veis, es un fichero .tar.gz, podeis descomprimirlo con el ultimo WinRAR por ejemplo. Debereis extraer todo su contenido hasta que llegueis al SDK (varios ficheros de texto/HTML), ahí, encontrareis otro fichero comprimido en formato .tar (o .gz), ese es el que nos interesa, extraerlo donde más rabia os de... dentro de esa carpeta, encontrareis otras carpetas (lib, bin, include,...), bien, copiarlas todas con el raton, y pegarlas sobre sus homonimas en el directorio de Dev-C++... os dira que estos directorios ya existen... no os preocupeis, no sobreescribireis nada viejo, salvo que ya tuvieseis algún SDL instalado... ya estamos casi listos.


2º: La libreria SDL.dll, que es la que hace funcionar los ejecutables... copiarlas en las siguientes direcciones:

Windows 9x: ?:\Windows\system
Windows NT/2k/XP: ?:\Windows\system32

Ahora vamos a generar un proyecto para SDL.

3º. Creamos un nuevo proyecto en Dev-C++ de tipo "consola" (si no sabes hacer esto... mejor no sigas leyendo :P)

4º. Una vez creado, nos dirigimos a las opciones del proyecto: Project->Options. Aquí, buscaremos la opcion "Further object files or linker options", donde escribiremos lo que sigue -lmingw32 -lSDLmain -lSDL -mwindows , d eno escribir esto, dará siempre error.


Tras esto, pues compilaremos normalmente y pa'lante ;)


NOTAS IMPORTANTES!!!

1º: La función MAIN ha de ser siempre como sigue:

#include

int main (int argc, char *argv[])
{
...
...
}


si no la escribis así, obtendreis un error de linkado continuamente...

2º:Cuando useis la orden printf("..."); la salida se genera en un fichero de texto llamado stdout.txt en vez de en la pantalla...

Usuarios de ATi HydraVision FX: Desactivar las funciones de control de ventanas en las propiedades de Hydravision, si no lo haceis, podeis obtener resultados inesperados al ejecutar los programas, como ver solo unas pocos pixeles y no poder ver completa la ventana... esto solo ocurre en modo ventana, no así en full screen.

Salu2
Bien... ahora aprendereis como tener listo un proyecto para SDL con un solo clic de raton, gracias a las plantillas para proyectos que nos proporciona Dev-C++

Por cierto, podreís poner lo que queraís, son simplemente ejemplos.

Por pasos...

1º: Entramos normalmente a Dev-C++

2º: Nos dirigimos a File->New Template.

3º: Pestaña Template->Template Information

3.1: Name: SDL Project Windows
3.2: Description: SDL Base Project
3.3: Category: SDL
3.4: Icon Filename: Podeis poner el que querais, o dejarlo en blanco


4º: Pestaña Template->Project Type
4.1: is C++ Application: Activado
4.2: Is Console (DOS-Box) Application: Desactivado
4.3: DLL: Desactivado


5º: Project Information
5.1: Default Poject Name: Project SDL
5.2: Extra Object Files or Linker Parameters: -lmingw32 -lSDLmain -lSDL -mwindows
5.3: Extra Compiler Options & Extra Include Directories: Nada de nada


6º: Pestaña C++, copiaremos el siguiente texto, basicamente es el código de Sergiox, con dos lineas extra de comentarios, no serivirá como inicialización básica de las librerias gráficas de SDL:

#include "SDL.h"

int main (int argc, char *argv[])
{

int error,i,x;
SDL_Surface* MiSurface=NULL;

error=SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO);

if(error!=0)
{
printf("Fallo al inicializar SDL");
SDL_Quit();
return -1;
}

MiSurface=SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);

//Codigo ejemplo
for(i=0; i<1000; i++)
{
SDL_FillRect( MiSurface, NULL, SDL_MapRGB(MiSurface->format,(i),(i*2),(i*5) ) );
SDL_UpdateRect(MiSurface,0,0,640,480);
}
//Fin Codigo Ejemplo


SDL_Quit();
return -1;
}




7º: Pulsaremos sobre el icono Save, introduciremos el nombre que más nos apetezca, ya que no tiene importancia real. A partir de este momento, cada vez que creemos un nuevo proyecto, aparecera una nueva categoría de proyecto llamada SDL, donde aparecerá nuestro nuevo tipo de proyecto: "SDL Windows".


Salu2
Eventos, qué son y cómo se usan.


Bienvenidos a un nuevo tutorial billyberjas(C), éste capítulo trata sobre los eventos en SDL. Perdonad el retraso en las entregas, pero tenía muchos eventos pendientes en cola....(después de leer el tutorial, entedereís el chiste :P )

Muchos de vostros estareís acostumbrados a la programación lineal (en otros círculos conocida como, "Programación por mis Coj*n*s" :) ), es decir, mi programa comienza, pide una serie de datos al usuario, y muestra un resultado. Éstos programas son muy típicos al iniciarse en el fascinante mundo de la programación. Vamos a ver un ejemplo:


#include <stdio.h>

void main(void)
{
int a,b,suma;

printf("Introduce dos enteros (separados por comas):"); //imprimo comentario

scanf( "%d,%d" ,&a, &b); //recibo los numeros

suma=a+b; //los sumo

printf("\n La suma de los numeritos es :%d ", suma); //muestro resultado

printf("\n\nGracias por confiar en nosotros "); //Comentario de Salida

}// fin del main




Con éste sencillo programa vemos uno de los fundamentos principales de la programación "por mis Coj*n*es", el usuario del programa sigue NUESTRO camino. El programa no admite mostrar la suma antes de pedir los numeros, ni admite mostrar el comentario de salida antes de mostrar el de entrada, tampoco admite hacer otra cosa que sea introducir dos números separados por comas. Es decir, el usuario está limitado a hacer lo que nostros hayamos pensado.


Ahora imaginaos una típica ventanita de cualquier programa, tiene un botón de cerrar, maximizar, minimizar, un par de campos de texto (para introducir valores), un botón de aceptar, otro de cancelar,etc...

El usuario puede hacer lo que le plazca, en el ORDEN que le plazca. Nada le impide minimizar la ventana, irse a otro programa, volver al nuestro, maximizar la ventana, introducir un valor, equivocarse, borrarlo, volver a introducirlo...y luego pensárselo mejor y darle al botón de cancelar.

Ésto es la llamada programación ORIENTADA A EVENTOS, cuya filosofía es radicalmente distinta a la programación "por mis Coj*n*s" ;-), en vez de decir por dónde va a ir el usuario, y programar ése camino, tendremos que programar TODOS los posibles caminos que el usuario pueda tomar (minimizar,cancelar,etc...), pero no os preocupéis que no es tán difícil como parece, e incluso podremos continuar con nuestra programación lineal con ligeros cambios.

"Muy bien"-Pensareís-" Ahora tengo que programar orientado a eventos, ¿qué narices es un evento? ¿es lo mismo que la programación orientada a objetos? porque yo el Java lo llevo muy mal...."

Calma y tranquilidad, la programación orientada a eventos NO ES LO MISMO que la programación orientada a objetos. Así que podeís respirar tranquilos, que no muerde :).

Podríamos definir un evento como cualquier cosa que requiera nuestra atención, en un entorno visual, podría recibir nuestra atención un movimiento de ratón, una pulsación de teclado, un aviso del Sistema Operativo (me he colgado, voy a cerrar el sistema, etc....) o incluso un evento predefinido por el programador.


Para ello, el Sistema Operativo nos facilitará la tarea de conseguir los eventos, el SO és el que nos va a proporcionar los eventos. Cuando nuestro usuario pase su recién estrenado ratón óptico por nuestra preciosa ventana, el SO nos va a lanzar cienes y cienes de eventos, más concretamente, un evento por cada movimiento que haga. Éste evento se compondrá del tipo de evento:"Movimiento de ratón sobre tu ventana" y de unos parámetros variables (en el caso del ratón, las coordenadas X e Y del puntero).

Obviamente, no necesitamos tratar todos los eventos, (un juego que funcione con el ratón no necesita preocuparse por el teclado, salvo para usar cheats :) ), si un evento no lo vamos a tratar, se lo devolvemos al Sistema Operativo, y nos quedamos tan anchos. Si le devolvemos el evento, significa que el SO tiene que tratar el evento por nostros, así que él SO hará lo que mejor le parezca.

Obviamente, nuestro programa necesitará una cierta remodelación en todo lo referido a la entrada de datos por parte del usuario (teclado,ratón,etc...), ya no vamos a parar nuestro programa hasta que nuestro usuario escriba "OK", sino que vamos a entrar en un bucle donde trataremos los eventos que nos interesan. Vamos a ver un ejemplo, que me parece a mí que os estaís liando :


Imaginaos típico programa visual (con ventanitas,checkboxes y tal) que necesita dos archivos para funcionar, uno de entrada y otro de salida. Tendríamos algo así como ésto.

Imagen

Una programación lineal tradicional obligaría al usuario a introducir primero el archivo de entrada, y después el archivo de salida. La programación orientada a eventos deja esa decisión en manos del usuario. ¿Quien nos dice que primero va a seleccionar el archivo de salida? ¿Y el de entrada? ¿Puede el usuario introducir a mano la ruta y el nombre del archivo? ¿O puede usar el botón examinar? Tódo esto tendríamos que controlarlo. Pero no os preocupeís porque en muchos casos va a ser incluso más sencillo que la programación lineal :).

En éste ejemplo en concreto tendríamos que tratar el evento "Hago click en el primer botón Examinar", "Hago click en el segundo botón examinar", "Hago click en Aceptar" y "Hago click en cancelar".

En los dos primeros eventos, lanzaríamos un cuadro de selección de fichero, una vez seleccionado y comprobado que és valido, introduciríamos en la Caja de Texto (TextBox) el nombre y la ruta del fichero.

Para el botón cancelar tendríamos que cerrar la ventana, o mostrar un mensaje de "¿Estás seguro?" y continuar con el flujo normal de nuestro programa.

Para el botón aceptar, simplemente tendríamos que comprobar que hay texto en las textbox (recordemos que lo puede haber introducido a mano, o con el botón de examinar), comprobar que es un fichero, que existe y que nos vale. Entonces ya podríamos hacer lo que quisieramos con los ficheros.

Pero cuidado, el usario también puede querer maximizar la ventana, cerrar el sistema operativo, pasar a otra tarea, etc... ¿Pero esos eventos ni siquiera están codificados en nuestro programa? ¿Que pasaría entonces? , pues simplemente, el Sistema Operativo se haría cargo de ellos. Así de sencillo. :)


Después de ésta ¿pequeña? introducción a los eventos, vamos al tema que nos ocupa, SDL y sus eventos.


Antes de empezar, deciros que SDL va a ser el que se peleé con el SO y sus eventos específicos, a nostros siempre nos van a llegar eventos de SDL, ésto facilita mucho las cosas a la hora de hacer nuestro programa/juego multiplataforma, pues los eventos van a ser los mismos. Así que ya no hay excusa para portar tu pedazo de juego a linux, seguro que muchos usuarios te lo agradecerán :).

En primer luegar, deciros que el sistema de eventos se inicializa llamando a SDL_Init(SDL_INIT_VIDEO);, es decir, que al inicilizar el subsistema de vídeo de SDL, también inicializamos el sistema de eventos.

SDL tratará los eventos que le lleguen del SO metiéndolos en una cola, y gurdándolos hasta que nosotros le pidamos que nos los dé. La estructura en la que SDL nos informará del evento que nos llega es SDL_Event ( lógico,¿no?).

typedef union{
  Uint8 type; //tipo de evento
  SDL_ActiveEvent active; //evento de activación (de ventana,foco,etc...)
  SDL_KeyboardEvent key; //evento de teclado (tecla pulsada, tecla soltada,etc...)
  SDL_MouseMotionEvent motion; // evento de movimiento de ratón
  SDL_MouseButtonEvent button; // evento de pulsación de botones de raton
  SDL_JoyAxisEvent jaxis; // evento de movimiento del joystick
  SDL_JoyBallEvent jball; // evento de movimiento del ¿trackball? del joystick
  SDL_JoyHatEvent jhat;  //evento de pulsación de los ¿hats? del joystick
  SDL_JoyButtonEvent jbutton; //evento de pulsación de los botones del joystick
  SDL_ResizeEvent resize; // evento de redefinición de tamaño de la aplicación (resize)
  SDL_ExposeEvent expose; // evento de exposición de ventana ( alguna ventana se ha puesto encima de nosotros)
  SDL_QuitEvent quit; // evento de .... salida...pues claro...;)
  SDL_UserEvent user; //evento de usuario, éstos los lanzamos nosotros, ¿como mola,eh ? XD
  SDL_SywWMEvent syswm; //evento del manejador de Ventanas ( nos pelearemos nostros mismos con los eventos de nuestro SO)
} SDL_Event;


-Un momento!!, ¿no habías dicho que era una estructura ? , ¡¡¡Eso que me has puesto es una unión!!!

- Yepes ;), una unión de estructuras, para ahorrar memoria, y facilitar la programación, ahora lo veremos....:)


Cuando nos llegué una unión de SDL_Event, lo primero que haremos será comprobar su tipo. Una vez que sepamos de qué tipo és. Sólamente tendremos que utilizar la estructura adecuada para comprobar sus datos. Aquí van los tipos y luego veremos un ejemplo.

SDL_ACTIVEEVENT SDL_ActiveEvent
SDL_KEYDOWN/UP SDL_KeyboardEvent
SDL_MOUSEMOTION SDL_MouseMotionEvent
SDL_MOUSEBUTTONDOWN/UP SDL_MouseButtonEvent
SDL_JOYAXISMOTION SDL_JoyAxisEvent
SDL_JOYBALLMOTION SDL_JoyBallEvent
SDL_JOYHATMOTION SDL_JoyHatEvent
SDL_JOYBUTTONDOWN/UP SDL_JoyButtonEvent
SDL_QUIT SDL_QuitEvent
SDL_SYSWMEVENT SDL_SysWMEvent
SDL_VIDEORESIZE SDL_ResizeEvent
SDL_VIDEOEXPOSE SDL_ExposeEvent
SDL_USEREVENT SDL_UserEvent

El ejemplo:

Imaginaos que tenemos un bucle que lo único que hace es esperar a que haya eventos, y si hay uno, tratarlo.


SDL_Event evento;
int salir=0;


while(!salir) //mientras que no tenga que salir del programa
{
        while(dame_evento(&evento)!=0)  //mientras que haya un evento en la cola pendiente para ser procesado.
       
        {
       
                switch(evento.type) //miramos de que típo es el evento que nos ha llegado
               
                {
               
                case SDL_SDL_MOUSEMOTION: // es un evento de ratón, en concreto un evento de movimiento
                                          //, oseasé un SDL_MouseMotionEvent, definido en la unión SDL_Event                                                        // como [I]motion[/I]
                      printf("Estás moviendo el ratón en las coordenadas x:%d,y:%d\n",evento.motion.x,evento.motion.y);
                     
                      break; //salimos del case MOUSEMOTION
               
                case SDL_QUIT: //nos llega un evento de salir del programa, por lo que saldremos del programa
               
                      salir=1;
                       
                      break;
                     
                default:
                       
                      printf("no sé que evento és....\n");
                     
                      break;
               
                } //fin del switch
                                   
                     
               
        } //fin del while (evento)
       
//si ésto fuera un programa normal, podríamos hacer cosas mientras no haya eventos pendientes :)
       
} //fin del while(!salir)

printf("Programa terminado\n");



Las variables del evento SDL_MOUSEMOTION las he sacado de la documentación de las SDL.

Ahora veamos cúales son las funciones para obtener eventos de la cola de SDL.

La más importante (y la que se suele utilizar más a menudo) es:

int SDL_PollEvent(SDL_Event *event);

Devuelve 0 si no hay eventos en la cola.

Si hay eventos en la cola devolverá 1, y además rellenará el puntero a SDL_Event que le hemos pasado.

Ésta función es muy útil si la utilizamos dentro de un bucle (como en el ejemplo)

Más funciones

int SDL_WaitEvent(SDL_Event *event);

Ésta función espera INDEFINIDAMENTE a que ocurra un evento (de cualquier tipo) y rellena el puntero que le hemos pasado.

Devuelve 0 si ha habido un error en la espera, o 1 si ha devuelto algo.

int SDL_PushEvent(SDL_Event *event);

Con ésta función podremos "empotrar" nuestros propios eventos en la cola,simplemente nos creamos un evento, rellenamos sus datos y llamamos a ésta función. Puede sernos útil para hacer demos (vamos metiendo las pulsaciónes del teclado, y nuestro programa las interpretará como pulsaciones reales), o para otras cosas que no quiero ni sé contaros :)

int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action, Uint32 mask);

Ésta función no la vamos a tocar, puesto que es relativamente complicada, y tampoco nos va a servir de mucho de momento. Comentaros simplemente que es una función de propósito general, que sirve para dar altas,bajas y consultas XD en la cola de eventos. También podemos pedir que nos dé los eventos que cumplan una determinada condición. Mas info en la Documentación.

void SDL_PumpEvents(void);

Ésta función "actualizará" nuestra cola de eventos, es decir que pedirá al SO los nuevos eventos que hayan podido ocurrir, puede sernos útil cuando empezemos a hacer "virguerías" con el SDL. Digamos que es un fflush() de eventos. Nota: Las únicas funciones que llaman implícitamente a SDL_PumpEvents() son SDL_PollEvent y SDL_WaitEvent por lo que si vamos a utilizar las demás funciones relativas a eventos, tenemos que recordar llamar a SDL_PumpEvents para que tengamos eventos en la cola!!


Hay varias funciones relacionadas con eventos que no voy a explicar, porque sería muy aburrido y no son indispensables para un correcto funcionamiento de nuestro aplicativo :). Y como lo mejor es predicar con el ejemplo, vamos a intentar hacer algo un poco decente, mover un muñequito por la pantalla, uno de los máximos deseos de cualquier programador serio ;).

Lo vamos a hacer de dos maneras, la tradicional con eventos llamando a SDL_PollEvent, y la "commando", actualizando nostros mismos los eventos con SDL_PumpEvents y usuando funciones avanzadas de SDL.


Tradicional



int heroex,heroey;
int salir=0;
SDL_Event evento;

while(!salir) //mientras no haya que salir
{

        while(SDL_PollEvent(&evento)!=0) //mientras haya algún evento en la cola
        {
       
        switch (evento.type)
                {
               
                case SDL_KEYDOWN: //entramos jústo donde queremos, cuando pulsen una tecla.
               
                        //entramos en otro switch para saber qué tecla hemos pulsado (buscad en la doc las keysims)
                       
                        switch(evento.key.keysym.sym)
                       
                                {
                               
                                case SDLK_LEFT: //ha pulsado el cursor izquierdo
                                       
                                        heroex--;
                                        break;
                                       
                                case SDLK_RIGHT: //ha pulsado el cursor derecho
                               
                                        heroex++;
                                        break;
                               
                                case SDLK_UP: //arriba
                               
                                        heroey--;
                                        break;
                               
                                case SDLK_DOWN: //abajo
                               
                                        heroey++;
                                        break;     
                                                                           
                                case SDLK_ESC: //ha pulsado la tecla ESCAPE .... ¿Por qué? ¿No le gusta? ;)
                                       
                                        salir=1;
                                        break;
                                 } //fin del switch de los keysyms
                                 
                        break; //fin del case SDL_KEYDOWN
                       
                 case SDL_QUIT: //si es un evento de salida
                               
                                salir=1;
                               
                                break;
                 default:
                       
                      printf("No sé que narices me estás contando, pero ya lo tratará nuestro gestor de ventanas :)\n");
                     
                   } //fin del switch de eventos
                   
                   
        } //fin del while (SDL_PollEvent() )

dibuja_heroe (heroex,heroey); //dibuja a nuestro héroe en las coordenadas que queramos

SDL_UpdateRect(.....) //Actualiza pantalla


} //fin del while(!salir)





Éste sería el método tradicional orientado a eventos, como vereís , es un poco engorroso al principio (sobre todo hasta que te acostumbres a los nombres de las estructuras de eventos), pero cuando lleves un par de miles de bucles de éstos....te salen con los ojos cerrados :)

Éste trozo de código entraría en un bucle mientras no haya que salirse del programa while(!salir), después entraríamos en otro bucle que estaría activo mientras haya eventos, en el cual,trataremos dos eventos, uno de teclado(SDL_KEYDOWN) y otro de sistema(SDL_QUIT). Si és un evento de teclado, trataríamos la tecla pulsada y actuaríamos en consecuencia, actualizando las coordenadas de nuestro héroe, si es un evento de sistema (SDL_QUIT) pues actualizaríamos el valor de la variable salir para que en la próxima iteración del bucle, nos vayamos a la playa (o a la piscina :) ).

Después de tratar los eventos, dibujaríamos nuestro héroe en la posición indicada, y actualizaríamos la pantalla.

Y fín de la historia :)

Ahora veamos la manera friki de tratar eventos. En ocasiones nos va a salir más rentable utilizar ésta manera de tratar eventos, pero saber cúando usar una y cúando usar la otra es un conocimiento que nos dará la experiencia.


Vamos a usar SDL_PumpEvents(),SDL_GetKeyState y SDL_PeepEvents



B]Friki-way of life[/B] :P



int heroex,heroey;
int salir=0;
SDL_Event evento;
Uint8 *teclas; //nuestro array de teclas

while(!salir)
{

SDL_PumpEvents(); //actualizamos eventos

teclas=SDL_GetKeyState(NULL); // recogemos el estado actual de las teclas en el array teclas.

if(teclas[SDLK_LEFT]) heroex--; //pa la izquierda

else if(teclas[SDLK_RIGHT]) heroex++; //pa la derecha

if(teclas[SDLK_UP]) heroey--; //parriba

else if(teclas[SDLK_DOWN] ) heroey++; pabajo

if(teclas[SDLK_ESC]) salir=1; //ha pulsado ESC

if(SDL_PeepEvents(NULL, 1, SDL_GETEVENT, SDL_QUIT)>=1) //si hay algun evento en la cola que sea SDL_QUIT
        salir=1; //pues salgo.
       

dibuja_heroe (heroex,heroey); //dibuja a nuestro héroe en las coordenadas que queramos

SDL_UpdateRect(.....) //Actualiza pantalla

}




Mucho más lioso, ¿verdad?. Queda en vuestras manos utilizar la manera que queraís, la ventaja de la segunda es que el muñeco podrá moverse a la vez en los dos ejes, mientras que en el primero (por utilizar un switch, aunque se puede cambiar) solo podrá moverse en un eje a la vez. También se puede utilizar SDL_GetKeyState cuando veamos que el movimiento no es todo lo preciso que deseamos ya que varias teclas pulsadas a la vez, generan varios eventos, que de la primera manera vamos a tratar por separado, pero en la friki-way podremos tratarlas a la vez.

Señores, estoy harto, así que si me permiten....me largo.

Ya sabeís si teneís alguna duda, estoy en el msn: sergio_cia@hotmail.com

Saludos cordiales :)

Nota: Gracias a las condiciones insalubres de mi trabajo, al finalizar éste tutorial, he acabado con un dolor de manos que no veas....

NO MÁS SANGRE POR PETROLEO
billyberjas te propongo una cosa:


PQ no pillas todos los capitulos del Tutorial de SDL y los pones juntos en otro hilo y pones q nadie postee en el? y dejas q este sea para dudas? lo veo una propuesta interesante, no se si te tndrias q poner en contacto con Netvicious o algun moderador para poder hacerlo pero asi tendrias todos los capitulos seguidos sin posts de otra gente

q te parece?
o ir creando el doc en PDF y colgarlo para descargar

saludos
yep, debería, a ver si encuentro tiempo para montarme el 5 capítulo y empiezo a hacerlo bien....ahora mismo mi gbasp me tiene absorvido... [tadoramo] [tadoramo] [tadoramo]
tengo una duda muy importante. Tened en cuenta que soy novato novatisimo.
Por mas ke busco solo encuentro SDL_loke sea, pero en ningun lado encuentro ¿ke son las sdl???
Hitcrasher escribió:tengo una duda muy importante. Tened en cuenta que soy novato novatisimo.
Por mas ke busco solo encuentro SDL_loke sea, pero en ningun lado encuentro ¿ke son las sdl???


Basicamente (y resumido) unas librerias para controlar raton, sonido, teclado y video bajo distintos sistemas, usando OpenGL, escribiendo una sola vez el codigo.

Tienes mas info aqui: http://www.libsdl.org/index.php

Saludos ^^
Holas...

Sus reiréis de mí porque soy muy novato, pero... se puede utilizar las SDL en un juego programado bajo C++?

Y luego sólo decir que la idea de un sólo post para los tutoriales estaría guay (no había un wiki para eso?), y felicitar a billyberjas por todo el curro que se pega y lo bien que lo hace. El tono y las explicaciones están genial, se hace muy ameno todo esto y entran muchas ganas de que pasen los exámenes y probar.

Un saludo!
FuckingFreaky escribió:Holas...

Sus reiréis de mí porque soy muy novato, pero... se puede utilizar las SDL en un juego programado bajo C++?


Claro que se puede, las puedes llamar como si estuvieras en C (ya que puedes utilizar código de C en C++), o usando alguna clase de C++ que las llame, pásate por la web oficial y verás que hay varias soluciones para lo que buscas :)

Saluti y gracias por el cumpido :)
De hecho, lo que visteis de BomberGUM! estaba en C++ y utilizaba SDL ;)

Saludos!
Pensaba que al final para BomberGUM! os habíais decantado por C y no C++.

En serio Billyberjas, me va a servir mucho todo esto cuando después de los exámenes empiece a mirármelo e intentar hacer cosillas.

Por cierto, he visto en la página oficial de SDL un libro en español que se supone te enseña a hacer un juego con SDL desde cero. Claro, supongo que el nivel no llegará para hacer un juegazo, pero como yo lo que quiero es empezar... Más que nada porque sé muy poco de la estructura de un videojuego y demás cosas, y si el libro ese lo enseña y además junto con SDL... perfecto. Alguno sabéis algo?
Cuál pensáis que es la mejor manera de aprender eso?

Un saludínx!
34 respuestas