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.
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.
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.
Just make sure to call walk(NORTH) only if KEY_UP is pressed, and no other directional keys are pressed. Similar for other directions.
Isn't that what I have already? If so, then I'm not sure what your getting at.
if KEY_UP is pressed, and no other directional keys are pressed.
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); //...
LennyLen: You gotta be kidding me. Is there any other way to do it that doesn't look like.. That?
LennyLen: You gotta be kidding me. Is there any other way to do it that doesn't look like.. That?
Yeah, what Jakub posted.
Edited it as soon as he posted that. That code does work, I just hate using if else. Thank you.
So..
How about those timers?
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.
You can only move in one direction.
... that seems like a pretty natural limitation, doesn't it?
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 .
Thank you! That works wonders!
Well, if you don't like ifs .
Actually you are using ifs, and that style of coding looks a bit cryptic IMHO.
Why don't you use just an ordinary switch?
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.
I prefer to separate logic and input, something like this:
1 | // 012 |
2 | // 345 |
3 | // 678 |
4 | switch(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 | } |
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 .
Now, who will stand up to the challenge and obfuscate the code even further?
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. 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();
However, if you want to be anal about this we can get by without them
Did you say anal?
I think an animation class is needed here. If I did make one, would I make it a friend class of cPlayer?
I don't know, post your cPlayer class first.
It's okay, I think I know what I'm going to do now. Thanks everyone!
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)?
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).
On second thought, here's some code for the animation class I was working on:
1 | cAnimation::cAnimation() |
2 | { |
3 | direction = NORTH; |
4 | |
5 | curframe = 0; |
6 | f_count = 0; |
7 | f_delay = 10; |
8 | } |
9 | |
10 | void 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 | |
109 | void 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 | |
208 | void 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?