Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » slow, rrreeallly slow fps

This thread is locked; no one can reply to it. rss feed Print
 1   2 
slow, rrreeallly slow fps
red-dragon
Member #7,722
August 2006

Yeah, sorry for hijacking the forum once again. But I'm reaching the end of my term, hence different threads for different topics.

I'm a total noob at the frames per second topic. In fact, I have looked at old threads here and followed a tutorial in implementing a timer and all. Thing is, I'm getting a rate of 7-8 frames per second when I move my character. I'm displaying a simple background with scrolling, one enemy moving on its own, and my character through keyboard input.

I'm using my laptop, for which the screen resolution is set at 1920x1200.

I followed this example code in implementing my timer: http://pixwiki.bafsoft.com/mags/12/articles/pong/article.html

I'm gonna show part of my code, maybe I'm doing something obviously wrong?

1 while(!key[KEY_ESC])
2 {
3
4 while(game_time > 0)
5 {
6 MapDrawBG(buffer, mapxoff, mapyoff, 0,
7 0,WIDTH,HEIGHT);
8
9 textprintf(buffer, font, 0, 10, WHITE, "FPS: %d",
10 fps);
11
12 int key;
13 if (keypressed())
14 key = getinput();
15 
16 if(i==4)
17 {
18 i=0;
19 enemy_dir();
20 }
21
22 
23 if(key == 0)
24 {
25 updatesprite(link);
26 move_character();
27 game_time--;
28 draw_link();
29 cfps++;
30 }
31
32 else if((key == 1) && (a != 0))
33 {
34 a--;
35 updateattacksprite(link);
36 attack();
37 draw_link();
38 game_time--;
39 cfps++;
40 }
41
42
43 if(a==0)
44 a = 10;
45
46 checkcollisions();
47 update_enemy_sprite(green_plant);
48 checkcollisions();
49
50 move_plant_enemy();
51 link->dir = 0;
52
53 draw_enemy();
54 
55 //vsync();
56 acquire_screen();
57 blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT);
58 release_screen();
59 
60 rest(70);
61
62
63 } //end of timer while
64 
65 while(game_time<0) ;
66 
67}

I know there are a few things I could put in other functions, but making the code neat is my priority after I'm done with this fps part.. unless you guys think it's highly inefficient. This is my first time tackling game programming, and if I had more time, I would've been able to restructure my code; unfortunately, I'll only get to do this after class is over.

Anyway, tia. And no making fun please :P

gnolam
Member #2,030
March 2002
avatar

Quote:

I'm gonna show part of my code, maybe I'm doing something obviously wrong?

Yes. Several. On my first and only skim through that (see item #1 on the list why I won't read it again).

1) For the love of God, choose descriptive variable names!
"if a == 0"?
"if i == 4"?
Gah!

2) You're mixing drawing and logic. :P

3)

Quote:

int key;

Overriding the existing key[] - not a good idea. Dump the entire keypressed()/readkey() stuff and use the key[] array.

4) Move the "game_time--" out of the ifs.

5)

Quote:

rest(70);

Even if that executes with no additional slowdown, that alone would give you a theoretical maximum FPS of 14. :P

6) You're mixing drawing and logic. :P
Yes, this deserves to be mentioned at least twice.

7)

Quote:

while(game_time<0) ;

...
What?

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Matthew Dalrymple
Member #7,922
October 2006
avatar

rest(70);

Have you tried decreasing this number? Also, using OpenLayer instead of just Allegro really helps with fps, as it uses hardware (your video card) for processing.

This line: while(game_time<0) ; Should never stop. When game_time gets to 0 it will get out of that big loop, then it hits this line. Well game_time will never be less than 0 as for it is 0.

=-----===-----===-----=
I like signatures that only the signer would understand. Inside jokes are always the best, because they exclude everyone else.

gnolam
Member #2,030
March 2002
avatar

Quote:

Quote:

while(game_time<0);

Should never stop.

No, that utterly bizarre loop will never start.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Matthew Dalrymple
Member #7,922
October 2006
avatar

Haha yes woopsies on my part.

Oh and to red-dragon regarding gnolam's post about "descriptive variable names!" Try using:

#define SOMETHING 4
#define NOTHING 0
...
     if(i==SOMETHING)
     {
          i= NOTHING;
          enemy_dir();
     }

See, you can actually read that logically. Get in the habit of saying your code out loud. "If i equals something then set i to nothing then call the enemy direction function."

=-----===-----===-----=
I like signatures that only the signer would understand. Inside jokes are always the best, because they exclude everyone else.

HardTranceFan
Member #7,317
June 2006
avatar

For starters :
1. Increase cfps only when you blit to the screen.
2. Decrease game_time only when you blit to the screen
3. What is the rest(70) for?

Not sure how much difference this will make to the overall game speed, but it may provide a more accurate FPS figure.

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

red-dragon
Member #7,722
August 2006

hey everyone,
thanks for the critiques :P I know I used some horrible variables and I have a LOT of globals, but it's mainly for debugging purposes. Horrible variable names are created from lack of sleep and staring at code for hours. Hey, it's hard for us beginners ;)

Now, I took a step back and remembered that the GPAIO book had a chapter on timers... so now, it seems to be working ok. I had a LOT of rest() that I commented out. The game is running like it's on steroids. What if you want the character to m ove at a slower/faster pace than... the enemy?

BAF
Member #2,981
December 2002
avatar

Quote:

2. Decrease game_time only when you blit to the screen

Umm, no? Decrease game_time once per logic loop. Drawing shouldn't be anywhere near loic.

Now as for the timing, just set up a nice timer controlled game loop, then you can control the rate at which the characters and enemies move.

Kris Asick
Member #1,424
July 2001

For a fixed-time game, (that is, a game where you want the framerate to be specific, like 15, 30, 60, etc.), you generally figure out the framerate you want, then base all the movement speeds of your players, enemies, etc. on their own speed. Thus the player might move 2 pixels a frame, enemies might move 1 pixel a frame.

Beyond that, what you need to do to fine-tune the movement speeds between things is to add either floating point variables or bit-shifted movement. Floating point is easier, bit-shifted is somewhat faster (though the difference is not as pronounced anymore as it once was.)

With floating point, everything has a decimal value, so you could assign a number to have a value of 3.7698, or 1.87658100647, or just plain 5.0. When you move an object, you can then move in smaller increments than a single pixel, such as:

myFloat += 0.25;

Bit-shifting is a little harder, but faster, and doesn't force you to do floating point arithmetic. Basically, with bit-shifting, you are deciding ahead of time how many increments should be between each pixel, and then your positions are decided accordingly, but you must use powers of two. For instance, if you want 64 increments between each pixel, that would be 2 to the power of 6, so you bit-shift by 6 whenever you draw something to the screen.

In this scenario, something at coordinates 640,384 is actually at pixel coordinates 10,6, because your drawing operation looks like:

draw_sprite(buffer,mySprite,spriteX>>6,spriteY>>6);

And by having the larger numbers you can now move objects with more precision. You just have to remember that if you want to set something based on pixel coordinates, you have to bit-shift the other way. For instance, if you want to place something at pixel coordinates 40,87 you would do:

spriteX = 40 << 6;
spriteY = 87 << 6;

The reason you use bit-shift operators ( << and >> ) instead of multiplication ( * ) is because multiplication is much slower in terms of CPU time.

Note though that you cannot bit-shift floating point numbers, only integers.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

James Stanley
Member #7,275
May 2006
avatar

I know it's important, as everybody says it, but what is actually wrong with mixing drawing and logic?

BAF
Member #2,981
December 2002
avatar

Because, you (should) run the logic at a fixed rate and draw in the free time. If you mix it, you have no way of controlling the speed of the logic, as you then depend on the frame rate.

James Stanley
Member #7,275
May 2006
avatar

Oh, I see.

HardTranceFan
Member #7,317
June 2006
avatar

BAF said:

Quote:

2. Decrease game_time only when you blit to the screen

Umm, no? Decrease game_time once per logic loop. Drawing shouldn't be anywhere near loic.

Err, yes, correct. I wasn't thinking properly when I wrote that bit. :-[

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

red-dragon
Member #7,722
August 2006

Kris Asic,
thanks man. I was looking fora nice detailed explanation like that :)

Now, I had set my game to about 30 frames per second. Now, I do want to base the movement of my enemies around that. I think my player will be ok.

Now, for enemy movement, I incremented it by a float inc = 0.25;
So, if enemy is going right, enemy->x += inc; But this means that now I have to change the int x, y (coordinates for enemy) to floats too, right? Or it might get truncated. Anyway, even an slight increment seemed too fast.

For my temporary fix, I've made a new variable, which is incremented and decremented each game loop from 0 to 1. Then if it's 1, I update the enemy movement. It seems to slow the movement a bit more, so I'll be tweaking this.

I'll have to reread about bit shifting, I've never done it. I believe there was a project regarding this in one of my courses, and I didn't get to do it :(

Anyway, thanks for the post, and let me know if something here I said is wrong. Actually, thanks to everyone ;)

HardTranceFan
Member #7,317
June 2006
avatar

Kris,

I'm not sure if I completely follow the bit shifting explanation. Here's my understanding so far. I'd appreciate if you (or anyone who does understand it properly) can comment:

Still with your example of 64 increments between pixels, if the movement is updated 128 per second, after one second the co-ordinates have changed by 2 pixels (assuming there's a continuous updating of co-ordinates).

Would that mean the right most position for a 640x480 screen will have an x component of 40960 (640*64)?

If you want one object to move at twice the speed of another, you bit shift one more (i.e. x_postion << 7 or x_position >> 7)?

And if you want something to move at 1.5 times normal, you'd bit shift by 6 and then add the original value bit shifted by 5?

Or am I totally off the path and down a cliff?

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

red-dragon
Member #7,722
August 2006

hmm,
ok, while I've been successful at slowing down the enemy, I can't seem to do it for link.

i.e. when attacking (spacebar), updateattacksprite() is called, where the proper frames are updated and then displayed.

To slow down enemy, here's exactly what I did (this is main at the moment):

        enemy_delay++;
        if(enemy_delay==5)
        {
                       update_enemy_sprite(green_plant);
                       checkcollisions();
                       move_plant_enemy();
                       enemy_delay = 0;
                       draw_enemy();
        }

Ok, so it slows down the enemy.

So, I tried something similar with link's updatespriteattack().
First, original code:

else if((key == 1) && (a != 0))
{       
             a--;
             updateattacksprite(link);
             draw_link();  
                           
             //attack();
}

Ok, yeah, I know a is a horrible variable name, let's get past that though.

Ok, modifying it like I did with enemy...:

1 else if((key == 1) && (a != 0))
2 {
3
4 attack_delay++;
5 if(attack_delay == 4)
6 {
7 a--;
8 updateattacksprite(link);
9 draw_link();
10 attack_delay = 0;
11 }
12 
13 //attack();
14
15 }

The point is for the frames to move by slowly. It happens so quickly that all I see is the last frame. Even with this code. Notice though, there is no move_character() here because he doesn't actually move..... only frames change. Hope that makes sense.

Any suggestions?

EDIT:
With the if(attack_delay == 4) modification, link also flickers now. >:(

Kris Asick
Member #1,424
July 2001

red-dragon: You don't have to do all that. Remember that you can make floating point values as small as 0.000000001, or more. Sometimes you'll need to go that low to really see any differences. (Maybe not that low, probably close to around 0.001.) And yes, if you use floating point for one thing you pretty much have to use it for everything else that's related.

HardTranceFan: You've pretty much got it, except you only ever need to bit-shift when drawing to the screen and when setting to pixel-coordinates. For everything else, you treat it as its own coordinate system with no bit-shifting.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

red-dragon
Member #7,722
August 2006

Kris Asick,
Will go back and go with a really low floating point number. That post I just made; I put in debug statements and realized that the updatesprite wasn't correct.... so now, I can see that all the frames ARE coming into play.

------------------------
Ok, just did more debug statements for variable a. The debug statement reveals that a starts as 10, as intended, then when spacebar is hit, it goes to 9 and stays there no matter what. No wonder the frame animations aren't all "automatically" displaying.

Once again, relevant code, in main,:

1if (keypressed())
2 which_key = getinput();
3 
4.....
5...
6.
7 
8else if((which_key == 1) && (a != 0))
9{
10
11 a--;
12 updateattacksprite(link);
13 draw_link();
14 attack();
15}

I found out int which_key was being declared within the while loop, which meant that it was being declared every game loop, so I changed it as a global. However, the debug statement still shows after 10, it goes to 9 and then doesn't change. Does whichever key you pressed last get reset every game loop??

EDIT: Yep, which_key resets to 0 every game loop. Can anyone explain why? And what can be done about this, please?
Anyone? Someone? Helllloooo? <echos> heh. C'mon.

Kris Asick
Member #1,424
July 2001

Think of it this way, red-dragon: If the keys didn't reset every frame, how would you know when someone let go of a key, or parse between hitting different letters to type something?

When you work with animated sprites, what you need to do is make those animations independent of your input handling. In other words, you probably want something more along the lines of this:

1a = 0;
2 
3if (keypressed())
4 which_key = getinput();
5 
6.....
7...
8.
9 
10if (which_key == 1 && !a) a = 10;
11if (a > 0)
12{
13 a--;
14 updateattacksprite(link);
15 draw_link();
16 attack();
17}

Thus while a = 0, no animation occurs, and then when you press the key you expect, a is set to 10, and while a is over 10, regardless of if a keyboard key is pressed, a decreases until it finally returns to 0.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

red-dragon
Member #7,722
August 2006

Hi Kris,
Appreciate your help. I woke up this morning and had a similar idea. So, I have it like you suggested, but something is still not right. I will show relevant code first:

1void updateattacksprite(SPRITE *spr)
2{
3
4 if(link->alive == 1)
5 {
6 
7 //update frame based on dir
8 if (++spr->framecount > spr->framedelay)
9 {
10 spr->framecount = 0;
11
12 /* if south, show frames 12-16 */
13 if(prev_dir == 4)
14 {
15 
16 spr->curframe++;
17 
18 if(spr->curframe < 12)
19 spr->curframe = 16;
20 else if(spr->curframe > 16)
21 spr->curframe = 12;
22
23 }
24
25 /* north */
26 else if(prev_dir = 2)
27 {
28 /* don't want to go out of bounds here
29 so don't increment if curframe == 21 */
30 if(spr->curframe != 21)
31 spr->curframe++;
32
33 if(spr->curframe < 17)
34 spr->curframe = 21;
35 else if(spr->curframe >= 21)
36 spr->curframe = 17;
37
38
39 }
40 }
41
42 } //if link alive
43}

Ok, so now with your help with code, I have this:

1....
2..
3.
4/* within game while loop */
5 else if(which_key == 1 && !a)
6 a = 5;
7 if(a > 0)
8 {
9 a--;
10 updateattacksprite(link);
11 draw_link();
12 attacked2 = attack();
13
14 if(a==0)
15 restore_frame(prev_dir);
16
17 }

updatespriteattack... I only have sprites for attacking up and down, not left and right..YET. So, up and down attacks both have 5 frames. Hence, a = 5 when spacebar is pressed in main while loop.

restore_frame... after the whole 5 frames, it is called. If before sword attack, Link's previous direction was, say, 4 (down), then his normal south (without holding a sword) frame appears.

What are the problems?
Little bug 1: It seems that hitting spacebar sometimes does not yield 5 frames necessarily; I know this because sometimes his last frame is, say frame 13 or 19, instead of them being 16 and 21. I don't know why this is happening, but it doesn't look good. He seems to start/stop on whatever frame.

I fixed something else as well. I have one more "bug" after this, but this has to be resolved first. TIA.

Kris Asick
Member #1,424
July 2001

You know, there is a point where you should be resolving your own problems and I think you've reached it for now. Experimentation will be a much better guide now than me telling you what to do because you're on the right track and I don't want to derail you with my own style of coding.

There are bugs in your code as you posted, but you should be able to spot them easily with a bit of scrutiny. One is in your IF statements, the other has to do with the fact that you are tracking TWO animation frame variables to do just one animation. (Use "a" or "spr->curframe" to time your animations, not both.)

The only other piece of advice I have for you is to eventually separate all your animations into separate arrays, then have your sprites simply run a pointer to the animation you want to use. Pointers are something you're going to have to really learn sooner or later to get the most out of C or C++, and once you understand them, things like animations will become a whole lot easier.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

red-dragon
Member #7,722
August 2006

Kris,
Regarding "You know, there is a point where you should be resolving your own problems and I think you've reached it for now. Experimentation will be a much better guide now than me telling you what to do because you're on the right track and I don't want to derail you with my own style of coding."

I didn't mean to come off as "here's my problem, fix it and tell me". I'm catching quite a few bugs myself and sometimes silly stuff is escaping me. That is all.

piccolo
Member #3,163
January 2003
avatar

i like to do it like this.
linkdelay = 10;
npcdelay=20;

1 
2if(conter1==linkdelay)
3{
4updatelinklogic();
5 
6conter1=0;
7}
8else
9{
10conter++;
11}
12 
13if(conter==npcdelay)
14{
15updateNPclogic();
16 
17conter=0;
18}
19else
20{
21conter++;
22}

link will move twice as fast as the NPcs

wow
-------------------------------
i am who you are not am i

Kris Asick
Member #1,424
July 2001

Quote:

I didn't mean to come off as "here's my problem, fix it and tell me". I'm catching quite a few bugs myself and sometimes silly stuff is escaping me. That is all.

Don't worry, you're not coming off that way. I'm just saying that not every problem has an immediate solution and that it may be more helpful to you to figure that particular problem out yourself.

For instance, there have been times when I've spent half an hour or more trying to solve a bug only to realize that all I had to do to fix the problem was change a '+' to a '-'. One of my friends once spent two hours on that exact same problem actually.

Sometimes the simplest problems are also the hardest to find and the search can be a good workout because it helps you learn to find that same kind of mistake again if you happen to make it again in the future.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

--- Kris Asick (Gemini)
--- http://www.pixelships.com

HardTranceFan
Member #7,317
June 2006
avatar

In those situations, you end up going through your code with a fine tooth comb, refining bits and pieces, and on the whole making the whole program more efficient and stable.

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

 1   2 


Go to: