Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Walk animation.

This thread is locked; no one can reply to it. rss feed Print
Walk animation.
julian_boolean
Member #8,201
January 2007

The problem I'm having is specifically with northwest, northeast, southeast, and southwest.

Somewhere in my program I have this:

1 if (key[KEY_UP])
2 walk(NORTH);
3 
4 if (key[KEY_RIGHT])
5 walk(EAST);
6 
7 if (key[KEY_DOWN])
8 walk(SOUTH);
9 
10 if (key[KEY_LEFT])
11 walk(WEST);
12
13 if (key[KEY_UP] && key[KEY_LEFT])
14 walk(NORTHWEST);
15 
16 if (key[KEY_UP] && key[KEY_RIGHT])
17 walk(NORTHEAST);
18 
19 if (key[KEY_DOWN] && key[KEY_RIGHT])
20 walk(SOUTHEAST);
21 
22 if (key[KEY_DOWN] && key[KEY_LEFT])
23 walk(SOUTHWEST);
24 
25// Elsewhere
26 
27// ...
28 
29 case NORTHWEST:
30 {
31 curframe++;
32
33 if (curframe <= 32)
34 curframe = 39;
35 
36 if (curframe >= 39)
37 curframe = 32;
38 }break;
39 
40 case NORTHEAST:
41 {
42 curframe++;
43
44 if (curframe <= 40)
45 curframe = 47;
46 
47 if (curframe >= 47)
48 curframe = 40;
49 }break;
50 
51 case SOUTHEAST:
52 {
53 curframe++;
54
55 if (curframe <= 48)
56 curframe = 55;
57 
58 if (curframe >= 55)
59 curframe = 48;
60 }break;
61
62 case SOUTHWEST:
63 {
64 if (curframe != maxframe)
65 curframe++;
66
67 if (curframe <= 56)
68 curframe = 63;
69 
70 if (curframe >= 63)
71 curframe = 56;
72 }break;

North, east, south, west, all works perfectly fine. But northwest, northeast, southeast, and southwest only displays the first frame for each direction instead of cycling through them. In other words when I press the up and right key, northeast only displays frame 40 and nothing else.

Edit:

I also have this around the direction switch to slow the frames down:

  if (frame_count++ > frame_delay)
  {
    f_count--;

    switch (dir)
    {
      // ...
    }
  }

But it acts REALLY sketchy and I usually have to set the delay to 150 or so to slow it down even a bit. Allegro timers came to mind.

Jakub Wasilewski
Member #3,653
June 2003
avatar

Just examine those ifs. Let's say I press up+left to go northwest. That means both key[KEY_UP] and key[KEY_LEFT] are true - which causes the program to call walk(NORTH), walk(WEST), walk(NORTHWEST) in that order.

So NORTH will set the frame to something appropriate, then WEST will set the frame to the first frame of "walk west" animation, and then finally NORTHWEST will set the frame to the first frame of "walk northwest" animation.

Just fix the ifs so that walk() is always called only once.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

julian_boolean
Member #8,201
January 2007

Hmm.. That reminds me, if I hold in an arrow key (like north) and press a different one while holding it in, it won't switch to that direction and will remain north. Is this problem related?

Edit:

Actually NM it does. Still not sure how I call walk() once. I was reading a book and in it the guy makes functions for walking in different directions, like walk_north(), but I really don't want to do that.

Jakub Wasilewski
Member #3,653
June 2003
avatar

Just make sure to call walk(NORTH) only if KEY_UP is pressed, and no other directional keys are pressed. Similar for other directions.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

julian_boolean
Member #8,201
January 2007

Isn't that what I have already? If so, then I'm not sure what your getting at.

Jakub Wasilewski
Member #3,653
June 2003
avatar

Quote:

if KEY_UP is pressed, and no other directional keys are pressed.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

julian_boolean
Member #8,201
January 2007

In theory it works, but you do have one limitation. You can only move in one direction.

void do_input()
{
  if (key[KEY_UP])
    walk(NORTH);
}

Unless you mean this:

void walk_north()
{
  if (key[KEY_UP])
    walk(NORTH);
}

void walk_east()
{
  if (key[KEY_RIGHT])
    walk(east);
}

LennyLen
Member #5,313
December 2004
avatar

if (key[KEY_UP] && !key[KEY_LEFT] && !key[KEY_RIGHT])
    walk(NORTH);

Et cetera.

Jakub Wasilewski
Member #3,653
June 2003
avatar

if (up && left)
  walk(NORTHWEST);
else if (up && right)
  walk(NORTHEAST);
else if (down && right)
  walk(SOUTHEAST);
else if (down && left)
  walk(SOUTHWEST);
// at these point all the "double" directions are handled, so we can check for the single ones - the elses ensure that we only call walk() once. 
else if (down)
  walk(SOUTH);
//...

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

julian_boolean
Member #8,201
January 2007

LennyLen: You gotta be kidding me. Is there any other way to do it that doesn't look like.. That?

LennyLen
Member #5,313
December 2004
avatar

Quote:

LennyLen: You gotta be kidding me. Is there any other way to do it that doesn't look like.. That?

Yeah, what Jakub posted.

julian_boolean
Member #8,201
January 2007

Edited it as soon as he posted that. :P That code does work, I just hate using if else. Thank you. :)

So..

How about those timers?

Quote:

I also have this around the direction switch to slow the frames down: if (frame_count++ > frame_delay)

  {
    f_count--;

    switch (dir)
    {
      // ...
    }
  }

But it acts REALLY sketchy and I usually have to set the delay to 150 or so to slow it down even a bit. Allegro timers came to mind.

X-G
Member #856
December 2000
avatar

Quote:

You can only move in one direction.

... that seems like a pretty natural limitation, doesn't it? :P

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Jakub Wasilewski
Member #3,653
June 2003
avatar

enum {NORTH = 1, EAST = 2, SOUTH = 4, WEST = 8};
enum {NORTHEAST = NORTH | EAST, NORTHWEST = NORTH | WEST,
      SOUTHWEST = SOUTH | WEST, SOUTHEAST = SOUTH | EAST};

int up = (key[KEY_UP]) ? NORTH : 0;
int down = (key[KEY_DOWN]) ? SOUTH : 0;
int left = (key[KEY_LEFT]) ? WEST : 0;
int right = (key[KEY_RIGHT]) ? EAST : 0;

walk (up | down | left | right);

Well, if you don't like ifs :P.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

julian_boolean
Member #8,201
January 2007

:-* Thank you! That works wonders!

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

Well, if you don't like ifs :P.

Actually you are using ifs, and that style of coding looks a bit cryptic IMHO.
Why don't you use just an ordinary switch?

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

julian_boolean
Member #8,201
January 2007

It was suppose to be like this originally:

1 if (key[KEY_UP] && key[KEY_LEFT])
2 walk(NORTHWEST); // move player northwest and play animation
3 
4 else if (key[KEY_UP] && key[KEY_RIGHT])
5 walk(NORTHEAST); // move player northeast and play animation
6 
7 else if (key[KEY_DOWN] && key[KEY_RIGHT])
8 walk(SOUTHEAST); // move player southeast and play animation
9 
10 else if (key[KEY_DOWN] && key[KEY_LEFT])
11 walk(SOUTHWEST); // move player southwest and play animation
12 
13 else if (key[KEY_UP])
14 walk(NORTH); // move player north and play animation
15 
16 else if (key[KEY_RIGHT])
17 walk(EAST); // move player east and play animation
18 
19 else if (key[KEY_DOWN])
20 walk(SOUTH); // move player south and play animation
21 
22 else if (key[KEY_LEFT])
23 walk(WEST); // move player west and play animation
24 
25 else if (key[KEY_A])
26 attack(); // play attack animation
27
28 else
29 idle(); // play idle animation

But I like Jakub's way of doing it. Very clean in my eyes.

Paul whoknows
Member #5,081
September 2004
avatar

I prefer to separate logic and input, something like this:

1// 012
2// 345
3// 678
4switch(direction)
5{
6 case 0:
7 walk(NORTHWEST);
8 break;
9 case 1:
10 walk(NORTH);
11 break;
12 case 2:
13 walk(NORTHEAST);
14 break;
15 case 3:
16 walk(WEAST);
17 break;
18 case 4:
19 //play standing animation here
20 break;
21 case 5:
22 walk(EAST);
23 break;
24 case 6:
25 walk(SOUTHWEST);
26 break;
27 case 7:
28 walk(SOUTH);
29 break;
30 case 8:
31 walk(SOUTHEAST);
32 break;
33}

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Jakub Wasilewski
Member #3,653
June 2003
avatar

Quote:

Actually you are using ifs, and that style of coding looks a bit cryptic IMHO.

Technically not ifs, but conditional expressions. However, if you want to be anal about this we can get by without them ;).

int up = (key[KEY_UP] & 1) * NORTH;
int down = (key[KEY_DOWN] & 1) * SOUTH;
int left = (key[KEY_LEFT] & 1) * WEST;
int right = (key[KEY_RIGHT] & 1) * EAST;

Now, who will stand up to the challenge and obfuscate the code even further? :P

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

julian_boolean
Member #8,201
January 2007

Edit:

Actually NM. I'm not sure what I want right now.

I do know that when a player is not walking (not pressing any of the arrow keys) OR attacking (not pressing the A key) that idle() needs to be called. If the A key is pressed, the player shouldn't be able to walk or be idle UNTIL it completes the attack (finishes cycling through the frames.)

Edit again:

Okay, holy crap. I think an animation class is needed here. :P If I did make one, would I make it a friend class of cPlayer? I wanted to do something like this:

cAnimation animate;

animate.walk_cycle();

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

However, if you want to be anal about this we can get by without them ;)


Did you say anal? :o

Quote:

I think an animation class is needed here. :P If I did make one, would I make it a friend class of cPlayer?

I don't know, post your cPlayer class first.

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

julian_boolean
Member #8,201
January 2007

It's okay, I think I know what I'm going to do now. Thanks everyone!

SkaxCo
Member #8,323
February 2007

enum {NORTH = 1, EAST = 2, SOUTH = 4, WEST = 8};
enum {NORTHEAST = NORTH | EAST, NORTHWEST = NORTH | WEST,
      SOUTHWEST = SOUTH | WEST, SOUTHEAST = SOUTH | EAST};

int up = (key[KEY_UP]) ? NORTH : 0;
int down = (key[KEY_DOWN]) ? SOUTH : 0;
int left = (key[KEY_LEFT]) ? WEST : 0;
int right = (key[KEY_RIGHT]) ? EAST : 0;

walk (up | down | left | right);

Just wondering, how does the second line work? Actually, a lot of it is confusing. Um...

1: fine.
2: dunno
3...6: if(key[KEY_UP]){
up = NORTH;
else
up = 0;
7: Won't walk get called as walk(0) or walk(1)?

Onewing
Member #6,152
August 2005
avatar

Quote:

Just wondering, how does the second line work?

Those are binary or's. NORTH = 1 or (00000001) and EAST = 2 or (00000010). Or'd together NORTH | EAST = 3 or (00000011).

------------
Solo-Games.org | My Tech Blog: The Digital Helm

julian_boolean
Member #8,201
January 2007

On second thought, here's some code for the animation class I was working on:

1cAnimation::cAnimation()
2{
3 direction = NORTH;
4
5 curframe = 0;
6 f_count = 0;
7 f_delay = 10;
8}
9 
10void cAnimation::animate_cycle()
11{
12 if (f_count++ > f_delay)
13 {
14 f_count = 0;
15 
16 switch (direction)
17 {
18 case NORTH:
19 {
20 curframe++;
21
22 if (curframe < 0)
23 curframe = 7;
24 
25 if (curframe > 7)
26 curframe = 0;
27 }break;
28 
29 case EAST:
30 {
31 curframe++;
32
33 if (curframe < 8)
34 curframe = 15;
35 
36 if (curframe > 15)
37 curframe = 8;
38 }break;
39 
40 case SOUTH:
41 {
42 curframe++;
43
44 if (curframe < 16)
45 curframe = 23;
46 
47 if (curframe > 23)
48 curframe = 16;
49 }break;
50
51 case WEST:
52 {
53 curframe++;
54
55 if (curframe < 24)
56 curframe = 31;
57 
58 if (curframe > 31)
59 curframe = 24;
60 }break;
61
62 case NORTHWEST:
63 {
64 curframe++;
65
66 if (curframe < 32)
67 curframe = 39;
68 
69 if (curframe > 39)
70 curframe = 32;
71 }break;
72 
73 case NORTHEAST:
74 {
75 curframe++;
76
77 if (curframe < 40)
78 curframe = 47;
79 
80 if (curframe > 47)
81 curframe = 40;
82 }break;
83 
84 case SOUTHEAST:
85 {
86 curframe++;
87
88 if (curframe < 48)
89 curframe = 55;
90 
91 if (curframe > 55)
92 curframe = 48;
93 }break;
94
95 case SOUTHWEST:
96 {
97 curframe++;
98
99 if (curframe < 56)
100 curframe = 63;
101 
102 if (curframe > 63)
103 curframe = 56;
104 }break;
105 }
106 }
107}
108 
109void cAnimation::animate_half_cycle()
110{
111 if (f_count++ > f_delay)
112 {
113 f_count = 0;
114 
115 switch (direction)
116 {
117 case NORTH:
118 {
119 curframe++;
120
121 if (curframe < 0)
122 curframe = 3;
123
124 if (curframe > 3)
125 curframe = 0;
126 }break;
127 
128 case EAST:
129 {
130 curframe++;
131
132 if (curframe < 4)
133 curframe = 7;
134
135 if (curframe > 7)
136 curframe = 4;
137 }break;
138 
139 case SOUTH:
140 {
141 curframe++;
142
143 if (curframe < 8)
144 curframe = 11;
145
146 if (curframe > 11)
147 curframe = 8;
148 }break;
149
150 case WEST:
151 {
152 curframe++;
153
154 if (curframe < 12)
155 curframe = 15;
156
157 if (curframe > 15)
158 curframe = 12;
159 }break;
160
161 case NORTHWEST:
162 {
163 curframe++;
164
165 if (curframe < 16)
166 curframe = 19;
167
168 if (curframe > 19)
169 curframe = 16;
170 }break;
171 
172 case NORTHEAST:
173 {
174 curframe++;
175
176 if (curframe < 20)
177 curframe = 23;
178
179 if (curframe > 23)
180 curframe = 20;
181 }break;
182 
183 case SOUTHEAST:
184 {
185 curframe++;
186
187 if (curframe < 24)
188 curframe = 27;
189
190 if (curframe > 27)
191 curframe = 24;
192 }break;
193
194 case SOUTHWEST:
195 {
196 curframe++;
197
198 if (curframe < 28)
199 curframe = 31;
200
201 if (curframe > 31)
202 curframe = 28;
203 }break;
204 }
205 }
206}
207 
208void cAnimation::animate_attack()
209{
210 if (f_count++ > f_delay)
211 {
212 f_count = 0;
213 
214 switch (direction)
215 {
216 case NORTH:
217 {
218 curframe++;
219
220 if (curframe < 0)
221 curframe = 3;
222 }break;
223 
224 case EAST:
225 {
226 curframe++;
227
228 if (curframe < 4)
229 curframe = 7;
230 }break;
231 
232 case SOUTH:
233 {
234 curframe++;
235
236 if (curframe < 8)
237 curframe = 11;
238 }break;
239
240 case WEST:
241 {
242 curframe++;
243
244 if (curframe < 12)
245 curframe = 15;
246 }break;
247
248 case NORTHWEST:
249 {
250 curframe++;
251
252 if (curframe < 16)
253 curframe = 19;
254 }break;
255 
256 case NORTHEAST:
257 {
258 curframe++;
259
260 if (curframe < 20)
261 curframe = 23;
262 }break;
263 
264 case SOUTHEAST:
265 {
266 curframe++;
267
268 if (curframe < 24)
269 curframe = 27;
270 }break;
271
272 case SOUTHWEST:
273 {
274 curframe++;
275
276 if (curframe < 28)
277 curframe = 31;
278 }break;
279 }
280 }
281}

Basically, animate_cycle() would be used for walking or idling, so outside the class I could go:

void cPlayer::idle()
{
  draw_action = IDLE; // Drawing is done in a function elsewhere.
  animate_cycle();
}

Then animate_half_cycle() would be used for actions a player can do that doesn't use as many frames, like sitting or swimming. And finally, animate_attack() does just that, it animates the attack of a player or monster. But it could also be used for other things I guess, like maybe having an animation of drinking a potion or something.

Any suggestions on how I could greatly improve this?

Go to: