Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » timing animation again

This thread is locked; no one can reply to it. rss feed Print
 1   2 
timing animation again
William Labbett
Member #4,486
March 2004
avatar

Quote:

William, since your animation is still running slower than it seems it should be, please show us more code, specifically all that relates to the logical processing and the struct you're using for your hero object.

Sure thing. I'll post my main() aswell :-

1int main()
2{
3 int old_ticks;
4 
5 init();
6 
7 get_shadow_colours();
8 load_data();
9 colour_codes_init();
10 generate_shapes_info();
11 create_and_organise_bitmaps();
12 
13 temp_buffer = create_bitmap(640, 480);
14 
15 initialise_levels();
16 
17 level_x = 4;
18 level_y = 5;
19 
20 current_level = level_numbers[level_y][level_x];
21 
22 initialise_hero_for_first_level();
23 
24 while(!key[KEY_ESC])
25 {
26 //read_level(level_number);
27 
28 
29 initialise_level_variables();
30 
31 initialise_water_tiles();
32 initialise_nodes();
33 
34 draw_first_frame();
35 fade_in_level();
36 blit(buffer, screen, 0, 0, 0, 0, 640, 480);
37
38 play_state = PLAYING;
39 
40 while(!key[KEY_ESC] && play_state == PLAYING)
41 {
42 logic_calls = 0;
43
44 while(ticks == 0)
45 {
46 rest(100 / updates_per_second);
47 }
48
49 
50 while(ticks > 0)
51 {
52 old_ticks = ticks;
53 
54 ++logic_calls;
55 
56 if(hero.opening_door == OPENING)
57 {
58 if(door_opening_info.anim_delay_counter > 0)
59 {
60 --door_opening_info.anim_delay_counter;
61 door_opening_info.change_frame = 0;;
62 }
63 else
64 {
65 door_opening_info.change_frame = 1;
66 door_opening_info.anim_delay_counter = door_opening_info.anim_ticks_per_frame;
67 }
68 }
69 
70 
71 if(water_animation_info.anim_delay_counter > 0) {
72 water_animation_info.anim_delay_counter--;
73 water_animation_info.draw = DONT_DRAW;
74 }
75 else
76 {
77 water_animation_info.draw = DRAW;
78 water_animation_info.anim_delay_counter = water_animation_info.anim_ticks_per_frame;
79 }
80 
81 
82 if(hero.anim_delay_counter > 0)
83 {
84 --hero.anim_delay_counter;
85 hero.update = 0;
86 }
87 else
88 {
89 hero.update = 1;
90 hero.anim_delay_counter = hero.anim_ticks_per_frame;
91 }
92 
93 
94 do_non_drawing();
95 ticks--;
96 if(old_ticks <= ticks) break;
97 
98 }
99 
100 
101 
102 draw_everything_to_buffer();
103 blit(buffer, screen, 0, 0, 0, 0, 640, 480);
104 
105 if(hero.leaving_level)
106 {
107 hero.level_exit_x = hero.x;
108 hero.level_exit_y = hero.y;
109 
110 initialise_next_level();
111 play_state = LEAVE_LEVEL;
112 }
113 
114 }
115 
116 }
117 
118 
119 fclose(logfile);
120 save_bitmap("buffer.bmp", buffer, NULL);
121 
122 allegro_exit();
123 return 0;
124}
125END_OF_MAIN();

1void do_non_drawing(void)
2{
3 /* if hero.animating is IN_ANIMATION then just need
4 to draw him in next position.
5 hero.animating needs to be changed to IN_ANIMATION when :
6 it's been determined that he'll move
7 when's this ?
8 when determine_heros_move is called.
9 On the other hand it has to be changed to NOT_IN_ANIMATION when :
10 he's finished moving or whatever he was doing.
11
12 */
13 
14 if(hero.update && hero.animating == NOT_IN_ANIMATION)
15 {
16 get_hero_input();
17 /* assigns hero.direction_hero_wants_to_move
18 hero.trying_to_push
19 hero.trying_to_pull */
20 
21 hero.what_hero_can_do = determine_heros_move();
22 
23 
24 
25 if( hero.what_hero_can_do == MOVE_ONLY
26 || hero.what_hero_can_do == JUST_HOLD
27 || hero.what_hero_can_do == JUST_UNHOLD
28 || hero.what_hero_can_do == MOVE_AND_PULL
29 || hero.what_hero_can_do == MOVE_AND_PUSH
30 || hero.what_hero_can_do == REACH
31 || hero.what_hero_can_do == UNREACH)
32 {
33 hero.animating = IN_ANIMATION;
34 }
35 
36 update_hero_frame_and_position();
37 }
38 
39 else if(hero.update) {
40 update_hero_frame_and_position();
41 }
42 
43 /* shapes_info.shape_being_moved
44 needs to be changed to NOT_BEING_MOVED because draw_shapes() must only be called
45 when a shape needs moving on the "tops" bitmap. Can writing comments like this solve
46 problems ? That's what I want to find out by trying. */
47 
48 
49 
50 if(outcast.level_has_outcast) update_outcast();
51 
52 
53 if(hero.update && shapes_info.needs_drawing == NEEDS_DRAWING) update_moving_shapes();
54 
55 
56 if(hero.opening_door == OPENING && door_opening_info.change_frame == 1)
57 {
58 ++door_opening_info.door_frame;
59 if(door_opening_info.door_frame == NUMBER_OF_FRAMES_FOR_DOOR_ANIMATION + 2)
60 {
61 --door_opening_info.door_frame;
62 }
63 }
64 
65}

That's my logic loop. Please forgive the crazy commenting.

The hero struct is :

1 
2struct hero {
3 BITMAP *hwh[NUMBER_OF_WH_FRAMES]; /* hero walking horizontally frames */
4 BITMAP *hwd[NUMBER_OF_WALKING_DOWN_FRAMES];
5 BITMAP *hs[NUMBER_OF_STILL_FRAMES]; /* hero still */
6 BITMAP *hh[NUMBER_OF_HOLDING_FRAMES]; /* hero holding */
7 BITMAP *hp[NUMBER_OF_PULLING_FRAMES];
8 BITMAP *hrfu[NUMBER_OF_REACHING_FRAMES];
9 BITMAP *hrfa[NUMBER_OF_REACHING_FRAMES];
10 int moving;
11 int pushing;
12 
13 unsigned short animating;
14 int direction_hero_wants_to_move;
15 short trying_to_push;
16 short trying_to_pull;
17 int reaching_for_door;
18 short direction_facing;
19 short what_hero_can_do;
20 short distance_from_xy;
21 int x, y;
22 
23 int holding;
24 
25 int holding_frame;
26 int reaching_frame;
27 int opening_door;
28 int opening_door_frame;
29 
30 int leaving_level;
31 unsigned short increment_for_walking;
32 
33 int draw;
34 int anim_delay_counter;
35 int anim_ticks_per_frame;
36 int update;
37 
38 int level_exit_x, level_exit_y;
39 
40 
41};

not all it's members are still in use but I've not gotten around to fleecing it yet.

This function :-

1 
2void initialise_hero_for_first_level(void)
3{
4 int x, y;
5 
6 hero.x = hero.y = -1;
7 /* Find out where hero starts. */
8 for(y = 0; y < LEVEL_HEIGHT; ++y)
9 for(x = 0; x < LEVEL_WIDTH; ++x)
10 if(levels_array[current_level - 1].level[x][y].level_map_colour == tc[PLAYER_START])
11 {
12 hero.x = x;
13 hero.y = y;
14 }
15 if(hero.x == -1 || hero.y == -1)
16 {
17 print_error("In read_level.c : read_level() : PLAYER_START not found.\n\n");
18 printf("Level number %d.", current_level - 1);
19 exit_game();
20 }
21 
22 
23 hero.update = 1;
24 hero.anim_delay_counter = 1;
25 hero.anim_ticks_per_frame = 1;
26 
27 hero.animating = NOT_IN_ANIMATION;
28 hero.direction_facing = FACING_RIGHT;
29 hero.trying_to_push = NOT_TRYING;
30 hero.trying_to_pull = NOT_TRYING;
31 hero.holding = NOT_HOLDING;
32 hero.increment_for_walking = 0;
33 hero.reaching_frame = -1;
34 hero.reaching_for_door = NOT_REACHING;
35 hero.opening_door = NOT_OPENING;
36 
37 hero.leaving_level = 0;
38}

sets things up.

Really appreciate your willingness to help.

edit : ...and I'll be happy to post any more code that needs to be seen.

GullRaDriel
Member #3,861
September 2003
avatar

Give your project a profiling party. It will help you that much for finding where exactly you consume the most part of your cpu time.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

William Labbett
Member #4,486
March 2004
avatar

what's a profiling party please ?

GullRaDriel
Member #3,861
September 2003
avatar

Example:

I compiled an old project with the following gcc flags for activating profiling: -pg

After what I launch my code one time, I play with it, and after exiting I call gprof.

Here are the commands and the result:

gcc -c -Wall -pedantic -pg -mwindows *.c
gcc -pg -o test.exe MapEditor.o m_action.o m_grafic.o m_help.o m_ressource.o -lnilorea -lagl -lalleg -luser32 -lgdi32 -lopengl32 -lglu32 -lglaux -lwsock32 -lws2_32 -lpthreadGC2

1test.exe
2Done !
3gprof test.exe
4Flat profile:
5 
6Each sample counts as 0.01 seconds.
7 % cumulative self self total
8 time seconds seconds calls Ts/call Ts/call name
9 33.33 0.01 0.01 allegro_gl_is_extension_s
10 33.33 0.02 0.01 draw_map
11 33.33 0.03 0.01 split_color
12 0.00 0.03 0.00 365 0.00 0.00 draw_gui
13 0.00 0.03 0.00 3 0.00 0.00 clear
14 0.00 0.03 0.00 1 0.00 0.00 at_exit_job
15 0.00 0.03 0.00 1 0.00 0.00 create_new_map
16 
17 % the percentage of the total running time of the
18time program used by this function.
19 
20cumulative a running sum of the number of seconds accounted
21 seconds for by this function and those listed above it.
22 
23 self the number of seconds accounted for by this
24seconds function alone. This is the major sort for this
25 listing.
26 
27calls the number of times this function was invoked, if
28 this function is profiled, else blank.
29 
30 self the average number of milliseconds spent in this
31ms/call function per call, if this function is profiled,
32 else blank.
33 
34 total the average number of milliseconds spent in this
35ms/call function and its descendents per call, if this
36 function is profiled, else blank.
37 
38name the name of the function. This is the minor sort
39 for this listing. The index shows the location of
40 the function in the gprof listing. If the index is
41 in parenthesis it shows where it would appear in
42 the gprof listing if it were to be printed.
43
44 Call graph (explanation follows)
45 
46 
47granularity: each sample hit covers 4 byte(s) for 33.33% of 0.03 seconds
48 
49index % time self children called name
50 <spontaneous>
51[1] 33.3 0.01 0.00 allegro_gl_is_extension_supported
52-----------------------------------------------
53 <spontaneous>
54[2] 33.3 0.01 0.00 draw_map [2]
55-----------------------------------------------
56 <spontaneous>
57[3] 33.3 0.01 0.00 split_color [3]
58-----------------------------------------------
59 0.00 0.00 365/365 main [464]
60[6] 0.0 0.00 0.00 365 draw_gui [6]
61-----------------------------------------------
62 0.00 0.00 3/3 main [464]
63[7] 0.0 0.00 0.00 3 clear [7]
64-----------------------------------------------
65 0.00 0.00 1/1 main [464]
66[8] 0.0 0.00 0.00 1 at_exit_job [8]
67-----------------------------------------------
68 0.00 0.00 1/1 main [464]
69[9] 0.0 0.00 0.00 1 create_new_map [9]
70-----------------------------------------------
71 
72 This table describes the call tree of the program, and was sorted by
73 the total amount of time spent in each function and its children.
74 
75 Each entry in this table consists of several lines. The line with the
76 index number at the left hand margin lists the current function.
77 The lines above it list the functions that called this function,
78 and the lines below it list the functions this one called.
79 This line lists:
80 index A unique number given to each element of the table.
81 Index numbers are sorted numerically.
82 The index number is printed next to every function name so
83 it is easier to look up where the function in the table.
84 
85 % time This is the percentage of the `total' time that was spent
86 in this function and its children. Note that due to
87 different viewpoints, functions excluded by options, etc,
88 these numbers will NOT add up to 100%.
89
90 self This is the total amount of time spent in this function.
91
92 children This is the total amount of time propagated into this
93 function by its children.
94
95 called This is the number of times the function was called.
96 If the function called itself recursively, the number
97 only includes non-recursive calls, and is followed by
98 a `+' and the number of recursive calls.
99 
100 name The name of the current function. The index number is
101 printed after it. If the function is a member of a
102 cycle, the cycle number is printed between the
103 function's name and the index number.
104
105
106 For the function's parents, the fields have the following meanings:
107 
108 self This is the amount of time that was propagated directly
109 from the function into this parent.
110 
111 children This is the amount of time that was propagated from
112 the function's children into this parent.
113
114 called This is the number of times this parent called the
115 function `/' the total number of times the function
116 was called. Recursive calls to the function are not
117 included in the number after the `/'.
118
119 name This is the name of the parent. The parent's index
120 number is printed after it. If the parent is a
121 member of a cycle, the cycle number is printed between
122 the name and the index number.
123 
124 If the parents of the function cannot be determined, the word
125 `<spontaneous>' is printed in the `name' field, and all the other
126 fields are blank.
127 
128 For the function's children, the fields have the following meanings:
129
130 self This is the amount of time that was propagated directly
131 from the child into the function.
132
133 children This is the amount of time that was propagated from the
134 child's children to the function.
135 
136 called This is the number of times the function called
137 this child `/' the total number of times the child
138 was called. Recursive calls by the child are not
139 listed in the number after the `/'.
140 
141 name This is the name of the child. The child's index
142 number is printed after it. If the child is a
143 member of a cycle, the cycle number is printed
144 between the name and the index number.
145
146 If there are any cycles (circles) in the call graph, there is an
147 entry for the cycle-as-a-whole. This entry shows who called the
148 cycle (as parents) and the members of the cycle (as children.)
149 The `+' recursive calls entry shows the number of function calls that
150 were internal to the cycle, and the calls entry for each member shows,
151 for that member, how many times it was called from other members of
152 the cycle.
153 
154
155Index by function name
156 
157 [1] allegro_gl_is_extension_supported [9] create_new_map [3] split_color
158 [8] at_exit_job [6] draw_gui
159 [7] clear [2] draw_map

And now I know where my time was mostly spent.

My top two eating functions are allegro_gl_is_extension_s and draw_map. Obvious, but sometime it helps.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

William Labbett
Member #4,486
March 2004
avatar

thanks Gull..

I tried it but I get :-

http://www.allegro.cc/files/attachment/597746

I appreciate your help.

Thomas Fjellstrom
Member #476
June 2000
avatar

You made sure to run your program before running it through gprof right?

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

GullRaDriel
Member #3,861
September 2003
avatar

Yeah, as stated before and repeated by Thomas, you must run it one time as usual before calling gprof on it.

So, let's first do a '17.exe' call, after what you will be able to launch gprof on it.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Just to be clear William, you meant that your animation speed was too slow, not your program speed, right?

This may be part of it :

Quote:

//
if(hero.anim_delay_counter > 0)
{
                   --hero.anim_delay_counter;
                   hero.update = 0;
}
else
               {
                   hero.update = 1;
                   hero.anim_delay_counter = hero.anim_ticks_per_frame;
               }

//

If you have the anim_ticks_per_frame set to 1, then your anim_delay_counter gets set to 1 when it is 0, and decremented when it is greater than zero.

So starting from hero.anim_delay_counter = 0, it is set to 1 on the first logic call. On the second call it will be decremented. On the third call it will reach zero again. This effectively means that hero.update would only be set to 1 on every other logic call. With this setup it means hero.update is only set to 1 on every (hero.anim_ticks_per_frame + 1)th frame.

What you want is to decrement your tick counter on every pass through the logic loop, and detect when it reaches zero that way. So something more like :

//
--hero.anim_delay_counter;
if (hero.anim_delay_counter <= 0) {
  // reached the time to update the hero's frame
  hero.update = 1;
  hero.anim_delay_counter = hero.anim_ticks_per_frame;
} else {
  hero.update = 0;
}
//

This way when the counter starts at 1 at the beginning of the logic call, it will be decremented to zero which triggers the frame update and resets the delay counter to the number of ticks per frame.

William Labbett
Member #4,486
March 2004
avatar

Okay guys.

Thanks to Thomas, Edgar and Gulladriel ;) I appreciate your patience.

I've got things to work on now, so I'll be absent for a while, while I work through the help.

I'll get back when I've done some work.

EDIT :

hi again. Trying to use profiling but with no luck.

I have : used the -pg compiler flag.
used -pg with the linker.
ran the program before gprof.

..but I still get gmon.out : no such file or directory.

Can anyone help ?

EDIT 2 :

actually I've got it now.

Here's the profile :

1Flat profile:
2 
3Each sample counts as 0.01 seconds.
4 % cumulative self self total
5 time seconds seconds calls ms/call ms/call name
6 30.00 0.06 0.06 _mangled_main
7 15.00 0.09 0.03 117 0.26 0.26 get_hero_input
8 10.00 0.11 0.02 404 0.05 0.17 do_non_drawing
9 10.00 0.13 0.02 5 4.00 4.00 add_two_pixel_border
10 5.00 0.14 0.01 202 0.05 0.05 update_hero_frame_and_position
11 5.00 0.15 0.01 117 0.09 0.09 determine_heros_move
12 5.00 0.16 0.01 1 10.00 10.00 fade_in_level
13 5.00 0.17 0.01 1 10.00 10.00 get_shadow_colours
14 5.00 0.18 0.01 1 10.00 30.00 grass_from_pattern
15 5.00 0.19 0.01 1 10.00 10.00 make_a_pattern
16 5.00 0.20 0.01 1 10.00 10.00 save_shadow_array
17 0.00 0.20 0.00 22768 0.00 0.00 hline
18 0.00 0.20 0.00 22528 0.00 0.00 random_number

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

It's nice to see that you've got profiling working for you. You will probably want a sample size larger than running your program for 0.20 seconds though, and you might as well wait until you've got all your basic program elements running before you worry about which functions are taking the longest overall.

Did you try the fix for the animation rate that I pointed out in my last post?

William Labbett
Member #4,486
March 2004
avatar

Quote:

Did you try the fix for the animation rate that I pointed out in my last post?

Not until I read the above. I was being neurotic about it. And I was having trouble getting on my feet today for some reason.

When I saw you'd replied, I cut and pasted the code you wrote in place of the old code in my main function and commented the old code out.

When I ran it, I couldn't believe it. The hero walks about really fast which is brilliant because that means I can actually choose how fast I want him to move by increasing hero.anim_ticks_per_frame which will slow him down a bit.

So I'm really pleased, really relieved and feeling more positive my project now.

Thanks very much for the help Edgar. You spotted exactly what the problem was.

:)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Well, I kind of glossed over it first. I should have read it more closely.

Quote:

So I'm really pleased, really relieved and feeling more positive my project now.

That's good. Sometimes a small victory is enough to carry the whole day.

 1   2 


Go to: