Movimiento de sprites

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

Movimiento de sprites

Notapor pablo9891 » Vie Dic 31, 2010 3:52 am

Buscando en internet acerca del movimiento de sprites, he sido incapaz de encontrar una forma que realmente me plazca y sobre todo que entienda, acerca del movimiento de los sprites, basicamente tengo esta imagen

Imagen

y lo que estoy intentando hacer es moverla, yo se que lo que deberia hacer es intentar dividir a la imagen en funcion de la cantidad de filas y columnas que tiene, pero eso a donde me conviene cargarlo, en una matriz o array como estube viendo que algunos hacen, o simplemente ir controlandolo mediante una funcion, pero eso me trae otro problema que es que, no todas las imagenes tienen el mismo tamaño, por lo que estoy bastante confundido,


Código: Seleccionar todo
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
#include<SDL_image.h>

#define anchoSprite 82;
#define alturaSprite 76;

#include <stdio.h>

class Frame
{

public:
    SDL_Surface* img;

    void cargaImagen(char* archivo)
    {
        SDL_Surface* temporal = NULL;
        img = NULL;
        if(temporal == NULL)
        {

         temporal = IMG_Load(archivo);

         img = SDL_DisplayFormat(temporal);
         SDL_FreeSurface(temporal);
        }
    }

    void eliminarImagen()
    {
        SDL_FreeSurface(img);
    }
};

class Personaje
{
private:
    int x;
    int y;
    int altura;
    int ancho;
    Frame miFrame;

    public:
    Personaje(int x,int y,char* archivo)
    {

        miFrame.cargaImagen(archivo);

        setX(x);
        setY(y);
    }

     int getAltura()
    {
     return miFrame.img->h;
    }

     int getAncho()
    {
     return miFrame.img->w;
    }

    int getY()
    {
     return y;
    }

    void setY(int y)
    {
     this->y = y;
    }
    int getX()
    {
     return x;
    }

    void setX(int x)
    {
     this->x = x;
    }

    void borrarFrame(){miFrame.eliminarImagen();}

    void dibujarImagen(SDL_Surface* superficieDestino,int x,int y)//con sy y sx, como variables del sprite de origen
    {
     SDL_Rect rectanguloRecortado;
     SDL_Rect rectanguloDestino;

     rectanguloRecortado.x = x;
     rectanguloRecortado.y = y;
     rectanguloRecortado.h = y+alturaSprite;
     rectanguloRecortado.w = anchoSprite;

     rectanguloDestino.x = getX();
     rectanguloDestino.y = getY();

     SDL_BlitSurface(miFrame.img, &rectanguloRecortado, superficieDestino, &rectanguloDestino);
    }
};

void limpieza(SDL_Surface* superficieLimpiar)
{
    SDL_FreeSurface(superficieLimpiar);
    SDL_Quit();
}

SDL_Surface* inicializaSdl(SDL_Surface* Surf_Display)
{
//INICIO TODO, SI ESTA MAL DEVUELVE ERROR
    if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
    {
        return NULL;
    }
    //ACA ES DONDE CREO LA PANTALLA Y SE LA ASIGNO A SDL_DISPLAY
    if((Surf_Display = SDL_SetVideoMode(1000,480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
    {
        return NULL;
    }
    return Surf_Display;
}

SDL_Surface* borrarPantalla(SDL_Surface* pantallaModificada, Personaje miPersonaje)
{
SDL_Rect rectangulo;
rectangulo.x = miPersonaje.getX();
rectangulo.y = miPersonaje.getY();
rectangulo.h = miPersonaje.getAltura();
rectangulo.w = miPersonaje.getAncho();
SDL_FillRect(pantallaModificada,&rectangulo,SDL_MapRGB(pantallaModificada->format,0,0,0));
return pantallaModificada;
}

int gameLoop()
{
bool ejecuta = true;
SDL_Surface* pantalla;
SDL_Event evento;
pantalla = NULL;
SDL_Surface* imagen;
SDL_Rect rectangulo;
Uint8 *key;

if((pantalla=inicializaSdl(pantalla)) == NULL)
{
  return -1;
}

Personaje miPersonaje(50,50,"nave.png");

while(ejecuta)
{
  miPersonaje.dibujarImagen(pantalla,82,0);
  SDL_PumpEvents();
  key = SDL_GetKeyState(NULL);
  if(key[SDLK_UP])
  {
   int aRecortar = alturaSprite;
   pantalla = borrarPantalla(pantalla,miPersonaje);
   miPersonaje.setY(miPersonaje.getY()-1);
   miPersonaje.dibujarImagen(pantalla,82,aRecortar);
  }
  if(key[SDLK_DOWN])
  {
   pantalla = borrarPantalla(pantalla,miPersonaje);
   miPersonaje.setY(miPersonaje.getY()+1);
   miPersonaje.dibujarImagen(pantalla,82,0);
  }
  if(key[SDLK_RIGHT])
  {
   int aRecortar = 82 + anchoSprite;
   pantalla = borrarPantalla(pantalla,miPersonaje);
   miPersonaje.setX(miPersonaje.getX()+1);

   miPersonaje.dibujarImagen(pantalla,aRecortar,0);
  }
  if(key[SDLK_LEFT])
  {
   int aRecortar = 82 - anchoSprite;
   pantalla = borrarPantalla(pantalla,miPersonaje);
   miPersonaje.setX(miPersonaje.getX()-1);
   miPersonaje.dibujarImagen(pantalla,aRecortar,0);
  }
  SDL_Flip(pantalla);
}
miPersonaje.borrarFrame();
limpieza(pantalla);
return 0;
}

int main ( int argc, char** argv )
{
    return gameLoop();
}


este es el codigo de mi programa, y que minimamente me permite poder moverme entre los sprites de la primer fila, asi que si alguno desea aplicarle algun cambio, sientase libre de hacerlo, realmente esta es la parte que mas me complica de todo esto junto con todo lo que es el tiempo de ejecucion y demas cosas
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor carlostex » Vie Dic 31, 2010 9:16 am

Si esa es la forma en la que se acostumbra trabajar con sprites que tienen varios frames.
Como dices el problema es que la imagen no es de tamaño uniforme lo cual implica que tienes que declarar el tamaño y posición de cada frame.
como es mejor trabajarlo, bueno estas usando C++, hay que aprovecharlo usando encapsulación y clases especializadas, es la forma en la que yo lo acostumbro.
La clase que maneja los sprites debería ser la encargada de controlar la animación, y esta estará embebida en la clase personaje.
la clase sprite podría ser así:
Código: Seleccionar todo
class sprite
{
      frame
      ancho_sprite
      alto_sprite
      columnas_del_frame
      filas_del_frame
      sprite_actual
      dibuja_sprite(superficie_destino)
      establece_sprite(numero_del_sprite)
      carga_frame(archivo)
}

es una idea sin meterse en declaraciones formales de c y sdl, como veras es fácil, quizás requiere de algunas funciones mas para la gestión del frame, pero tiene la ventaja que no usa memoria extra para almacenar un sprite, si no que la función dibujar copia el frame establecido a la superficie final que se muestra.
si el tamaño de los sprites fuera fijo por ejemplo 64*64 y tendría una matriz de 3*3 sprite sería tan sencillo calcular que parte copiar como sigue:
Código: Seleccionar todo
posicion_x=ancho_sprite*columnas_del_frame
posicion_y=alto_sprite*filas_del_frame

esas posiciones las pasas como parámetro a la función blit_surface en el argumento del rectángulo a copiar y listo.
El conocimiento de unos es conocimiento de todos.
Avatar de Usuario
carlostex
 
Mensajes: 249
Registrado: Mar Jul 14, 2009 4:13 am
Ubicación: mexico

Re: Movimiento de sprites

Notapor pablo9891 » Dom Ene 02, 2011 12:12 am

Cuando te referis a cargar todo por separado me estas diciendo de cargarlo en un array??

mi idea era la de en la clase frame que tengo, generar una matriz de 3*3 de tipo SDL_Surface sobre el cual voy a ir cargando pedazito por pedazito del sprite, cuando tenga que mover el sprite era simplemente moverme un espacio dentro de esa matriz y luego cargar ese pedazo
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor Juanxo » Dom Ene 02, 2011 1:28 am

lo normal en este caso es usar el clip rect a la hora de hacer un blit.

Código: Seleccionar todo
//dentro de la clase que tengas donde manejes la imagen ( Animacion, Sprite, Nave, etc)

void CambiarFrame(int frame)
{
  int x = frame % FRAMES_ANCHO;
  int y = frame / FRAMES_ANCHO;
 
  rect_frame.x = ANCHO_FRAME * x;
  rect_frame.y = ALTO_FRAME * y;
  rect_frame.width = ANCHO_FRAME;
  rect_frame.height = ALTO_FRAME;
}

void DibujarNave()
{
  // Esto no recuerdo si era así exactamente, pero lo que quiero decir es:
  //dibuja esto en la pantalla screen en la posición pos_nave y con el clip_rect rect_frame
  SDL_BlitSurface(screen, pos_nave, rect_frame);
}

...


El tema es que no hace falta dividir la imagen, simplemente cambiar el rectángulo de corte. Y en cuanto a lo de que no son del mismo tamaño, siempre suelen ser del mismo tamaño cada frame, o no te referías a eso?
Avatar de Usuario
Juanxo
 
Mensajes: 437
Registrado: Sab Ene 31, 2009 2:34 am
Ubicación: Madrid(España)

Re: Movimiento de sprites

Notapor carlostex » Dom Ene 02, 2011 2:09 am

si, en un juego quieres usar la menor memoria posible y los menores pasos, por eso no es bueno crear un array de imágenes, el problema que tienes es que esta imagen no es estántar, todos las imágenes que yo he visto de ese tipo tienen una separación igual que permite usar bien el clip rect, mi consejo es que busque otras imágenes.
El conocimiento de unos es conocimiento de todos.
Avatar de Usuario
carlostex
 
Mensajes: 249
Registrado: Mar Jul 14, 2009 4:13 am
Ubicación: mexico

Re: Movimiento de sprites

Notapor pablo9891 » Dom Ene 02, 2011 7:04 am

Entiendo sobre la parte de ir recortando el frame en pedazitos que son los que voy cargando en la pantalla, lo que no entiendo es en el caso de la navecita que tengo, cual es la mejor tecnica para hacer el recorte ya que tengo frames de diferentes tamaños y tampoco entiendo como hacer para relacionar el evento que ocurre, sea que se haya apretado la tecla para arriba, abajo o al costado y la carga del frame se me habia ocurrido que dependiendo de la tecla que se toco se pase un determinado valor a alguna funcion y desde ahi realizo la carga del frame, pero todavia son ideas que voy teniendo
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor carlostex » Dom Ene 02, 2011 7:30 am

pues podrías hacer un array de SDL_Rect que contenga los cuadrados a recortar y cuando quieras cambiar de frame le pasas el area que corresponde al indice del frame.
Para ir cambiando de frame pues efectivamente tiene que ser cuando cambia de dirección, osea cuando dobla o cuando avanza, parte de procesar ese evento va a ser cambiar al frame que quieres que aparezca en esa situación, podrías usar poolling cuando detectes que la tecla se pulso activas tal frame y cuando de desaprete pones el frame del estado estático
El conocimiento de unos es conocimiento de todos.
Avatar de Usuario
carlostex
 
Mensajes: 249
Registrado: Mar Jul 14, 2009 4:13 am
Ubicación: mexico

Re: Movimiento de sprites

Notapor pablo9891 » Lun Ene 03, 2011 3:25 am

Imagen

acabo de conseguir esta imagen, lo que me esta complicando es la forma en la que puedo determinar la posicion X e Y sobre las que comenzar a dibujar el sprite, en este caso son todos mas o menos del mismo tamaño
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor carlostex » Lun Ene 03, 2011 4:50 pm

A que te refieres con la posición con la que vas a dibujar?, supongo que ya leíste como se hace para recortar las áreas del frame que quieres
El conocimiento de unos es conocimiento de todos.
Avatar de Usuario
carlostex
 
Mensajes: 249
Registrado: Mar Jul 14, 2009 4:13 am
Ubicación: mexico

Re: Movimiento de sprites

Notapor pablo9891 » Lun Ene 03, 2011 7:19 pm

Obviamente que si, lo que quiero decir es que, yo se que por ejemplo tengo que definir el rectangulo sobre el cual voy a recortar, eso tiene una posicion X y una posicion Y, el tema es como defino esa posicion sobre la cual voy a comenzar a recortar para luego colocar sobre la pantalla, el calculo que tengo que hacer, o sea vos ya me diste una idea

posicion_x=ancho_sprite*columnas_del_frame
posicion_y=alto_sprite*filas_del_frame


pero esto es asi nomas?? o necesito algo mas???, eso es lo que no entiendo
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor Juanxo » Lun Ene 03, 2011 7:50 pm

si, con eso te valdría
Mirate la función que te puse arriba, que te pasa de un frame que le pidas a la posición que necesitas
Avatar de Usuario
Juanxo
 
Mensajes: 437
Registrado: Sab Ene 31, 2009 2:34 am
Ubicación: Madrid(España)

Re: Movimiento de sprites

Notapor pablo9891 » Lun Ene 03, 2011 8:14 pm

con el frame que le paso a la funcion te referis a un numero para el frame, es decir cada uno de los frames tiene un numero de 1 a 16 en este caso?
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor Juanxo » Lun Ene 03, 2011 8:32 pm

si, pero acuerdate que como casi todo en programación, empieza en 0
Avatar de Usuario
Juanxo
 
Mensajes: 437
Registrado: Sab Ene 31, 2009 2:34 am
Ubicación: Madrid(España)

Re: Movimiento de sprites

Notapor pablo9891 » Jue Ene 06, 2011 5:35 am

Finalmente pude resolver el problema, pero tengo una duda acerca de la solucion que elabore, ya que me parece que no es de lo mas optima

Esta es la funcion que arme para determinar el numero de frame siguiente en base al frame actual, para poder armar la secuencia de frames que van a hacer que el personaje se mueva, lo que quiero saber es si se puede elaborar algo mas simple, les dejo la funcion:

Código: Seleccionar todo
int nuevoFrame(int accion,int numFrame)
{
  int val = numFrame;

  switch(accion)
  {
   case 1:

    switch(getNfil())//ARRIBA
    {
     case 0:
      setNcol(2);
      setNfil(3);
      val = 14;
      break;

     case 1:
     case 2:
      setNcol(2);
      setNfil(3);
      val = 14;
      break;

     case 3:

      if(getNcol()<=2)
      {
       setNcol(getNcol()+1);
       val = numFrame+1;
      }
      else
      {
       setNcol(0);
       val = 12;
      }

      break;
    }

    break;
   case 2:

    switch(getNfil())//ABAJO
    {
     case 0:

      if(getNcol()<=2)
      {
       setNcol(getNcol()+1);
       val = numFrame+1;
      }
      else
      {
       setNcol(0);
       val = 0;
      }

      break;
     case 1:
     case 2:
      setNcol(2);
      setNfil(0);
      val = 2;
      break;
     case 3:
      setNcol(2);
      setNfil(0);
      val = 2;
      break;
    }

    break;
   case 3:

    switch(getNfil())//DERECHA
    {
     case 0:
     case 1:
     case 3:
      setNcol(2);
      setNfil(2);
      val = 10;
      break;
     case 2:

      if(getNcol()<=2)
      {
       setNcol(getNcol()+1);
       val = numFrame+1;
      }
      else
      {
       setNcol(0);
       val = 8;
      }

      break;
    }

    break;
   case 4:

    switch(getNfil())//IZQUIERDA
    {
     case 0:
     case 3:
     case 2:
      setNcol(1);
      setNfil(1);
      val = 4;
      break;
     case 1:

      if(getNcol()<=2)
      {
       setNcol(getNcol()+1);
       val = numFrame+1;
      }
      else
      {
       setNcol(0);
       val = 4;
      }

      break;
    }

    break;
  }

  return val;
}


Basicamente la idea es que con el numero de frame actual y el movimiento que se realiza pueda determinar cual es el siguiente frame que se va a tener que cargar, me gustaria saber que les parece y si se puede cambiar algo
pablo9891
 
Mensajes: 32
Registrado: Lun Dic 28, 2009 2:48 am

Re: Movimiento de sprites

Notapor Juanxo » Jue Ene 06, 2011 12:47 pm

creo que te has complicado demasiado.

Lo mejor es dividir el tema, entre una función que cambie al siguiente frame dentro del mismo loop y otra funcion que cambie el tipo de acción a realizar:

Código: Seleccionar todo

// Esto se lo podrías pasar por parametro a la hora de construir el sprite,
// para poder utilizar cualquier valor en diferentes sprites
int const NUM_FRAMES_ANCHO = 4;
int const NUM_FRAMES_ALTO = 4;
int const ANCHO_FRAME = X; // Aquí pones el ancho de cada frame
int const ALTO_FRAME = Y; // Aquí pones el alto de cada frame

enum Acciones
{
   Accion_Abajo,
   Accion_Izquierda,
   Accion_Derecha,
   Accion_Arriba
};

int cambiarAccion(int accion)
{
   assert(accion < NUM_FRAMES_ALTO);
   clip_rect.x = 0; // Nos ponemos en el primer frame del loop
   clip_rect.y = accion * ALTO_FRAME;
}

int siguienteFrame(int numFrame)
{
   int fila_actual = numFrame / NUM_FRAMES_ANCHO;
   int columna_actual = numFrame % NUM_FRAMES_ANCHO;
   
   int nueva_columna = columna_actual + 1;
   
   // Si nos hemos pasado, volvemos a la primera columna, para hacer un loop
   if (nueva_columna >= NUM_FRAMES_ANCHO)
      nueva_columna = 0;
      
   clip_rect.x = nueva_columna * ANCHO_FRAME;
   //En teoría esto no hace falta, ya que no hemos cambiado de fila
   // por lo que el valor que tuviera almacenado debería ser válido
   clip_rect.y = fila_actual * ALTO_FRAME;
}


/* El tema ahora seria llamar cada vez que quieras
pasar al siguiente frame (una vez cada segundo o lo que sea)
llamas a siguienteFrame. Otra cosa que te recomendaría es que
guardaras la columna o el frame actual dentro de la clase, para
no tener que pasarselo cada vez a siguienteFrame.

Y cuando quieras cambiar de accion: */

if (se ha pulsado tecla derecha)
   Caballero.cambiarAccion(Accion_Derecha);
elif (se ha pulsado tecla izquierda)
   Caballero.cambiarAccion(Accion_Izquierda);
Avatar de Usuario
Juanxo
 
Mensajes: 437
Registrado: Sab Ene 31, 2009 2:34 am
Ubicación: Madrid(España)


Volver a Sobre las bibliotecas multimedia

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado