Reservar memoria dinámica para una matriz en C

Acabamos de hablar hace nada de cómo reservar memoria para un vector unidimensional de forma dinámica con C. Hoy le toca el turno a las matrices o arrays bidimensionales. Los vectores se organizan de forma lineal, secuencial y con todos los elementos en posiciones correlativas en la memoria. Las matrices se almacenan en forma de vector de vectores.

Dimensiones fijas

Si es de dimensiones fijas (declarándolas como matriz[filas][columnas]), el vector de vectores se guardará también uno al lado del otro.

Por lo tanto, en una matriz del tipo:

a00 a01 a02
a10 a11 a12
a20 a21 a22

En memoria (en la que los elementos los direccionamos en una sola dirección) los tendríamos de la siguiente forma (en cada lenguaje este criterio cambia, en Fotran se almacena en forma de vector de columnas):

a00 a01 a02 a10 a11 a12 a20 a21 a22

Dimensiones variables

Sin embargo, en el caso de la memoria dinámica, las cosas cambian. El mecanismo será el siguiente:

  • Declararemos un doble puntero “matriz” sobre el que reservaremos memoria para tantas filas tengamos.
  • Recorreremos el vector recién creado para reservar memoria para las columnas de cada fila.

Hay dos detalles a tener en cuenta:

  • La variable “matriz” será del tipo doble puntero ya que hará referencia a un vector de punteros.
  • Cada fila sí estará almacenada de forma consecutiva en memoria, pero éstas a su vez no estarán de forma obligada juntas, aunque podremos seguir accediendo de la misma forma.

Veamos un ejemplo con código real (no hace comprobaciones de que el malloc se ejecute correctamente):

#include <stdlib.h> #include <stdio.h> int main(void) { int filas = 2; int columnas = 3; int **x; int i; // Recorre filas int j; // Recorre columnas // Reserva de Memoria x = (int **)malloc(filas*sizeof(int*)); for (i=0;i<filas;i++) x[i] = (int*)malloc(columnas*sizeof(int)); // Damos Valores a la Matriz x[0][0] = 1; x[0][1] = 2; x[0][2] = 3; x[1][0] = 4; x[1][1] = 5; x[1][2] = 6; // Dibujamos la Matriz en pantalla for (i=0; i<filas; i++) { printf("\n"); for (j=0; j<columnas; j++) printf("\t%d", x[i][j] ); } return 0; } read more

Leer más » 16 Comentarios

Reservar memoria dinámica para un vector en C

Puesto que estamos hablando bastante de C en el curso de programación de videojuegos con SDL, voy a publicar una serie de pequeños apuntes sobre programación en C que seguro que os son de utilidad. No van a constituir un curso como tal pero serán una serie de entradas relacionadas sobre este tema. read more

Leer más » 8 Comentarios

Curso programación de videojuegos con SDL – Moviendo una imagen por la pantalla

Tras cargar la imagen y quedarse estática en la pantalla os darán ganas de moverla. Aprendamos a como moverla por la pantalla con las flechas del teclado. Aprovecharemos para cambiar la forma de salirnos de la aplicación, ahora lo podremos hacer mediante la tecla ESC o haciendo clic en el cierre de la ventana. Veamos como en el caso anterior lo que debemos incluir:

  1. Declaramos un entero para las coordenadas X e Y de nuestro avión:int posicionJugadorX=320, posicionJugadorY=40;
  2. Declaramos un puntero, para que se almacene un vector dinámico con las teclas pulsadas:Uint8* teclas;
  3. Cambiamos la estructura del programa. Ahora, tras inicializar todo, parte que terminamos cambiando el título a la ventana, pasamos a hacer un bucle para que el programa se ejecute hasta que el jugador quiera salir.while(!terminar)
  4. Usamos la variable posicion tanto para dibujar el fondo como el avión en cada paso del bucle:SDL_BlitSurface(fondo, NULL, screen, &posicion); …posicion.x=posicionJugadorX; posicion.y=posicionJugadorY; SDL_BlitSurface(jugador, NULL, screen, &posicion);
  5. Bucle para detectar salidas (pulsación de ESC o de la cruz de cerrar programa):while ( SDL_PollEvent(&event) ) {if(event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE)terminar = 1;}
  6. Finalmente, el resto de las teclas:teclas = SDL_GetKeyState(NULL);if(teclas[SDLK_UP]) { posicionJugadorY -= 2; }if(teclas[SDLK_DOWN]) { posicionJugadorY += 2;}if(teclas[SDLK_LEFT]) { posicionJugadorX -= 2; }if(teclas[SDLK_RIGHT]) { posicionJugadorX += 2; }

De esta manera conseguiremos que nuestro avión se mueva a través de la pantalla siguiendo nuestras órdenes. Modificaremos nuestro fichero Makefile para poder compilar este ejemplo. El resultado es el mismo que antes pero podemos mover nuestro avión. El código completo:

#include <stdio.h> #include <stdlib.h> #include <SDL/SDL.h> #define MASK 255, 255, 255 int main() { SDL_Surface *screen; SDL_Surface *fondo; SDL_Surface *jugador; SDL_Event event; int terminar=0; SDL_Rect posicion; int i, j; int posicionJugadorX=320, posicionJugadorY=40; Uint8* teclas; if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("No se pudo inicializar SDL: %s\n", SDL_GetError()); exit(1); } fondo = SDL_LoadBMP("fondo.bmp"); jugador = SDL_LoadBMP("avion.bmp"); SDL_SetColorKey (jugador, SDL_SRCCOLORKEY, SDL_MapRGB (jugador->format, MASK)); screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE ); if( screen == NULL ) {   printf( "Error al entrar a modo grafico: %s\n", SDL_GetError() );   SDL_Quit();   return -1; } SDL_WM_SetCaption( "Moviendo nuestro avion", "Moviendo nuestro avion" ); while(!terminar) {   for (i=0; i<10; i++)     for (j=0; j<10; j++)     {       posicion.x=64*i;       posicion.y=48*j;       SDL_BlitSurface(fondo, NULL, screen, &posicion);     }   posicion.x=posicionJugadorX;   posicion.y=posicionJugadorY;   SDL_BlitSurface(jugador, NULL, screen, &posicion);   SDL_Flip(screen);   /*salida con ESC o cerrar ventana*/   while ( SDL_PollEvent(&event) )   {     if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE)       terminar = 1;   }   /* Vemos el estado indivudal de las teclas de la cruceta */   teclas = SDL_GetKeyState(NULL);   if (teclas[SDLK_UP]) { posicionJugadorY -= 2; }   if (teclas[SDLK_DOWN]) { posicionJugadorY += 2;}   if (teclas[SDLK_LEFT]) { posicionJugadorX -= 2; }   if (teclas[SDLK_RIGHT]) { posicionJugadorX += 2; } } SDL_Quit(); return 0; } read more

Leer más » 5 Comentarios

Temperatura de Color en GIMP

Una de las carácterísticas que más añoraba al revelar mis fotografías con GIMP era el ajuste de la temperatura de color. Encontré un plugin, Colortemp, para realizar esta tarea, pero no era demasiado intuitivo. Ya que tenía que indicar la temperatura de color inicial y la que deseábamos obtener, con lo que si hemos de ir probando hasta conseguir el resultado esperado esto se puede convertir en una tarea algo complicada.

Así, me puse a buscar y encontré YUV Temperature, en este caso los cálculos se hacen teniendo en cuenta el nivel temperatura, ángulo de incidencia y la compesación a la exposición. Podemos considerar el siguiente esquema: read more

Leer más » 2 Comentarios

¿Cuál es el equivalente de la función NVL de Oracle en MySQL?

Cuando estamos realizando consultas contra una base de datos, en nuestro SELECT es posible que estemos usando campos que puedan ser iguales a NULL y que pueden afear nuestras salidas o directamente, crearnos problemas en nuestros desarrollos (por ejemplo porque tratemos de forma lógica lo mismo la cadena vacía y el NULL). read more

Leer más » 3 Comentarios

Curso programación de videojuegos con SDL – Cargando imágenes con SDL

Ya hemos visto cómo cargar una ventana simple con SDL y ponerle título. No está mal para comenzar, pero estaréis deseando hacer algo más. Lo siguiente que haremos será cargar una imagen en pantalla operación que se repite multitud de veces en cualquier juego a la hora de cargar tanto fondos, como personajes.

Para carga una imagen haremos lo siguiente:

  1. Declaramos un puntero a una variable del tipo SDL_Surface: SDL_Surface *jugador;
  2. Declaramos una variable del tipo SDL_Rect:SDL_Rect posicion;
  3. Cargamos el mapa de bits: jugador=SDL_LoadBMP(“avion.bmp”);
  4. Asignamos la posición, mediante sus coordenadas X e Y:
    posicion.x=320;
    posicion.y=400;
  5. Acoplamos la imágen al “screen”: SDL_BlitSurface(jugador, NULL, screen, &posicion);
  • jugador: superficie (SDL_Surface) que queremos insertar o de orígen.
  • NULL: indica que queremos insertar toda la imagen.
  • screen: superficie dónde se va a insertar.
  • posicion: la posición dónde se colocará.

Ya tenemos la imagen cargada. El problema de cargarla de esta manera es que no tenemos transparencias y tendríamos la imagen nuestra, avión sobre fondo blanco, apareciendo sobre el fondo, azul (imitando al mar), por lo que alrededor del avión quedaría un recuadro blanco que sin duda quedaría muy mal. Para eliminar este fondo blanco y hacer que SDL lo cargue transparente hacemos lo siguiente:

  1. Definimos una máscara con el color RGB del color a hacer transparente. En este caso el blanco, RGB(255,255,255): #define MASK 255, 255, 255
  2. Hacemos transparentes los píxeles blancos: SDL_SetColorKey (jugador, SDL_SRCCOLORKEY, SDL_MapRGB (jugador->format, MASK));
  • jugador: la superficie en la que aplicar el efecto.
  • SDL_SRCCOLORKEY: Indicar hacer transparencia.
  • SDL_MapRGB jugador->format: formato de la imagen
  • SDL_MapRGB MASK: máscara, en realidad son tres parámetros, (r,g,b).

De esta manera conseguimos un resultado así:

Veamos el código al completo:

#include <stdio.h> #include <stdlib.h> #include <SDL.h> #define MASK 255, 255, 255 int main() { SDL_Surface *screen; SDL_Surface *fondo; SDL_Surface *jugador; SDL_Event event; int terminar=0; SDL_Rect posicion; int i, j; if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("No se pudo inicializar SDL: %s\n", SDL_GetError()); exit(1); } fondo = SDL_LoadBMP("fondo.bmp"); jugador = SDL_LoadBMP("avion.bmp"); SDL_SetColorKey (jugador, SDL_SRCCOLORKEY, SDL_MapRGB (jugador->format, MASK)); screen = SDL_SetVideoMode( 640, 480, 16, SDL_HWSURFACE ); if( screen == NULL ) { printf( "Error al entrar a modo grafico: %s\n", SDL_GetError() ); SDL_Quit(); return -1; } SDL_WM_SetCaption( "Moviendo nuestro avion", " Moviendo nuestro avion" ); for (i=0; i<10; i++) for (j=0; j<10; j++) { posicion.x=64*i; posicion.y=48*j; SDL_BlitSurface(fondo, NULL, screen, &posicion); } posicion.x=320; posicion.y=400; SDL_BlitSurface(jugador, NULL, screen, &posicion); SDL_Flip(screen); while(terminar == 0) { while ( SDL_PollEvent(&event) ) { if ( event.type == SDL_KEYUP ) terminar = 1; } } SDL_Quit(); return 0; } read more

Leer más » 13 Comentarios

Instalar Natural Scrolling en Ubuntu

Una de las características que más me han llamado la atención del reciente lanzamiento de Mac OS X Lion es el Natural Scrolling. ¿Y qué significa esto? Como muchos habréis notado, cuando hacemos scroll con un dispositivo móvil con pantalla táctil sobre un elemento (e.g. Navegador Web) nos deplazamos en orden invertido. Y es esto lo que nos ofrece esta característica.

Bien, para instalarlo en nuestro sistema Linux, en este caso Ubuntu (supongo que no habrá problema en otros sistemas basados en Debian): read more

Leer más » 3 Comentarios

Curso programación de videojuegos con SDL – ¡Hola mundo!

Comenzaremos con un ejemplo mínimo de SDL dónde abriremos una ventana con el título “Hola Mundo”. Para ello además del código en C prepararemos el Makefile para compilarlo. Podríamos haber usado un entorno de desarrollo integrado como Anjuta por ejemplo, pero ya que se trata de una iniciación a SDL lo mejor creo que es trabajar directamente sobre el compilador y los Makefile.

Makefile

Comenzaremos con el Makefile. Incluiremos además de “sdl-config” las librerías que hemos instalado en el paso anterior:

SDL_CONFIG = sdl-config
DEFAULT_CFLAGS = $(shell $(SDL_CONFIG) --cflags)
MORE_CFLAGS = -O2 

CFLAGS = $(DEFAULT_CFLAGS) $(MORE_CFLAGS)
CXXFLAGS = $(DEFAULT_CFLAGS) $(MORE_CFLAGS) -fno-exceptions -fno-rtti 

LDLIBS = -lSDL_image -lSDL_mixer -lSDL_ttf -lSDL_net
 $(shell $(SDL_CONFIG) --libs) 

all: holamundo_sdl
holamundo_sdl: holamundo_sdl.c 

clean:
	rm -f *~
	rm -f main.o main

holamundo_sdl.c

Pasemos ahora a implementar nuestro primer programa con SDL. Será lo más sencillo posible y básicamente realizará las dos siguientes acciones:

  • Abrirá una ventana con el título “Hola Mundo SDL”.
  • Se cerrará cuando pulsemos “Tecla hacia arriba”.

#include <stdio.h> #include <stdlib.h> #include <SDL.h> int main(int argc, char *argv[]) { SDL_Surface *image, *screen; SDL_Rect dest; SDL_Event event; int terminar=0; atexit(SDL_Quit); if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("No se pudo iniciar SDL: %s\n",SDL_GetError()); exit(1); } screen = SDL_SetVideoMode(640,480,24,SDL_HWSURFACE); if (screen == NULL) { printf("No se puede inicializar el modo gráfico: %s\n", SDL_GetError()); exit(1); } SDL_WM_SetCaption("Hola Mundo SDL","Hola Mundo SDL"); SDL_Flip(screen); while(terminar == 0) { while ( SDL_PollEvent(&event) ) { if ( event.type == SDL_KEYUP ) terminar = 1; } } return 0; } read more

Leer más » 11 Comentarios

Forzar reinstalar con YUM

Para reinstalar un paquete con el gestor de paquetes YUM tenemos tres opciones:

1. Desinstalar y volver a instalar:

root@6581-D:~$ yum remove PACKAGE
root@6581-D:~$ yum install PACKAGE

2. Si por las dependencias tenemos problemas para desinstalarlo, forzamos la desinstalación con RPM y lo volvemos a instalar:

root@6581-D:~$ rpm -e –nodeps PACKAGE
root@6581-D:~$ yum install PACKAGE

3. Como último caso, supongamos que las dependencias que tiene son tan grandes como para desinstalar algo que no queremos. Entonces forzamos desinstalación evitando dependencias, así: read more

Leer más » 2 Comentarios

Curso programación de videojuegos con SDL – Instalación y configuración

Una vez introducidos en qué es SDL pasemos a la parte práctica. Comencemos instalando los componentes necesarios. Si usas Ubuntu, Debian o cualquier otra distribución que use Synaptic o APT instalaremos los siguientes paquetes: read more

Leer más » 3 Comentarios