//particle.h
#include <allegro.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
int random(float bound1, float bound2)
{
float scale = rand() / float(RAND_MAX);
float output = ceil(scale * (bound2 - bound1) + bound1);
return int(output);
}
class PARTICLE
{
private:
float angle;
float speed;
int x_comp;
int y_comp;
int x;
int y;
int life;
int r;
int g;
int b;
bool visible;
int iteration_counter;
public:
void initialize(float uangle, float utolerance, float uspeed, int ulife, int ux, int uy, int uR, int uG, int uB, bool uvisible)
{
speed = uspeed;
life = ulife;
x = ux;
y = uy;
float bound1 = uangle - (utolerance / 2);
float bound2 = uangle + (utolerance / 2);
angle = random(bound1, bound2);
if(angle > 360)
{
angle -= 360;
}
if(angle < 0)
{
angle += 360;
}
x_comp = int(ceil(cos(angle)*speed));
y_comp = int(ceil(sin(angle)*speed));
if(angle > 270 || (angle > 90 && angle < 180))
{
x_comp = -x_comp;
y_comp = -y_comp;
}
r = uR;
g = uG;
b = uB;
visible = true;
iteration_counter = 1;
}
void update()
{
if(visible == true)
{
x += x_comp;
y += y_comp - 2;
iteration_counter++;
}
if(iteration_counter >= life)
{
visible = false;
}
}
void blit(BITMAP *buffer)
{
if(visible == true)
{
rectfill(buffer, x, y, x+2, y+2, makecol(r, g, b));
}
}
};
class PARTICLE_MANAGER
{
private:
float angle;
float tolerance;
float speed;
int x;
int y;
int particle_life;
int spawn_rate;
int r;
int g;
int b;
int stream_counter;
int num_used;
PARTICLE stream[999];
public:
void initialize(int ux, int uy, float uangle, float utolerance, float uspeed, int uparticle_life,
int uspawn_rate, int ur, int ug, int ub)
{
x = ux;
y = uy;
angle = uangle;
tolerance = utolerance;
speed = uspeed;
particle_life = uparticle_life;
spawn_rate = uspawn_rate;
r = ur;
g = ug;
b = ub;
stream_counter = 0;
num_used = 0;
int counter;
for(counter = 0; counter < 1000; counter++)
{
stream[counter].initialize(angle, tolerance, speed, particle_life, x, y, r, g, b, false);
}
}
void update()
{
if(num_used >= 999 - spawn_rate)//so we don't go over 999
{
num_used = 0;
}
int counter;
for(counter = num_used; counter <= counter + spawn_rate; counter++)
{
stream[counter].initialize(angle, tolerance, speed, particle_life, x, y, r, g, b, true);
}
num_used += spawn_rate;
for(counter = 0; counter <= 999; counter++)
{
stream[counter].update();
}
}
void blit(BITMAP *buffer)
{
int counter;
for(counter = 0; counter <= 999; counter++)
{
stream[counter].blit(buffer);
}
}
};
//main.cpp
#include <allegro.h>
#include "particle.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
volatile long counter = 0;
void IncFps()
{
counter++;
}
int main()
{
/* Initialization */
allegro_init();
install_keyboard();
install_timer();
install_mouse();
install_sound( DIGI_AUTODETECT, MIDI_AUTODETECT, 0 );
set_color_depth( 16 );
bool fullscreen = false;
LOCK_VARIABLE( counter );
LOCK_FUNCTION( IncFps );
install_int_ex( IncFps, BPS_TO_TIMER(60) );
if ( fullscreen == true ) // For fullscreen
set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0);
else // For windowed
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
PARTICLE_MANAGER stream;
stream.initialize(100, 100, float(1), float(30), float(2), 120, 1, 255, 0, 0);
BITMAP *buffer = create_bitmap( 640, 480 );
/* End Initialization */
/* Game loop and such would go here */
while ( !key[KEY_ESC] )
{
while(counter > 0)
{
stream.update();
counter -= 1;
}
/* Draw functions */
stream.blit(buffer);
blit( buffer, screen, 0, 0, 0, 0, 640, 480 );
clear_bitmap( buffer );
}
/* Free memory afterwards! */
destroy_bitmap( buffer );
return 0;
}
END_OF_MAIN();
Simple Particle Effect Error
I know that this is probably an incredibly simple error on my part, but I cannot get this particle effect to run for me. It is in allegro and is divided between "particle.h" and "main.cpp" There is a particle class that takes care of holding values for a single particle, updating a single particle, and blitting a single particle. There is also a particle manager class that holds the data for a stream of particles, such as coordinates, angle, width (in degrees) of stream, spawn rate per frame of particles, speed of particles, and life of particles, as well as holding an array of 1000 particles and updating and blitting them. Also included is a function to simplify random number generation.
When I compile everything it runs, but then exits after about a second. If I remove the update function from the game loop, it draws a single particle and does nothing else, but when I try to exit, the program has an error. Could somebody please help me find the error in this?
Can you edit your post to use [source] .. [/source] tags, so the code is easier to read?
What is the error you get if the update function is removed?
What is the error you get if the update function is removed?
The error is that, obviously it doesn't update, but it 1) blits the particles even though it shouldn't and 2) makes an error window when I close out, but it doesn't seem to actually cause any major errors. The same error occurs, minus the particle, when I remove the blit AND update functions.
thanks in advance
thanks in advance
Yes, but what does that 'error window' actually say? :)
Anyway, the iteration range on this loop looks wrong:
Try changing it to:
To solve the particles being blitted when they're not meant to be, try adding a constructor to PARTICLE that initializes its visible member to false:
Really the class should have all its setup completed in the constructor, and not have particles pre-allocated in a zombie state, but oh well, it's a start.
Anyway, the iteration range on this loop looks wrong:
for(counter = num_used; counter <= counter + spawn_rate; counter++)
Try changing it to:
for(counter = num_used; counter < num_used + spawn_rate; counter++)
To solve the particles being blitted when they're not meant to be, try adding a constructor to PARTICLE that initializes its visible member to false:
PARTICLE() : visible(false) { }
Really the class should have all its setup completed in the constructor, and not have particles pre-allocated in a zombie state, but oh well, it's a start.
YES!!! The constructor for the particle class worked; The error message still pops up when trying to exit though. All it says is particle.exe has stopped working. As to the constructors, the initialization functions were constructors originally, but then I realized that I had no idea how to do constructors with arrays. It's not perfect but they actually update now. The gravity and the range of the angle (tolerance) do not seem to be working, though.
P.S. The range was also a part of it
P.S. The range was also a part of it
Try upping the number of particles allocated from 999 to 1000:
PARTICLE stream[999 1000];
You have some other loops in there which expect it to be 1000.
PARTICLE stream[999 1000];
You have some other loops in there which expect it to be 1000.
Nope, no change, but your system of problem solving is really helping me see how I can debug these things. Do you think it might help to turn my initializations into constructors? I could record it and post a youtube video if you think that would help?
I changed a couple of things around in the particle manager initialization, and it closes properly now. Now I just have to get the range of the angle to work properly.
Thank you for all of your help
update: I tracked it down to a math error with the particle speed. Darn you, trig!
I changed a couple of things around in the particle manager initialization, and it closes properly now. Now I just have to get the range of the angle to work properly.
Thank you for all of your help
update: I tracked it down to a math error with the particle speed. Darn you, trig!
Yup, it would help to have proper constructors.
Here, I C++'d your code up a bit:
EDIT: Ah, good to hear you got it working.
Here, I C++'d your code up a bit:
#include <vector>class PARTICLE{private: float angle; float speed; int x_comp; int y_comp; int x, y; int life; int r, g, b; int iteration_counter;public: PARTICLE(float angle, float tolerance, float speed, int life, int x, int y, int r, int g, int b) : speed(speed), life(life), x(x), y(y), r(r), g(g), b(b), iteration_counter(1) { float bound1 = angle - (tolerance / 2); float bound2 = angle + (tolerance / 2); angle = random(bound1, bound2); if(angle > 360) angle -= 360; if(angle < 0) angle += 360; x_comp = int(ceil(cos(angle)*speed)); y_comp = int(ceil(sin(angle)*speed)); if(angle > 270 || (angle > 90 && angle < 180)) { x_comp = -x_comp; y_comp = -y_comp; } } bool update() // returns true if particle should stay alive, otherwise false { x += x_comp; y += y_comp - 2; return ++iteration_counter < life; } void blit(BITMAP *buffer) const { rectfill(buffer, x, y, x+2, y+2, makecol(r, g, b)); }};class PARTICLE_MANAGER{private: const size_t max_particles; const float angle; const float tolerance; const float speed; const int x, y; const int particle_life; const int spawn_rate; const int r, g, b; typedef std::vector<PARTICLE> Stream; Stream stream;public: PARTICLE_MANAGER(int x, int y, float angle, float tolerance, float speed, int particle_life, int spawn_rate, int r, int g, int b, size_t max_particles) : x(x), y(y), angle(angle), tolerance(tolerance), speed(speed), particle_life(particle_life), spawn_rate(spawn_rate), r(r), g(g), b(b), max_particles(max_particles) { } void update() { for(int i = 0; i < spawn_rate && stream.size() < max_particles; ++i) stream.push_back(PARTICLE(angle, tolerance, speed, particle_life, x, y, r, g, b)); Stream::iterator it = stream.begin(); while(it != stream.end()) if(it->update()) ++it; else it = stream.erase(it); } void blit(BITMAP *buffer) const { for(int i = 0; i < stream.size(); ++i) stream.blit(buffer); }};
EDIT: Ah, good to hear you got it working.
Yes, this is really good; I noticed two things, 1) I accidentally subtracted with the y component for gravity and, 2) I changed the x and y components into floats so it would make the speeds better, but I realized that there must be something really wrong with my trig. Could you look at that and tell me if you think there's something wrong with it? The speed actually controls the shape of the stream, somehow.
Well, trig. functions like sin and cos take their angle argument in radians, not degrees. Try converting them:
const float PI = 3.1415926f;
x_comp = int(ceil(cos(angle*PI/180)*speed));
y_comp = int(ceil(sin(angle*PI/180)*speed));
const float PI = 3.1415926f;
x_comp = int(ceil(cos(angle*PI/180)*speed));
y_comp = int(ceil(sin(angle*PI/180)*speed));
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement