Setting game speeds the same on all computers
Danex!

ok so i have my pong game working and everything is fine and i feel great about it so i decided to send it out to sum friends to show them my work and see if they can find flaws in the program through playing it, the first thing they noticed is how fast the ball moves when the game starts....however when i complie and run the game the ball starts out and a speed barely above crawling, so whats goin on here??

second they noticed the lack of a start menu of any kind so they can be ready to play right when they start the game and not be shocked into the game with the ball already moveing and they don't even know the controls(lack of a readme or instruction which should also be on a menu) i looked at another game's menu screen and thought it was cool and then looked at its code...and its probably more lines of code than my entire game ha ha ha so any suggestions for either of these?
Danex!

HardTranceFan

I assume you had a peek at my game code. I didn't think it was THAT long ;D

For you ball speed problem, use timers to work out how much time has elapsed since the last frame was blatted to the screen, and use this to multiply your speed variables.

Say you want 10 ball movements done per second. Then you would use something along the lines of:

#define ballMovements 10

timeMultiplier = ballMovements/ticksPerSecond;
deltaTime = timeNow() - lastTime;
position = position + (speed * timeMulitplier * deltaTime);
lastTime = timeNow();

On slower machines the steps between sequential ball placements would be larger than faster on machines. It's pseudo code (ie you need to determine what you want to use for timeNow() and ticksPerSecond).

One way of implementing a menu system would be to print a list of options and highlight the chosen menu option (a pointer next to the text, changing the colour of the text, a coloured box behind the text...), and move the highlight with the cursor keys, selecting the option when space or return are pressed.

Jeroen

Matt Weir

You could always just have a start screen for the game that has the control keys written on it somewhere if you want to take the easy way out for your game. ;)

HardTranceFan

That reminds me of the good old days, when you had to enter the letter of the option you wanted to choose (Press 'S' to start, 'E' to exit', 'O' for options...)

Sigh. :D

Danex!

hey hardtrace, i am trying to implement a moves per second like u said but i don't really understand what you are saying and therefore could not implement it :/... so could you clarify or help or something?
Danex!

imaxcs

nm :-X

HardTranceFan

OK, I'll try it by explaining what is happening, and then giving a little definition of each variable involved in my pseudo code.

The idea is to move the ball at a set speed by altering the ball's position on the screen a set number of times per second, regardless of how fast or slow the PC runs.

The PC timer works on clock ticks. I assume faster PCs have more clock ticks per second than slower PCs. Dividing the number of ball speed updates by the number of clock ticks per second, you get a multiplier. Using this multiplier on the number of clock ticks that have passed determines the number of times the speed factor should be added to the ball's position.

For example: Say you have 2 PCs, PC1 with 1000 clock ticks per second, PC2 with 5000 clock ticks per second, and you want the speed component to be added 10 times per second. The multiplier for PC1 will be 10/1000 = 1/100 (add the speed component once every 100 clock ticks). The multiplier for PC2 will be 10/5000 = 1/500.

Now, just for explanations sake, assume the speed is 1 (pixel) this is to be added 10 times per second. Say PC1 updates the ball position every 250 clock ticks (deltaTime = 250, which is the same on PC1 as 4 times a second) and PC2 updates the ball position every 200 clock ticks (deltaTime = 200, equivalent to 25 times a second). For PC1, the position update will be 1 * 250 * (1/100), or 2.5 pixels every update. This still achieves the 10 updates per second (2.5 * 4 = 10). For PC2, the position update will be 1 * 200 * (1/500) = 0.4 pixels per update. This too achieves the 10 updates per second (0.4 * 25 = 10)

The pseudo code names stand for:

timeMultiplier is calculated to be the minimum number of clock ticks that need to occur before the ball should be redrawn to the screen.

ballMovements is the number of times you want the speed component to be added to the ball's position per second. Play with this to get a reasonable speed.

ticksPerSecond is the number of clock cycles (?) that occur per second (=CLOCKS_PER_SEC in time.h from memory)

deltaTime is the elapsed time between the last time the ball was drawn to the screen and now

timeNow() is a made up function name that gets the number of cycles elapsed (=clock() in time.h, again from memory)

lastTime is the number of cycles when the ball was last redrawn to the screen.

position is the x or y component of the ball's screen position

speed is the x or y speed value of the ball

To add to this all, an alternative is to check that a set number of clock ticks have passed (ie deltaTime > ticksPerSecond / ballMovements), and then adding the speed component accordingly.

Danex!

Ok so everything resets itself.
Also i should declare all of your intergers as global floats correct.
How do i get the time_now() from <time.h> shoudl i set timenow() = time.h? Can you even do this without errors?
Also ticks per second would also be taken from time.h right? So how to you get that out of there?
So basically my questions are:

1) Can i set time_now = <time.h>. If not what should i do to do this?

2) How do i pull ticks_per_second out of the computer?
Danex!

HardTranceFan
Quote:

1) Can i set time_now = <time.h>. If not what should i do to do this?

Err, no. timeNow() was a pseudo code for a function that gets the current number of clock ticks. As per definition, in time.h it's clock(). time.h is a standard C library.

Quote:

2) How do i pull ticks_per_second out of the computer?

As I explained the definitions, use CLOCKS_PER_SEC.

Check out http://www.cplusplus.com/ref/ctime/ , and look for some tutorials on timers. You can also look at the source code of my game for timer usage.

Jeroen

Danex!

I see now, i just over analyzed it thinking that you were useing other names besides clock() and the other one for a specific reason cause it might cause errors in the program.(I guess you giving me the pseudo then the acual function confused me.) However i understand now :), back to work then, Thankyou for your help!
Danex!

HardTranceFan

I had thought using the pseudo code may help in case you used a different timer library, but looks like it confused the issue a little. I'll try making it clearer next time. Good luck making it all work in your game :)

Jeroen

Danex!
 timeMultiplier = ballMovements/CLOCKS_PER_SEC;
deltaTime = clock() - lastTime;
ball_x = ball_x + (x_speed * timeMulitplier * deltaTime);
lastTime = clock();
ball_y = ball_y + y_speed;

Above is what i am working with.
When you complie the program it returns the error:
`timeMulitplier' undeclared (first use this function)
Why is it counting timeMultiplier as a function when i declared it as a float?
Danex!

Thomas Fjellstrom

Its not counting it as a function. its saying its not been defined or declared anywhere this function can see. and won't repeat the warning again after this first message.

Danex!

Its defined as a global, how can it not be seen?
Danex!

Zaphos
Quote:

Its defined as a global, how can it not be seen?

If it's defined below where it's used, or in a different (not included) file? Or if you made a typo ...

HardTranceFan

You'll also need to apply the timeMulitplier * deltaTime bit to the ball_y calculation (or the ball will travel slowly vertically on your machine, and race along on your mates PCs).

Jeroen

Danex!

thats my code with comments where i defined timeMultiplier and where it showed error

1//global stuff
2 
3#include <allegro.h>
4#include <cstdlib>
5#include <time.h>
6#define ballMovements 10
7BITMAP *buffer;
8void menu();
9void game();
10volatile long speed_counter;
11void increment_speed_counter() {
12speed_counter ++; }
13END_OF_FUNCTION(increment_speed_counter)
14float ball_x = 320;
15float ball_y = 240;
16int paddle_speed_up = 2;
17int paddle_speed_down = 2;
18int paddle_1_y = 240;
19int paddle_1_height = 79;
20int paddle_2_height = 79;
21int paddle_2_y = 240;
22int paddle_1_x = 0;
23int paddle_2_x = 0;
24float x_speed=-1;
25float y_speed=-1;
26float deltaTime, lastTime;
27float timeMultiplier; //defined as a global float
28 
29//main
30 
31int main() {
32 allegro_init();
33 install_timer();
34 LOCK_VARIABLE(speed_counter);
35 LOCK_FUNCTION(increment_speed_counter);
36 install_int_ex(increment_speed_counter,BPS_TO_TIMER(60));
37 install_keyboard();
38 set_color_depth(16);
39 set_gfx_mode(GFX_AUTODETECT_WINDOWED,640,480,0,0);
40
41 BITMAP *paddle_1;
42 BITMAP *paddle_2;
43 paddle_1 = load_bitmap("paddle1.bmp",NULL);
44 paddle_2 = load_bitmap("paddle2.bmp",NULL);
45 buffer = create_bitmap(640,480);
46 menu();
47 while (!key[KEY_ESC])
48 {
49
50 while (speed_counter >0)
51 {
52 if (key[KEY_DOWN]){
53 paddle_1_y = paddle_1_y + paddle_speed_up; }
54 else if (key[KEY_UP]){
55 paddle_1_y = paddle_1_y - paddle_speed_up; }
56 if (key[KEY_S]) {
57 paddle_2_y = paddle_2_y + paddle_speed_up; }
58 else if (key[KEY_W]){
59 paddle_2_y = paddle_2_y - paddle_speed_up; }
60 speed_counter --;
61 if (paddle_1_y < 0){
62 paddle_1_y = 0;}
63 if (paddle_2_y < 0){
64 paddle_2_y = 0;}
65 if (paddle_1_y + paddle_1_height > 480){
66 paddle_1_y = 480 - paddle_1_height;}
67 if (paddle_2_y + paddle_2_height > 480){
68 paddle_2_y = 480 - paddle_2_height;}
69
70 }
71
72 game();
73 textout_ex(buffer, font, "PongGame // Press ESC to leave", 0, 0, makecol( 255, 0, 0), makecol( 0, 0, 0));
74 draw_sprite(buffer, paddle_1, 20, paddle_1_y);
75 draw_sprite(buffer, paddle_2, 620, paddle_2_y);
76 blit(buffer,screen,0,0,0,0,640,480);
77 clear_bitmap(buffer); }
78destroy_bitmap(paddle_1);
79destroy_bitmap(paddle_2);
80destroy_bitmap(buffer);
81return 0;}
82END_OF_MAIN()
83 
84 
85
86void game(){
87 
88timeMultiplier = ballMovements/CLOCKS_PER_SEC;
89deltaTime = clock() - lastTime;
90ball_x = ball_x + (x_speed * timeMulitplier * deltaTime);//error
91ball_y = ball_y + (y_speed * timeMulitplier * deltaTime);//error
92lastTime = clock();
93 
94if (ball_y < 0){
95ball_y = 0;
96y_speed = -y_speed;}
97if (ball_y > 475){
98ball_y = 475;
99y_speed = -y_speed;}
100if (ball_x < 20 && ball_y >= paddle_1_y && ball_y <= paddle_1_y + paddle_1_height){
101 x_speed = -x_speed;
102 y_speed += (float) rand() / RAND_MAX * .4;
103 if (x_speed > 19) {
104 x_speed = 19;}
105 if (paddle_speed_up > 4)
106 {paddle_speed_up = 4;}
107 else{
108 x_speed++;
109 paddle_speed_up = paddle_speed_up + 1;}
110
111 }
112if (ball_x > 620 && ball_y >= paddle_2_y && ball_y <= paddle_2_y + paddle_2_height){
113 x_speed = -x_speed;
114 y_speed += (float) rand() / RAND_MAX * .4;
115 if (x_speed > 19) {
116 x_speed = 19;}
117 
118 }
119if (ball_x > 640) {
120ball_x =320;
121textout_ex( screen, font, "Player 1 Wins!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0));
122rest(3000);
123exit(EXIT_FAILURE);
124}
125if (ball_x < 0){
126ball_x = 320;
127textout_ex( screen, font, "Player 2 Wins!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0));
128rest(3000);
129exit(EXIT_FAILURE);
130}
131circlefill( buffer, ball_x, ball_y , 5, makecol( 0,255, 0)); }
132
133void menu() {
134 textout_ex( screen, font, "Press any key to begin!", 320, 240, makecol( 255, 0, 0), makecol( 0, 0, 0));
135readkey(); }

HardTranceFan

You've got a typo - timeMulitplier should be timeMultiplier ::)

Jeroen

Danex!

:-[He he makes me feel dumb cause i checked that but i just can't spell.
Well now the program compiles but the ball never starts moving? Whats goin on there. With the old system it moved but jsut to fast on some computers, now its not moving at all. Could it be that my comp is so slow that its just takeing that long to move?
Danex!

HardTranceFan

I copied the first spelling of it and did a repeated search in the code - it only found 2, hence it was a spelling difference.

As for your latest problem, I'm tempted to say debug, but that might not solve it. Visit the time.h link I gave you earlier, and look the data type clock() returns.

Jeroen

Danex!

Ok I tried to run debug useing the dev C++ debug function but it just produced an error that turned my screen blue and i have to click to restore and it had shut down dev c++ so thats out. As for clock() it says for most compiliers it returns long int. Should i change it to long int type?
Danex!
[edit]
Did that and it did nothing...makes me mad that the game works perfectly on my system but differnetly on other systems

HardTranceFan

Try setting it to type clock_t.

Remember to cast in the calculations.

Debugging is not just a matter of running a program in debug mode. Debugging is the process of working out what is going wrong by whatever means you can. If debug mode won't work, try using output statements to the screen or a file to see what certain values are set to.

And I repeat, look at examples of time.h being used in other programs. It's one of the best ways of learning of how things are done.

Jeroen

LennyLen
Quote:

He he makes me feel dumb cause i checked that but i just can't spell.

Unless you've set your compiler to not report a single error or warning, then it should have complained about an undeclared variable.

Bob

What's wrong with the Allegro FAQ?

Kitty Cat

clock() isn't the function you want, as it only measures time for the process, not the whole system time. The standard functions to use would be gettimeofday, or clock_gettime (both POSIX standard). Of course, Windows doesn't have these, so you'll need to use QueryPerformanceFrequency and QueryPerformanceCounter.

However, I'd recommend against delta time methods for newbies. A fixed logic rate, as described in Allegro's FAQ, would be much simpler and work just as good.

fsDoom

Also why are you installing the allegro timer-function anyway if you're not gonna use it :D ?

HardTranceFan
Quote:

What's wrong with the Allegro FAQ?

Nothing. I dabbled with OpenGL and SDL before trying Allegro, and the method I described works with C++ using any of these game libraries.

Quote:

QueryPerformanceFrequency and QueryPerformanceCounter

Same idea as CLOCKS_PER_SEC and clock(). If QueryPerformanceFrequency and QueryPerformanceCounter windows specific, that would make them a lot less portable.

Jeroen

Danex!

Ok i looked at the code from FAQ(just a side note that FAQ section looks helpful, i will cunsult it before asking questions next time) but there is a problem, i am already using the code that it provided. Thats how i learned to make programs ha ha ha, so what should i do or add to it, the only thing not in my code that was not in the code before was update_game_logic();, which i have not previously made, is it declared already in the standard library? so i am adding that in in random places and seeing if it works or does anything, if you want to seed where i have already implemented the code just look up a bit in the forum, i posted it. Thankyou for your time.
Danex!
[edit]
think it works and realized the noobishness of that question, it mean udateing the ball by update_game_logic(); oh well now i just gotta get some friends to test for me, also i am woefully ignorant of how to set up a download site and keep it running
any help?
Danex

Kitty Cat
Quote:

Same idea as CLOCKS_PER_SEC and clock().

Except it doesn't do the same thing. clock() only measures the time your process takes, not the system time/real-time. So that means if you rest or if your process is put to sleep while it waits on IO, clock will slow down. And the time other processes take will slow clock down as well.

There is no simple cross-platform way to get system time, with accuracy better th an seconds. clock_gettime(CLOCK_REALTIME, ...) and gettimeofday are standard and can get the system time, but Windows doesn't support them. So to get comparable functionality on Windows, you have to use QueryPerformanceFrequency and QueryPerformanceCounter. Or, since MinGW does try to add POSIX functions Windows doesn't natively support, you could supply patches for those functions and (when they're accepted and applied) use them on any system with GCC.

Thread #587622. Printed from Allegro.cc