Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Animation works right in two arrays, but not this one?

This thread is locked; no one can reply to it. rss feed Print
Animation works right in two arrays, but not this one?
gamelord12
Member #8,586
May 2007

Okay, so after getting a lot of help from this board, I managed to get my basic fight stance animation working for my sword fighting game. After that, I figured all my other animations would be easy. I did my running forward animation and it worked fine. Now I tried using the same procedure to put in my running backward animation and I'm not getting good results. When I pass what should be the correct number into the function, it skips the last frame of the animation. When I pass 4 into the function (what should be one too high), it displays that last frame, but there's a stuttering glitch that comes in every second or two. Note: I used the same exact method to put it in as I did the last two sprite sheets, and there are four frames on the sprite sheet for the problematic animation.

1// Sword Play
2 
3// Known issues:
4 
5// flawlessly, player can move forward...and that's it
6// moving backward has animation issues
7// many more sprite sheets still needed
8 
9#include <allegro.h>
10 
11#define BLACK makecol(0, 0, 0)
12#define GREEN makecol(0, 255, 0)
13#define WHITE makecol(255, 255, 255)
14 
15volatile int frame1 = 0, frame2 = 0, p1 = 40, p2 = SCREEN_W - 40, player, stamina1 = 100, stamina2 = 100, ticks = 0;
16const int frameRate = 8, staticy = 200;
17 
18// obtains sprites from a sprite sheet
19BITMAP *grabframe(BITMAP *source, int width, int height, int startx, int starty, int columns, int frame)
20{
21 BITMAP *temp = create_bitmap(width, height);
22 
23 int x = startx + (frame % columns) * width;
24 int y = starty + (frame / columns) * height;
25 
26 blit(source, temp, x, y, 0, 0, width, height);
27 
28 return temp;
29}
30BITMAP *buffer; // used to smooth out the animation
31BITMAP *buffer2; // used to smooth out animation even more
32BITMAP *pic; // temporary variable for putting sprites into an array
33BITMAP *SwordPlayTitle; // title screen picture
34 
35// sprite arrays end in s (for sprite) to differentiate from functions
36BITMAP *fightStances[4];
37BITMAP *runForwards[9];
38BITMAP *runBackwards[4];
39 
40/*BITMAP *attackHeads[10];
41BITMAP *attackHands[10];
42BITMAP *attackFoots[10];
43BITMAP *defendHeads[1];
44BITMAP *defendHands[1];
45BITMAP *defendFoots[1];
46
47BITMAP *powerStruggles[1];
48BITMAP *pushs[4];*/
49 
50void time(void); // used to count hundredths of a second
51void frame1Function(int maxframes); // controls animation of current action for player 1
52 
53void runForward(int player); // 9 frames
54void runBackward(int player); // 4 frames
55 
56/*void attackHead(int player);
57void attackHand(int player);
58void attackFoot(int player);
59void defendHead(int player);
60void defendHand(int player);
61void defendFoot(int player);
62
63void push(int player); // 5 frames: one player stumbles backward, other stays in fightStance
64void powerStruggle(void); // both players go through same two frames, then loser is pushed*/
65 
66void stamina(void); // displays players' stamina bars
67void increaseStamina(void); // slightly regenerates stamina every second
68/*void decreaseStamina(void); // decreases player's stamina when an attack is blocked*/
69 
70int main(void)
71{
72 allegro_init(); // uses Allegro
73 install_timer(); // initializes timing functionality
74 install_keyboard(); // allows use of keyboard
75 set_color_depth(32); // sets color depth for pallette of sprites
76 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); // makes the screen a 640x480 window
77 SwordPlayTitle = load_bitmap("SwordPlayTitle.bmp", NULL); // loads title screen image
78 
79 blit(SwordPlayTitle, screen, 0, 0, 0, 0, SwordPlayTitle->w, SwordPlayTitle->h); // puts the title screen picture on the screen
80 textprintf_centre_ex(screen, font, SCREEN_W / 2, 460, makecol(255, 255, 255), -1, "Press Any Key to Continue...");
81 destroy_bitmap(SwordPlayTitle); // frees up memory by destroying a now unneeded title screen
82 readkey(); // waits for input to proceed
83 
84 rest(50); // brief pause between input and loading the actual game
85 
86 // loads frames for the fighting stance animation
87 pic = load_bitmap("FightStanceSpriteSheet.bmp", NULL);
88 for(int x = 0; x <= 3; x++)
89 {
90 fightStances[x] = grabframe(pic, 240, 240, 0, 0, 4, x);
91 }
92 
93 // loads frames for the running forward animation
94 pic = load_bitmap("RunForwardSheet.bmp", NULL);
95 for(int x = 0; x <= 8; x++)
96 {
97 runForwards[x] = grabframe(pic, 240, 240, 0, 0, 4, x);
98 }
99 
100 // loads frames for the running backward animation
101 pic = load_bitmap("RunBackwardSheet.bmp", NULL);
102 for(int x = 0; x <= 3; x++)
103 {
104 runBackwards[x] = grabframe(pic, 240, 240, 0, 0, 4, x);
105 }
106
107 destroy_bitmap(pic); // frees up memory by destroying a now unneeded temporary variable
108 buffer = create_bitmap(SCREEN_W, SCREEN_H); // makes the buffer
109 buffer2 = create_bitmap(SCREEN_W, SCREEN_H); // makes the buffer's buffer
110 install_int_ex(time, BPS_TO_TIMER(100)); // calls the timer function 100 times every second
111 install_int_ex(increaseStamina, BPS_TO_TIMER(1)); // increases the stamina bars for both players by 1 every second
112 
113 // main game loop
114 while(!key[KEY_ESC])
115 {
116 clear_to_color(buffer, WHITE);
117 /*// attack commands for player 1
118 if(key[KEY_W] && key[KEY_SPACE])
119 attackHead(1);
120 else if(key[KEY_SPACE])
121 attackHand(1);
122 else if(key[KEY_S] && key[KEY_SPACE])
123 attackFoot(1);
124
125 // defend commands for player 1
126 else if(key[KEY_W] && key[KEY_LSHIFT])
127 defendHead(1);
128 else if(key[KEY_LSHIFT])
129 defendHand(1);
130 else if(key[KEY_S] && key[KEY_LSHIFT])
131 defendFoot(1);*/
132 
133 // movement commands for player 1
134 if(key[KEY_D])
135 {
136 runForward(1);
137 masked_blit(runForwards[frame1], buffer, 0, 0, p1, staticy, runForwards[frame1]->w, runForwards[frame1]->h);
138 }
139 else if(key[KEY_A])
140 {
141 runBackward(1);
142 masked_blit(runBackwards[frame1], buffer, 0, 0, p1, staticy, runBackwards[frame1]->w, runBackwards[frame1]->h);
143 }
144 else
145 {
146 frame1Function(3);
147 masked_blit(fightStances[frame1], buffer, 0, 0, p1, staticy, fightStances[frame1]->w, fightStances[frame1]->h);
148 }
149 stamina(); // displays the stamina bars on the screen
150 masked_blit(buffer, buffer2, 0, 0, 0, 0, buffer->w, buffer->h); // puts everything that just happened in the last split-second on the second buffer
151 masked_blit(buffer2, screen, 0, 0, 0, 0, buffer2->w, buffer2->h); // puts that buffer on the screen
152 clear_bitmap(buffer); // erases the buffer so that it can be changed again
153 }
154 remove_int(increaseStamina); // frees up the memory used to call this function over and over again
155 
156 return 0; // makes this code compatible with non-MS compilers
157}END_OF_MAIN()
158 
159void time()
160{
161 ticks++;
162
163 if(ticks >= 100)
164 ticks = 0;
165}
166 
167void frame1Function(int maxframes)
168{
169 if(frame1 >= maxframes)
170 frame1 = 0;
171 
172 float comparisonVariable = 100 / frameRate;
173
174 if(ticks >= comparisonVariable)
175 {
176 ticks = 0;
177 
178 if(frame1 >= maxframes)
179 frame1 = 0;
180 else
181 frame1++;
182 }
183}
184 
185void runForward(int player)
186{
187 if(player == 1)
188 {
189 frame1Function(8);
190
191 if(p1 <= (SCREEN_W - 240))
192 p1++;
193 }
194}
195 
196void runBackward(int player)
197{
198 if(player == 1)
199 {
200 frame1Function(4);
201 
202 if(p1 > 0)
203 p1--;
204 }
205}
206 
207void stamina()
208{
209 textprintf_ex(buffer, font, 5, 15, BLACK, -1, "Player 1");
210 textprintf_right_ex(buffer, font, SCREEN_W - 5, 15, BLACK, -1, "Player 2");
211 rectfill(buffer, 5, 5, 5 + stamina1, 10, GREEN);
212 rectfill(buffer, SCREEN_W - 105, 5, SCREEN_W - 105 + stamina2, 10, GREEN);
213}
214 
215void increaseStamina()
216{
217 stamina1++;
218 if(stamina1 > 100)
219 stamina1 = 100;
220 stamina2++;
221 if(stamina2 > 100)
222 stamina2 = 100;
223}

HardTranceFan
Member #7,317
June 2006
avatar

Your frame1Function(...) logic is faulty - if frame1 is 3, then you can reach the frame1++ line, setting frame1 to 4, which exceeds your array dimension, before dropping out of the function. Do a check of frame1 before the function exits.

Alternatively, since you're passing the value 8 (one less than the array size) in runForward(...), you should be passing 3 runBackward(...).

--
"Shame your mind don't shine like your possessions do" - Faithless (I want more part 1)

gamelord12
Member #8,586
May 2007

I said that when I pass in the correct value, it skips the last frame. Also, it checks for when it is greater than or equal to, not just greater than, so it will only increase it when it is supposed to.

HardTranceFan
Member #7,317
June 2006
avatar

Sigh. Your function is wrong. You're thinking along the right lines, but it's not implemented correctly. I'll explain why by stepping through your frame1Function. Below I've put line numbers in function, and have a couple of scenarios to show you where the function falls over.

void frame1Function(int maxframes)
{
1  if(frame1 >= maxframes)
2    frame1 = 0;
3  float comparisonVariable = 100 / frameRate;
4  if(ticks >= comparisonVariable)
  {    
5    ticks = 0;
6    if(frame1 >= maxframes)
7      frame1 = 0;
8    else
9      frame1++;
  }
}

We'll set frame1 = 3 & call frame1Function(3):

The condition in line 1 frame1 >= maxframes is true so line 2 is executed
> frame1 is now 0

If line 4 evaluates to true, then lines 5-9 are executed
> Line 6 evaluates to false, so line 9 is executed
> frame++ sets frame to 1

Hey, guess what, you've skipped a frame. frame1 went from 3 to 1, and missed out 0.

Ok, let's try out frame1 = 3 & call frame1Function(4):

Line 1 evaluates to false, so line 2 is not executed
> frame1 is still 3

If line 4 evaluates to true, then lines 5-9 are executed
> Line 6 evaluates to false, so line 9 is executed
> frame++ sets frame to 4

Hey, guess what, you've gone past the array boundary. frame1 went from 3 to 4.

To correct this behaviour, use the modulus operator ('%'), as in the following code:

void frame1Function(int maxframes)
{
  if(ticks >= (100 / frameRate))
  {
    ticks = 0;
    frame1++;
  }

  frame1 = frame1 % maxframes;
}

--
"Shame your mind don't shine like your possessions do" - Faithless (I want more part 1)

Go to: