Sistema de particulas

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

Sistema de particulas

Notapor sofoke » Mié Mar 11, 2009 9:00 pm

He estado varias horas tratando de crear un sistema de particulas.
algo como un efecto de lluvia, nieve, etc... pero no se me ocurre como se logra tal efecto's'
Imagine que se podria con SDL_gfx dibujando tal vez algunos puntos como base..
Pero entonces mi duda surge: ¿Como se dibujan tales puntos con esa libreria?
O si hay una mejor forma me gustaria me ayudaran...
NOTA: estoy usando C++ y SDL...
...cuando lo popular no es suficiente...
Gnu-Linux-y-Más
Avatar de Usuario
sofoke
 
Mensajes: 102
Registrado: Jue May 24, 2007 8:10 pm
Ubicación: México

Notapor Juanxo » Mié Mar 11, 2009 11:20 pm

Buenas Sofoke:

No se si lo habras visto, pero en la sección de ejemplos hay un efecto de nieve creado por hugo que, aunque está hecho en python, te podrá dar ideas de como conseguirlo.

Un saludo
Avatar de Usuario
Juanxo
 
Mensajes: 437
Registrado: Sab Ene 31, 2009 2:34 am
Ubicación: Madrid(España)

Notapor sofoke » Mié Mar 11, 2009 11:50 pm

Gracias por responder...
y si lo he checado pero estaba buscando algo mas simple como un manual o tutorial que indice como hacerlo desde cero...
...cuando lo popular no es suficiente...
Gnu-Linux-y-Más
Avatar de Usuario
sofoke
 
Mensajes: 102
Registrado: Jue May 24, 2007 8:10 pm
Ubicación: México

Notapor hugoruscitti » Mié Mar 11, 2009 11:57 pm

Hace un buen tiempo hicimos una propuesta de programación
sobre partículas:

http://www.losersjuegos.com.ar/referenc ... particulas

Ahí vas a encontrar varios ejemplos de efectos como lluvias, nieve
y otros, espero te resulte útil.

Saludos.
Avatar de Usuario
hugoruscitti
Site Admin
 
Mensajes: 1242
Registrado: Dom Jul 30, 2006 3:57 am
Ubicación: Buenos Aires, Argentina

Notapor lacabra25 » Jue Mar 19, 2009 5:02 pm

Dado que SDL solo trabaja en 2D las particulas no seran mas que los pixeles de la pantalla (o un conjunto de estos formando cuadrados pequeños o circulos pequeños), para empezar hay que comenzar por como se estudian los mivimientos (puesto que lo que podemos hacer unicamente es mover las particulas pues es lo que se va a ver en pantalla) en fisica y la respuesta es que con vectores, como SDL trabaja en 2D sera mas sencillo que en 3D puesto que los vectores solo tendran dos componentes, cada particula debera tener al menos un vector posicion y despues puedes hacer que cada particula tenga ademas un vector velocidad, incluso un vector aceleracion y ya subiendo la dificultad incluso una masa y vectores de fuerza. Ahora es cuestion de aplicar la matematicas y la fisica a las particulas y calcular el nuevo vector de posicion, y las nuevas propiedades de la particula en cada momento, como interactuan unas con otras, que comportamiento deberan tener.... Lo siguiente es que dependiendo del tipo de particula que quieras hacer (lluvia, fuego, arena, ...) decidas si representar la particula como un pixel, como un punto de varios pixeles, como una raya.... Ahora a dibujar las particulas, si no vas a usar imagenes para hacer las particulas (me refiero a imagenes en archivos externos al programa, lo cual seguramente permitira una mayor flexibilidad del sistema de particulas) una opcion es crear una superficie y dibujar en ella pixel a pixel o dibujando pequeños rectangulos la particula y usar esta superficie como particula (de este modo todas las particulas serian iguales y solo tendrias que hacer un blitting a la pantalla en las coordenadas que le correspondan a la particula) este metodo es una buena opcion cuando todas las particulas sean iguales (arena por ejemplo) pero si las particulas son para, por ejemplo, un fuego cada una debera tener un color entre amarillo y rojo diferente (un fuego no es solo rojo o solo amarillo, tiene tonos naranjas...) una opcion es dibujar directamente en la superficie de la pantalla las particulas dibujando los pixeles que sean necesarios (aqui es necesario o usar doble buffer para evitar el parpadeo o antes copiar la superficie de la pantalla a otra superficie, tambien deberas tener cuidado con el codigo para dibujar las particulas para que compruebe lo mas rapido posible todas las particulas y las dibuje tambien lo mas rapido posible, contra menos codigo y mas rapido se ejecute el codigo mejor por lo que habra variables que, por ejemplo, en vez de int deberan ser register int...).

Espero que esto te pueda ayudar con el sistema de particulas. Aprovecho para decirte que para poder comprobar el tiempo que tarda en ejecutarse cada funcion y las veces que es llamada (por lo que te comentaba de la necesidad de que los pixeles de las particulas estuviesen dibujados en el menor tiempo posible) puedes usar el profiler: http://www.chuidiang.com/clinux/herrami ... ofiler.php

Edito: no me acuerdo si era en los ejemplos o donde era pero me parece que en uno de los ejemplos hay funciones para dibujar un pixel de un color determinado en una superficie en las coordenadas que se quiera.

Código: Seleccionar todo
int reemplazar_color(SDL_Surface *src, Uint32 remover, Uint32 reemplazo){
   register unsigned short int b;
   register unsigned int x, y;
   b= SDL_MUSTLOCK(src);
   if(b == 1){
      if(SDL_LockSurface(src) < 0){
         return 0;
      }
   }
   for(x = 0; x <src>w; x++){
      for(y = 0; y <src>h; y++){
         if(obtener_pixel(src, x, y) == remover){
            colocar_pixel(src, x, y, reemplazo);
         }
      }
   }
   if(b == 1){
      SDL_UnlockSurface (src);
   }
   return 0;

}



int colocar_pixel(SDL_Surface *src, int x, int y, Uint32 pixel){

    register unsigned short int b;

    b= SDL_MUSTLOCK(src);

    if(b == 1){

         if(SDL_LockSurface(src) <0>format->BytesPerPixel;

    Uint8 *p = (Uint8 *)src->pixels + y * src->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;

    }

    if(b == 1){

         SDL_UnlockSurface (src);

    }

    return 0;

}



Uint32 obtener_pixel(SDL_Surface *src, int x, int y){

       int bpp = src->format->BytesPerPixel;

       Uint8 *p = (Uint8 *)src->pixels + y * src->pitch + x * bpp;

       switch(bpp){

                   case 1: return *p;

                        break;

                   case 2: return *(Uint16 *)p;

                        break;

                   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;

                        break;

                   case 4: return *(Uint32 *)p;

                        break;

                   default: return 0;

                            break;

       }

}


Hay tienes las funciones necesarias para colocar pixeles en una superficie que las obtuve de algun ejemplo o algun codigo de losers juegos y tambien las vi en un manual y entre un codigo y otro y algunas cosas que creo que cambie consegui esas tres funciones que tenia guardadas en el disco duro. Como veras algunas variables se declaran como regoster para que si es posible se guarden en los registros de la CPU para que el acceso a ella sea mas rapido y las funciones son cortas y con poco codigo y usando punteros.
Esta cuenta ahora a pasado a la cuenta jhg
Avatar de Usuario
lacabra25
 
Mensajes: 222
Registrado: Mié Abr 02, 2008 9:45 pm
Ubicación: Tenerife (España)

Notapor sofoke » Jue Mar 19, 2009 6:59 pm

Buenas y gracias por la ayuda a todos...
Ahora con respecto a lo ultimo (lacabra25) no he tenido oportunidad de probar aun las funciones que propones... me surgio una duda lo que hacen estas funciones es escojer un pixel de pantalla y cambiarlo de color? me refiero a que si selecciona por ejemplo un pixel que ya se la ha asignado 'x' color y asignarle un 'y' color....
Tambien suena interesante eso de crear una superficie con un pixel 'x' y copiarla a la superficie principal en las coordenadas donde se desee, no habia pensado en eso pero igual suena bueno...
Yo imaginaba algo como una capa en el juego exclusiva para dibujar el sistema de particulas, por decir tomar 'x' posicion en pantalla y crear ahi el pixel de 'y' color, pero imagino el problema vendria al querer mover ese pixel...
Estare checando el codigo que me parece muy bueno, tambien he bajado los ejemplos de la web (losersjuegos claro) pero aun no me queda muy claro como es que lo logran...
...cuando lo popular no es suficiente...
Gnu-Linux-y-Más
Avatar de Usuario
sofoke
 
Mensajes: 102
Registrado: Jue May 24, 2007 8:10 pm
Ubicación: México

Notapor lacabra25 » Jue Mar 19, 2009 7:19 pm

Si, la una de las tres funciones se encarga de cambiar un pixel del color que tenga a un color que queramos. El codigo de todas formas revisalo por que hace bastante tiempo que no lo reviso ni lo compilo y aunque en principio no deberia dar fallos no puedo estar seguro despues de tanto tiempo sin usarlo. El codigo basicamente lo que hace es bloquear la superficie si es necesario (esto lo saque de el tutorial de la libreria SDL de la seccion de libros), se hace apuntar un puntero a la zona de memoria donde esta el pixel que se quiere cambiar y ,dependiendo de los bytes por pixel, cambia el valor del pixel y, si es necesario, desbloquea la superficie.
Esta cuenta ahora a pasado a la cuenta jhg
Avatar de Usuario
lacabra25
 
Mensajes: 222
Registrado: Mié Abr 02, 2008 9:45 pm
Ubicación: Tenerife (España)

Notapor endaramiz » Jue Mar 19, 2009 9:48 pm

Tengo una duda con el código:
Código: Seleccionar todo
for(x = 0; x <src>w; x++){

En concreto con el 'x <src>w'. Es la primera vez que lo veo. Y por internet no veo nada.

Por cierto, si se compila con optimización del código, creo que el compilador hace automáticamente lo de las variables register. Sería cuestión de probarlo...

Saludos.

EDIT:
lacabra25 escribió:no me acuerdo si era en los ejemplos o donde era pero me parece que en uno de los ejemplos hay funciones para dibujar un pixel de un color determinado en una superficie en las coordenadas que se quiera.

Correcto:
- Capítulo 1 del libro de RCAF
- Ejemplos de gráficas de Carlos Gabriel Valentin
- Artículo del rectángulo con las esquinas redondeadas
- Ejemplo de colisión de copos de nieve (pygame)
- ...
Avatar de Usuario
endaramiz
 
Mensajes: 283
Registrado: Vie Ago 31, 2007 9:25 am
Ubicación: Barcelona

Notapor Juan Carlos » Vie Mar 20, 2009 2:42 pm

Hola, creo que:
Código: Seleccionar todo
x <src>w

en realidad deberia escribirse como:
Código: Seleccionar todo
x < src->w

Creo que tiene mas sentido.

Saludos
Juan Carlos
 
Mensajes: 97
Registrado: Sab Jul 07, 2007 1:05 pm

Notapor sofoke » Vie Mar 20, 2009 9:29 pm

Me surgio una duda mas...
ya creada una superficie para almacenar el efecto, ahora como hago el blit sobre la superficie principal, es decir; como pego la superficie creada en la superficie principal?...
[EDITO] Ya he logrado hacerlo
Ahora mi otra duda es, cual es la parte concreta (segun el codigo arriba) para dibujar un pixel...¿?
...cuando lo popular no es suficiente...
Gnu-Linux-y-Más
Avatar de Usuario
sofoke
 
Mensajes: 102
Registrado: Jue May 24, 2007 8:10 pm
Ubicación: México

Notapor Geo » Sab Mar 21, 2009 12:05 am

Todo está dentro de la función colocar_pixel, lo que hace es colocar los valores que recibe en la posición adecuada de memoria, de acuerdo al número de bytes que representan cada pixel en el modo que se está trabajando. Por ejemplo,

Código: Seleccionar todo
Uint8 *p = (Uint8 *)src->pixels + y * src->pitch + x*bpp;

Esto nos da la dirección del pixel.

Supongamos que trabajamos en modo de 24 bits (3 bytes por pixel).

El valor de pixel que pasamos es de 4 bytes (Uint32), ordenados así: XRGB.
Para representar esas tres componentes en una máquina big endian, esos valores se colocan en memoria de esta forma: RGB.
Mientras que en una máquina little endian, quedarían así: BGR.

Lo que el código dentro de case 3 hace es colocar el valor de pixel en memoria en el orden correcto. Fíjate que, para p[ 1 ], el código es exactamente igual (B queda enmedio en ambos casos).
La imaginación es el límite.
Visita mi blog en inglés o en español.
Geo
 
Mensajes: 244
Registrado: Jue Ago 10, 2006 3:51 am
Ubicación: México


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

cron