Hardware Programacion Videojuegos

  • November 2019
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Hardware Programacion Videojuegos as PDF for free.

More details

  • Words: 3,108
  • Pages: 48
Introducción a la programación de videojuegos David Erosa García Luis Rodero Morales

[email protected]

[email protected]

Acceso al hardware Allegro y SDL

Introducción Consiguiendo las librerías



Allegro puede conseguirse en http://alleg.sf.net. Su última versión es la 4.1.13.

• • •

En http://www.allegro.cc hay todo tipo de addons y utilidades, además de numerosos juegos (con su código fuente (o no)).

SDL, cuya última versión es la 1.2.7, al igual que sus addons y juegos, se puede encontrar en http://libsdl.org .

Ambos pueden descargarse de dos formas:

• •

Está el código fuente listo para ser compilado. En versión precompilada (Dev-C++, MinGW32, MSVC, paquetes para distintas distribuciones GNU/Linux...).

3

Introducción Compilando - Allegro



Para compilar un programa Allegro en GNU/Linux: g++ `allegro-config --libs --cppflags` main.cpp -o prueba

• • •

Esta línea genera como salida un ejecutable 'prueba' a partir de un fuente 'main.cpp'.

Para Dev-C++ hay paquetes de desarrollo preparados que generan proyectos Allegro listos para ser compilados. Dado que el código fuente está disponible, es muy sencillo adaptarlo a las necesidades de nuestro compilador (p.ej. MS-Visual-C++).

4

Introducción Compilando - SDL



La compilación de un programa SDL en GNU/Linux es muy sencilla: g++ `sdl-config --libs --cflags` $(LIBS) main.cpp -o prueba



• • •

Donde LIBS depende de las librerias extras que vayamos a usar:

• • •

-lSDL_image para SDL_image. -lSDL_mixer para SDL_mixer. -lSDL_ttf para SDL_ttf...

Esta línea genera como salida un ejecutable 'prueba' a partir de un fuente 'main.cpp'.

Para Dev-C++ hay paquetes de desarrollo preparados que generan proyectos SDL listos para ser compilados. Dado que el código fuente está disponible, es muy sencillo adaptarlo a las necesidades de nuestro compilador (p.ej. MS-Visual-C++). 5

Inicialización - Finalización Allegro

• • • • •

Siempre hay que incluir la cabecera “allegro.h”. Para inicializar la librería, basta con llamar a la macro allegro_init ()



Configura varios parámetros relacionados con el sistema operativo.

Devuelve 0 siempre, si no puede inicializarse aborta la ejecución. Para cerrar la librería, se llama a la función allegro_exit () (no es necesario) Justo después de la llave de cierre de main, hay que llamar a END_OF_MAIN ().

6

Inicialización - Finalización SDL

• • • •

Siempre hay que incluir “SDL.h” Opcionalmente: “SDL_image.h”, “SDL_mixer.h”, “SDL_ttf.h”... SDL se inicializa con: int SDL_Init (Uint32 flags)

• •

Devuelve -1 en caso de error, 0 en caso de éxito. Los flags determinan los subsistemas a inicializar.

Pueden inicializarse y terminarse subsistemas individuales int SDL_InitSubSystem (Uint32 flags) void SDL_QuitSubSystem (Uint32 flags)



Se finaliza el uso de SDL con void SDL_Quit (void)

7

Lo que vamos a ver • • • • • •

Empezando Funciones de entrada. Funciones de sonido. Funciones de cronometrado. Funciones gráficas.

Red y eso pa otro año... :P

8

Empezando... Iniciar un modo gráfico



En Allegro: int set_gfx_mode (int card, int w, int h, int v_w, int v_h)

• •

Luego veremos qué significan los parámetros. En principio haremos la llamada de la siguiente forma: set_gfx_mode (GFX_AUTODETECT_WINDOWED, 320, 240, 0, 0);



En SDL: SDL_Surface* SDL_SetVideoMode (int w, int h, int bpp, Uint32 flags)

• •

Luego veremos qué significan los parámetros. La llamada que haremos será: screen = SDL_SetVideoMode (320, 240, 0, SDL_ANYFORMAT);

9

Funciones de entrada Introducción



• •

Veremos cómo acceder a dispositivos como:

• • •

Teclado. Ratón. Joystick - Gamepad.

Hay multitud de métodos relacionados con cada dispositivo en ambas librerías, así que sólo veremos los que vayamos a usar posteriormente (por simplicidad). En SDL puede consultarse el estado de los dispositivos mediante eventos, lo que se verá más adelante, tras los métodos que usemos.

10

Funciones de entrada Leyendo el teclado - Allegro

• •



Antes de nada : int install_keyboard ()

• •

Inicializa el módulo de teclado. Devuelve 0 si no hubo errores, valor negativo en otro caso.

int poll_keyboard ()

• • • •

Lo usaremos siempre (para mantener la portabilidad). Actualiza los valores del array extern volatile char key [KEY_MAX]. Este array indica el estado del teclado en cualquier momento. Un elemento del array valdrá TRUE si la tecla representada por él está pulsada.

int readkey ()

• •

Lo usaremos cuando haga falta esperar cualquier pulsación. Devuelve el código de la tecla pulsada. 11

Funciones de entrada Leyendo el teclado - SDL



En SDL antes de usar las funciones de comprobación de dispositivos de entrada hay que llamar a void SDL_PumpEvents (void) para que recoja la información pendiente de los dispositivos de entrada.



Hay dos métodos para leer la entrada del teclado:

• •

Por eventos, que veremos más adelante. Asíncronamente:



Se usa la función Uint8* SDL_GetKeyState (int *numkeys)



Ésta devuelve un array de tipo Uint8 (≈char) indexado según los símbolos de teclado de SDL (SDL_keysym.h).

12

Funciones de entrada Leyendo el ratón – Allegro (1)

• •

Antes de nada : int install_mouse ()

• •

Inicializa el ratón. Devuelve 0 si no hubo errores, valor negativo en otro caso.

int poll_mouse ()

• • •

Lo usaremos siempre (para mantener la portabilidad). Actualiza los valores de:

• •

extern volatile int mouse_x, mouse_y, mouse_z, mouse_b, mouse_pos. Estas variables indican los valores actuales de posición, rotación de la rueda, y botones.

Las posiciones se miden en píxels, y los botones se obtienen comparando bits (lo veremos ahora en un ejemplo).

13

Funciones de entrada Leyendo el ratón – Allegro (2)



Hay muchas más funciones de ratón:

• • • • • • •

void set_mouse_speed (int xspeed, int yspeed); void set_mouse_sprite (BITMAP *sprite); void show_mouse (BITMAP *bmp); void get_mouse_mickeys (int *mickeyx, int *mickeyy); void position_mouse (int x, int y) void position_mouse (int z) ...

14

Funciones de entrada Leyendo el ratón - SDL



Tras llamar a void SDL_PumpEvents (void) podemos solicitar el estado del ratón con: Uint8 SDL_GetMouseState (int *x, int *y)

• •

Devuelve una máscara con los botones pulsados, la cual se puede comprobar con la macro SDL_BUTTON (x) Por ejemplo, para saber si se está pulsando el botón 1 del ratón: if ( SDL_GetMouseState (NULL, NULL) & SDL_BUTTON (1) ) printf (“Botón 1 pulsado!\n”);



Otra función similar (y posiblemente más util) es: Uint8 SDL_GetRelativeMouseState (int *x, int *y)



Que devuelve en x e y la posición relativa del ratón respecto a la última consulta, así como la máscara de botones.

15

Funciones de entrada Leyendo el Joystick - Allegro





Antes de nada : int install_joystick (int type)

• • •

Inicializa los joysticks que haya instalados. A type le pasaremos JOY_TYPE_AUTODETECT. Devuelve 0 si no hubo errores, valor negativo en otro caso.

int poll_joystick ()

• •

El joystick no se actualiza asíncronamente. Actualiza los valores de extern JOYSTICK_INFO joy [n]



Esta estructura contiene toda la información sobre un joystick:

• • •

int flags, int num_sticks, int num_buttons JOYSTICK_STICK_INFO stick [n] JOYSTICK_BUTTON_INFO button [n]

16

Funciones de entrada Leyendo el Joystick – Allegro



Cómo comprobar el estado de un joystick:



El movimiento se mira con: joy[n_joy].axis[n_axis].d1 joy[n_joy].axis[n_axis].d2



• • •

Siendo n_joy el id del joystick y n_axis el id de eje. Si n_axis es 0, d1 es izquierda y d2 es derecha Si n_axis es 1, d1 es arriba y d2 es abajo.

Las pulsaciones de botones se obtienen con: joy[n_joy].button[n_button].b





Siendo n_joy el id del joystick y n_button el id de botón.

Todo esto se toma como valores lógicos.

17

Funciones de entrada Leyendo el joystick - SDL

• •

Es necesario el flag SDL_INIT_JOYSTICK en la inicialización. Abrir el joystick con SDL_Joystick *SDL_JoystickOpen (int index)



Antes de consultar el estado, hay que llamar a void SDL_JoystickUpdate (void)



Se consulta el estado de los ejes del joystick con Sint16 SDL_JoystickGetAxis (SDL_Joystick *joystick, int axis)



Y los botones con Uint8 SDL_JoystickGetButton (SDL_Joystick *joystick, int button)



Se termina el uso del joystick con void SDL_JoystickClose (SDL_Joystick *joystick)

18

Funciones de entrada Eventos en SDL



SDL puede recibir el estado de teclado, ratón y joysticks por eventos. int SDL_PollEvent (SDL_Event *event)



Mediante un switch, determinamos el tipo de evento que ha ocurrido: SDL_Event evento; SDL_PollEvent (&evento); switch (evento.type) { case SDL_KEYDOWN: .... case SDL_MOUSEMOTION: ... case SDL_JOYAXISMOTION: ... case SDL_JOYBUTTONDOWN: ... } 19

Funciones de sonido Inicializando - Allegro



Antes de nada: int install_sound (int digi, int midi, const char *cfg_path);



• • • • •

digi normalmente será DIGI_AUTODETECT. midi, como no lo vamos a usar, MIDI_NONE. cfg_path lo pondremos a NULL. Inicia el sistema de sonido. Devuelve 0 si no hubo errores, valor negativo en otro caso.

void set_volume (int digi_volume, int midi_volume)

• •

Configura el volumen maestro del sonido digital y la música MIDI. Valores entre 0 y 255 (silencio - máximo).

20

Funciones de sonido Samples - Allegro

• •

Estructura SAMPLE : guarda los datos de un sonido digital. Para cargar un sonido: SAMPLE *load_sample(const char *filename)



Para reproducirlo: int play_sample(const SAMPLE *spl, int vol, int pan, int freq, int loop)



Para detener su reproducción: void stop_sample(const SAMPLE *spl)



Para quitar el sonido de la memoria: void destroy_sample(SAMPLE *spl)

21

Funciones de sonido Samples - SDL

• • •

Usaremos la librería SDL_mixer. Hay que pasar el flag SDL_INIT_AUDIO en SDL_Init (...). Las funciones necesarias para reproducir un sonido son: int Mix_OpenAudio (int freq, Uint16 format, int chans, int chunksze) Mix_Chunk *Mix_LoadWAV (char *file) int

Mix_PlayChannel (int channel, Mix_Chunk *chunk, int loops)

void

Mix_Pause (int channel)

void

Mix_Resume (int channel)

void

Mix_CloseAudio (void)

void

Mix_FreeChunk(Mix_Chunk *chunk)

22

Funciones de sonido Música - Allegro

• •



Usaremos la librería allegroMP3. Tenemos una clase FF_AllMusic, con la siguiente interfaz:

• • • • •

load (char *) play (void) stop (void) isPlaying (void) kill (void)

Habrá que añadir la opción '-lalmp3' antes de allegro-config en la compilación.

23

Funciones de sonido Música - SDL

• • •

También usaremos la librería SDL_mixer. Flag SDL_INIT_AUDIO en SDL_Init (...) y abrir el dispositivo de audio. Las funciones necesarias para reproducir música son: Mix_Music *Mix_LoadMUS (char *file) int

Mix_PlayMusic (Mix_Music *music, int loops)

void

Mix_PauseMusic (void)

void

Mix_ResumeMusic (void)

int

Mix_HaltMusic (void)

void

Mix_CloseAudio (void)

void

Mix_FreeMusic (Mix_Music *music)

24

Funciones de cronometrado Inicializando - Allegro



Hay que llamar a la función: int install_timer ()

• •

Devuelve 0 si no hubo errores, pero se puede pasar del valor de retorno, ya que es muy difícil que falle. Varios subsistemas de Allegro dependen de timers.

25

Funciones de cronometrado Timers – Allegro (1)



Para crear un timer se llama a una de las siguientes funciones: int install_int (void (*proc)(), int speed); int install_int_ex (void (*proc)(), int speed);



Donde proc es un puntero a una función definida así: void funcion () { /* Lo que aquí se modifique debe ser volatile*/ } END_OF_FUNCTION ();



En la inicialización, hay que bloquear la memoria de la función y de la variable que modifique con LOCK_VARIABLE (variable)y LOCK_FUNCTION (funcion).

26

Funciones de cronometrado Timers – Allegro (2)



speed se toma de distinta manera en las dos funciones:

• •

En install_int se toma como milisegundos. En install_int_ex se toma como ticks del reloj del sistema.





Podemos dar speed en este caso de varias maneras:

• • • •

SECS_TO_TIMER (n) n = número de segundos entre ticks. MSEC_TO_TIMER (n) n = número de milisegundos entre ticks. BPS_TO_TIMER (n) n = número de ticks por segundo. BPM_TO_TIMER (n) n = número de ticks por minuto.

Conviene más usar BPS_TO_TIMER.

27

Funciones de cronometrado Timers – Allegro (3)



Para borrar un timer: void remove_int (void (*proc)())

• •

Donde proc es la función con la que creamos el timer.

Con void rest (long time) hacemos una pausa de time milisegundos.

28

Funciones de cronometrado Timers – SDL (1)



Milisegundos transcurridos desde la inicialización de SDL: Uint32 SDL_GetTicks (void)



Realizar una pausa de ms milisegundos: void SDL_Delay (Uint32 ms)

29

Funciones de cronometrado Timers – SDL (2)



Para timers es necesario pasar SDL_INIT_TIMER a SDL_Init (...)



Para que cada interval milisegundos se ejecute la función callback: SDL_TimerID SDL_AddTimer ( Uint32 interval, SDL_NewTimerCallback callback, void *param)



Donde SDL_NewTimerCallback es: typedef Uint32 (*SDL_NewTimerCallback) (Uint32 interval, void *param)



Para eliminar un timer se usa: SDL_bool SDL_RemoveTimer (SDL_TimerID id)

30

Funciones gráficas Gráficos – Allegro (1)



Antes de iniciar un modo gráfico, hay que usar void set_color_depth (int depth) // depth = {8,15,16,24,32}



La función para iniciar modos gráficos es: int set_gfx_mode (int card, int w, int h, int v_w, int v_h)



• •

card especifica el driver gráfico. Puede ser:

• • • • •

GFX_AUTODETECT GFX_AUTODETECT_WINDOWED GFX_AUTODETECT_FULLSCREEN GFX_SAFE GFX_TEXT

w y h son el ancho y alto respectivamente del área visible. v_w y v_h son el ancho y alto virtuales. 31

Funciones gráficas Gráficos – Allegro (2)

• •

Allegro usa una estructura BITMAP para almacenar datos de imagen.



Los únicos campos que nos pueden interesar son w y h, que son el ancho y alto de la imagen cargada.

Para cargar una imagen se usa: BITMAP* load_bitmap (const char *filename, RGB *pal)





Como no usaremos paletas, pal será siempre NULL.

El método que usaremos será:

• •

Declarar un puntero a BITMAP. Inicializarlo con la función anterior.

32

Funciones gráficas Gráficos – Allegro (3)



La pantalla está representada como un BITMAP de ancho y alto los especificados en set_gfx_mode: extern BITMAP *screen



Para poner un BITMAP a color 0, se usa: void clear_bitmap (BITMAP* bitmap)



Para dibujar un BITMAP en otro, usamos:

void blit (BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height)

• •

Podemos dibujarlo entero o parte (según los parámetros source_x, source_y, width y height)

Para dibujar un sprite en un BITMAP: void draw_sprite (BITMAP *bmp, BITMAP *sprite, int x, int y)

33

Funciones gráficas Gráficos – Allegro (4)



Diferencias entre blit y draw_sprite:

BITMAP original

BITMAP de destino Usando blit

34

Resultado

Funciones gráficas Gráficos – Allegro (5)



Diferencias entre blit y draw_sprite:

BITMAP original

BITMAP de destino Usando draw_sprite

35

Resultado

Funciones gráficas Gráficos – Allegro (6)

• •

Para dibujar directamente en pantalla, sólo hay que especificar screen como BITMAP de destino.



Ésto no es recomendable, lo veremos cuando veamos animación.

Para borrar un BITMAP de la memoria: void destroy_bitmap( BITMAP *bmp)

36

Funciones gráficas Gráficos – SDL (1)



El tipo de dato gráfico de SDL es SDL_Surface

typedef struct SDL_Surface { Uint32 flags; SDL_PixelFormat *format; int w, h; Uint16 pitch; void *pixels; SDL_Rect clip_rect; int refcount; } SDL_Surface;

37

Funciones gráficas Gráficos – SDL (2)



Inicializar el modo gráfico: SDL_Surface* SDL_SetVideoMode (int w, int h, int bpp, Uint32 flags)





Algunos flags son: SDL_SWSURFACE

SDL_HWSURFACE

SDL_ANYFORMAT

SDL_HWPALETTE

SDL_DOUBLEBUF

SDL_FULLSCREEN

SDL_OPENGL

SDL_OPENGLBLIT

SDL_RESIZABLE

SDL_NOFRAME

Devuelve NULL en caso de error, o la superficie del framebuffer.

38

Funciones gráficas Gráficos – SDL (3)

• •

Para leer los gráficos usaremos la librería SDL_image. Para cargar una imagen: SDL_Surface* IMG_Load (const char *file)



Para liberar la superficie se usa: void SDL_FreeSurface (SDL_Surface *surface)

39

Funciones gráficas Gráficos – SDL (4)



Para representar un gráfico en pantalla, es necesario “pegarlo” en la superficie que actúa como tal.

SDL_Surface *screen; screen = SDL_SetVideoMode (640, 480, 0, SDL_ANYFORMAT);

= SDL_Surface *sprite

SDL_Surface *screen

40

SDL_Surface *screen

Funciones gráficas Gráficos – SDL (5)



Para hacer blit de una superficie en otra: int SDL_BlitSurface ( SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect )

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

41

Funciones gráficas Gráficos – SDL (6)



Podemos especificar el color transparente de la imagen con int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)

• •

Donde flag debe ser SDL_SRCCOLORKEY para establecer el color transparente o 0 para eliminar el color clave. El color de la transparencia se indica con Uint32 SDL_MapRGB (SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8 b)



El parámetro fmt suele ser el miembro format de la superficie en la que se establece el color transparente. ... Uint32 color = SDL_MapRGB (sprite->format, 255, 0, 255); SDL_SetColorKey (sprite, SDL_SRCCOLORKEY, color); ...

42

Funciones gráficas Doble buffer

• •

Se usa para evitar el parpadeo que se produce por el refresco al dibujar directamente en pantalla. Hay varias maneras de implementarlo:

• •

Page-Flipping



Consiste en usar dos superficies para dibujar, que se intercambian coincidiendo con el refresco vertical.

Double-Buffer



Se dibuja en una superficie y se representa en pantalla una vez terminado de dibujar el fotograma completo.

43

Funciones gráficas Doble buffer



En Allegro:



Page-Flipping



Tenemos dos estructuras BITMAP y las intercambiamos usando: int show_video_bitmap (BITMAP *bmp)



Double-Buffer



Dibujamos en el BITMAP que actúa de buffer y cuando terminamos lo volcamos a screen.

44

Funciones gráficas Doble buffer

• •

Para poder visualizar usando SDL los cambios efectuados en la superficie de pantalla, hay que intercambiar los buffers (en caso de usar doble buffer) o actualizar la superficie (en caso de no usar doble buffer). Para intercambiar los buffers (Page Flipping): int SDL_Flip (SDL_Surface *screen)



Para actualizar una superficie o parte de ella: void SDL_UpdateRect (

SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h)



Donde x, y, w y h representan la posición y las dimensiones del rectángulo a actualizar. Si todos los valores valen 0, se actualiza la superficie completa.

45

Funciones gráficas Texto – Allegro



Para dibujar texto, usamos las siguientes funciones:

void textout (

BITMAP *bmp, const FONT *f, const char *s, int x, int y, int c)

void textout_centre ( BITMAP *bmp, const FONT *f, const char *s, int x, int y, int c) void textprintf (

BITMAP *bmp, const FONT *f, int x, int y, int c, const char *fmt, ...)

void textprintf_centre (

BITMAP *bmp, const FONT *f, int x, int y, int c, const char *fmt, ...)



Existe una librería externa llamada AllegroFont que carga fuentes TrueType. Sus funciones tienen la misma sintaxis, pero con el prefijo 'alfont_' y el sufijo opcional '_aa' si queremos anti-aliasing.

46

Funciones gráficas Texto – SDL

• • •

SDL no tiene funciones para representar texto en pantalla, pero existe una librería que suple esta carencia: SDL_ttf SDL_ttf usa la librería freetype2. Las funciones básicas son: int TTF_Init (void) TTF_Font *TTF_OpenFont (const char *font, int size) SDL_Surface *TTF_RenderText_Blended ( TTF_Font *font, const char *text, SDL_Color color) void TTF_CloseFont (TTF_Font *font) void TTF_Quit (void)

47

EOD • •

Ya (se supone que) manejamos Allegro y SDL en un nivel básico. El próximo día veremos cómo encapsular los subsistemas.

48

Related Documents