Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Particle Panic!

This thread is locked; no one can reply to it. rss feed Print
Particle Panic!
ngiacomelli
Member #5,114
October 2004

[EDIT: first question removed! (Stupid, stupid, stupid!)]

Now, my second question (particle panic!) involves linked-lists which I have had absolutely no experience with. My program has been freezing occasionally since I added the particle engine. Which seems to me like it's a memory leak. I just wanted to know if this looked alright before I dived into really hunting it down:

particle.h:

typedef struct part_list{

    double x, y, z;
    double dx, dy, dz; // direction
    double rx, ry, rz; // randomness
    double tx, ty, tz; // last location
        
    int visible, life, birth;
    
    struct part_list *next;
    
}particle_list;

particle.c:

1void update_particles()
2{
3
4 int r_x, r_y, r_z;
5
6 particle_list *tmp, *next;
7 for(tmp = p_head; tmp; tmp = next){
8 next = tmp->next;
9
10 if( tmp->life > 0 ) {
11
12 if( tmp->birth<=0 ) {
13
14 tmp->tx = tmp->x;
15 tmp->ty = tmp->y;
16 tmp->tz = tmp->z;
17
18 tmp->x += tmp->dx;
19 tmp->y += tmp->dy;
20 tmp->z += tmp->dz;
21
22 if(tmp->rx > 0) tmp->x += random_particle_direction((tmp->rx*2)) - tmp->rx;
23 if(tmp->ry > 0) tmp->y += random_particle_direction((tmp->ry*2)) - tmp->ry;
24 if(tmp->rz > 0) tmp->z += random_particle_direction((tmp->rz*2)) - tmp->rz;
25
26 tmp->life--;
27
28 if(tmp->life<=0) tmp->visible=0;
29
30 } else {
31
32 tmp->birth--;
33
34 if(tmp->birth==0) tmp->visible=1;
35
36 }
37
38 }
39
40 }
41
42 clean_particle_tree();
43 
44}
45 
46void clean_particle_tree() {
47 
48 particle_list *tmp, *next;
49 for(tmp = p_head; tmp; tmp = next){
50
51 next = tmp->next;
52 
53 if(tmp->life <= 0) {
54 delete_particle_node(tmp->x, tmp->y, tmp->z);
55 }
56 
57 }
58 
59}
60 
61void render_particles() {
62
63 particle_list *tmp, *next;
64 for(tmp = p_head; tmp; tmp = next){
65
66 next = tmp->next;
67
68 if(tmp->visible)
69 render_object (buffer, particle, camera.angle, camera.x + itofix(tmp->x), camera.y + itofix(tmp->y), camera.z - itofix(tmp->z), camera);
70 
71 }
72 
73}
74 
75void add_particle_node(int birth, int life,
76 int x, int y, int z,
77 int dx, int dy, int dz,
78 int rx, int ry, int rz
79 ){
80
81 particle_list *tmp = (particle_list *)malloc(sizeof(particle_list));
82 if(!tmp) return;
83
84 tmp->x = x; tmp->y = y; tmp->z = z;
85 tmp->dz = dz; tmp->dx = dx; tmp->dy = dy;
86 tmp->rx = rx; tmp->ry = ry; tmp->rz = rz;
87
88 tmp->birth = birth;
89 tmp->visible = 0;
90 tmp->life = life;
91 tmp->next = p_head;
92
93 p_head = tmp;
94
95}
96 
97void delete_particle_node(int x, int y, int z){
98
99 particle_list *tmp, *next, *prev;
100 for(tmp = p_head, prev = p_head; tmp; prev = tmp, tmp = next){
101
102 next = tmp->next;
103
104 if(tmp->x == x && tmp->y == y && tmp->z == z){
105
106 free(tmp);
107
108 if(prev == tmp) {
109 p_head = next;
110 } else {
111 prev->next = next;
112 }
113
114 }
115
116 }
117
118}
119 
120void destroy_all_particles(){
121
122 particle_list *tmp, *next;
123 for(tmp = p_head; tmp; tmp = next){
124
125 next = tmp->next;
126 free(tmp);
127
128 }
129 p_head = NULL;
130
131}

Hrvoje Ban
Member #4,537
April 2004
avatar

Use arc for drawing partial circles (arcs). Just increase angle every frame.

amarillion
Member #940
January 2001
avatar

Why do you use the x,y,z coordinates to identify a particle to delete? Why not the pointer itself?

Like this you have to do a test for equality of doubles, which should always be avoided I think. And, although unlikely, you could have two particles at exactly the same spot.

--
Martijn van Iersel | My Blog | Sin & Cos | Tegel tilemap editor | TINS 2017

ngiacomelli
Member #5,114
October 2004

Good point! I changed my code. Is this what you mean?

1void clean_particle_tree() {
2 
3 particle_list *tmp, *next;
4 for(tmp = p_head; tmp; tmp = next){
5
6 next = tmp->next;
7 
8 if(tmp->life <= 0) {
9 delete_particle_node(tmp);
10 }
11 
12 }
13 
14}
15 
16void delete_particle_node(particle_list *tmp_t){
17
18 particle_list *tmp, *next, *prev;
19 for(tmp = p_head, prev = p_head; tmp; prev = tmp, tmp = next){
20
21 next = tmp->next;
22
23 if(tmp == tmp_t){
24
25 free(tmp);
26
27 if(prev == tmp) {
28 p_head = next;
29 } else {
30 prev->next = next;
31 }
32
33 }
34
35 }
36
37}

Hrvoje Ban
Member #4,537
April 2004
avatar

You shouldn't remove questions, even stupid ones ;) since someone else might have same problem and get here through search.

Also, in C if you write function like foo() it means that function take varying number of arguments, for no arguments use foo(void).

ngiacomelli
Member #5,114
October 2004

Problem with do_circle (arcs isn't what I wanted):

1int c_click;
2 
3void draw_spawn_point(BITMAP *bmp, int x, int y, int d) {
4
5 int i;
6
7 c_click++;
8 if(c_click == d) {
9
10 add_object_node(1, x, y, 0);
11
12 for(i = 0; i < 10; i++) {
13
14 add_particle_node(rand()%50, rand()%150,
15 (x - 5) + rand()%20, (y - 5) + rand()%20, rand()%10,
16 0, 0, 2,
17 0, 0, 0);
18
19 }
20
21 c_click = 0;
22
23 }
24
25}
26 
27void create_spawn_point(int size, int s_size, int x_s, int y_s) {
28
29 c_click = 0;
30
31 add_object_node(1, x_s, y_s, 0); // add centre node
32
33 do_circle(buffer, x_s, y_s, size, s_size, draw_spawn_point);
34 
35}

Now. The code works but when I have it placing a sprite within do_circle I end up with a huge amount of sprites per circle. So I wanted to cut that down. I thought that if I passed s_size as 10(which become d in draw_spawn_point). It would only draw a sprite every 10 calls to draw_spawn_point. Sadly, this doesn't work. It seems like it only calls the function for some areas of the circle, but not for others?! This is confusing as, if I remove the c_click counter, the entire circle is drawn.

Do I not understand the callback functionality?

nonnus29
Member #2,606
August 2002
avatar

void clean_particle_tree() {

     particle_list *tmp, *next;
     for(tmp = p_head; tmp; tmp = next){
           //You're always skipping the head of the list:
           next = tmp->next;

           if(tmp->life <= 0) {                      
               delete_particle_node(tmp->x, tmp->y, tmp->z);
           }

     }

}

The head of the list never gets deleted, or anything else.....

Edit; oops, n/m I'm wrong. :-[

Go to: