Sistema de Partículas III : Rendering
- Sin considerar ninguna paleta
No voy a considerar ninguna paleta, por ahora almenos...En el sistema inicial las explosiones siempre las hice rojas con chispitas negras al final...Se ajusta a mi manera de dibujar XD. Es muy fácil usar una paleta, pero no tan fácil es modelarla, hay que probar y probar viendola en pantalla hasta que quede bien. Hasta ahora he probado estas implementaciones con la paleta anterior (rojo y negro) y con una que saqué de "All about color palettes, Chapter 8" ; no sé el nombre del libro, pero los fascículos están muy buenos y completos, tiene todo sobre programación gráfica en 2D.
- Explosiones: ejemplo
Para modelar explosiones usamos los algoritmos de setup y movimiento de partículas vistos en el cap. 2, modificando los siguientes parámetros:
- gravedad: +3.5
- considerar: muertes y sistema muerto
Considerar muertes implica asegurar que luego de que una partícula queda pegada a una superficie (al piso por ejemplo) ya no se la esté intentando mover. El sistema está muerto cuando todas las partículas están muertas. Si esto no se controla, al finalizar la explosión el sistema seguirá chupando recursos innecesariamente.
Para los ejemplos usé 10.000 partículas, la resolución que usé es 320x200. Este sistema en su pico máximo (todas las partículas vivas) consume 3480 KB (sí, un disparate). Este mismo sistema a una resolución de 800x600 consume 4716 KB. El motor influye mucho en el rendimiento, y también la forma de usarlo. Notar que el sistema es estático, o sea que con 'pico máximo' me refiero a poca diferencia con pico mínimo. Una vez mas...es recomendable implementarlo de forma dinámica.
Esta es la función que usé para ver las partículas:
void putpixel(SDL_Surface *screen, int x, int y, Uint32 color)
{
// Determinamos posición de inicio
char *buffer=(char*) screen->pixels;
// Calculamos offset para y
buffer+=screen->pitch*y;
// Calculamos offset para x
buffer+=screen->format->BytesPerPixel*x;
// Copiamos el pixel
memcpy(buffer, &color, screen->format->BytesPerPixel);
}
Explosión con pixeles: (10.000 partículas)
Explosión usando 1.000 partículas:
- Que venga la sangre!!!
Con este algoritmo generar cascadas, salpicones, etc. de sangre es muy fácil, y va muy bien :D. En cascada:
No se nota mediante shots, pero hay un leve rebote antes de terminar de caer.
Lo mejor de todo, es la vagancia de implementar la sangre, simplmente hice las siguientes modificaciones:
-> gravedad = +3.5
-> las partículas mueren cuando alcanzan la coordenada y=180
Como vimos en el capítulo 2, considerabamos choques con las superficies. Por lo tanto al existir gravedad, se genera una serie de rebotes descendentes, acabando las partículas muertas en el piso. Si no se considerara las colisiones con el piso, las partículas mueren apenas alcancen la coordenada y=180 , esto sería ideal para cuando la sangre cae de una ventana o algo así...sin tocar piso o nada en su camino.
- Obtener otras orientaciones
Ejemplo:
// olvidemos la clase vector por un instante
// sinó no me da el espacio ;)
// coordenadas de inicio
// si hubiese que modelar lluvia
// sería y=0, x= rand()%320
particles[i].x = float(rand()%2+ 160);
particles[i].y = float(rand()%2+ 100);
// para obtener direcciones a gusto
// hay que modificar los ángulos de
// salida
// generamos ángulo pseudoaleatorio
// en grados y lo pasamos a radianes
int grade = rand()% 360;
float angle = (float) grade/180 * 3.1416;
// incializamos velocidad
float vel = 4.0f;
// generamos el vector dirección
particles[i].dirx = sin(angle) * vel;
particles[i].diry = cos(angle) * vel;
Notar que hemos cambiado la forma de disparar las partículas respecto de lo visto en el capítulo 2. Ambas formas funcionan, es decir, mediante ángulos y mediante valores pseudoaleatorios, sin embargo con el segundo método aparecen 2 lineas perpendiculares en el centro de explosión, y se debe a que en esas rectas no hay partículas viajando porque sus valores iniciales no pertenecen a la recta. Las rectas no son de partículas en sí, son de vacío, es decir, el conjunto de partículas explota y deja espacios vacíos alrededor de esas rectas. En fin, es solo un detalle, pero para más calidad usar ángulos para incializar las direcciones.
- Dibujando las partículas
void Draw_Particle(particle *aparticle)
{
long x, y;
// pasando las coordenadas a enteros...
x = (long)(aparticle->x);
y = (long)(aparticle->y);
// color rojo, no hay paleta
Uint32 c=SDL_MapRGB(pantalla->format,255,0,0);
// dibujamos la partícula en pantalla
putpixel(paux,x,y,c);
}
- Dinámica en pantalla
SDL_FillRect(pantalla, 0, SDL_MapRGB(pantalla->format, 0, 0, 0));
// dibujar partículas
Draw_Particles(particles);
// doble buffer
SDL_BlitSurface(paux, 0, pantalla, &dstrect);
// mover partículas
Move_Particles(particles);
// actualizar
SDL_Flip(pantalla);
Esto es todo por el capítulo 3...Quedan muchos efectos, aunque después de hacer 2 o 3 y entender la dinámica es fácil imaginarse otros efectos con tan solo modificar parámetros y colores. Una mejora que vale la pena es considerar una paleta de colores.