Jump to content
  • Advertisement
Sign in to follow this  
rubiksnut

Simple Particle Effect Error

This topic is 3210 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.
//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();


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?

Share this post


Link to post
Share on other sites
Advertisement
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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Yes, but what does that 'error window' actually say? :)

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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
Yup, it would help to have proper constructors.

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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));

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!