Reputation:
I've made myself a game, just like Pong using SDL and OpenGL under c++:
#include "SDL.h"
#include "SDL_opengl.h"
#include <iostream>
int main(int argc, char* args[])
{
//initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
//OpenGL memory
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute( SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1);
//caption of the window
SDL_WM_SetCaption( "Bine baaa", NULL );
//size
SDL_SetVideoMode(600,400,32, SDL_OPENGL);
//clearcolor
glClearColor(0,0,0,1); //RED,GREEN,BLUE,ALPHA
//portion of screen displayed
glViewport(0,0,600,400);
//for gradients
glShadeModel(GL_SMOOTH);
//2D rendering
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//save
glDisable(GL_DEPTH_TEST);
bool isRunning = true;
SDL_Event event;
typedef struct player{
float myX;
float myY;
float width=15;
float height=60;
bool up=false;
bool down=false;
};
player player1,player2;
player1.myX=10;
player1.myY=160;
player2.myX=580;
player2.myY=160;
float ballX=300;
float ballY=200;
float vitezaX=0.5;
float vitezaY=0.5;
float latura =10;
//main loop
while(isRunning){
//EVENTS
while ( SDL_PollEvent(&event)){
if( event.type == SDL_QUIT )
isRunning=false;
//escape button closes window
if(event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE)
isRunning=false;
if( event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_r)
glClearColor(1,0,0,1);
if( event.type == SDL_KEYDOWN){
if(event.key.keysym.sym==SDLK_UP)
player2.up=true;
if(event.key.keysym.sym==SDLK_DOWN)
player2.down=true;
if(event.key.keysym.sym==SDLK_w)
player1.up=true;
if(event.key.keysym.sym==SDLK_s)
player1.down=true;
}
if( event.type == SDL_KEYUP){
if(event.key.keysym.sym==SDLK_UP)
player2.up=false;
if(event.key.keysym.sym==SDLK_DOWN)
player2.down=false;
if(event.key.keysym.sym==SDLK_w)
player1.up=false;
if(event.key.keysym.sym==SDLK_s)
player1.down=false;
}
}
//LOGIC
if(player1.up==true)
player1.myY-=0.3;
if(player1.down==true)
player1.myY+=0.3;
if(player2.up==true)
player2.myY-=0.3;
if(player2.down==true)
player2.myY+=0.3;
if(ballY<0)
vitezaY=-vitezaY;
if(ballY+latura>400)
vitezaY=-vitezaY;
if(ballX+latura>player2.myX && ballY+latura>player2.myY && ballY<player2.myY+player2.height){
vitezaX=-vitezaX;
if(ballX+latura-player2.myX>=1){
if(vitezaY>0)
ballY=player2.myY-latura;
else
ballY=player2.myY+player2.height;
vitezaX=-vitezaX;
vitezaY=-vitezaY;
}
}
if(ballX<player1.myX+player1.width && ballY+latura>player1.myY && ballY<player1.myY+player1.height){
vitezaX=-vitezaX;
if((player1.myX+player1.width)-ballX>=1){
if(vitezaY>0)
ballY=player1.myY-latura;
else
ballY=player1.myY+player1.height;
vitezaX=-vitezaX;
vitezaY=-vitezaY;
}
}
if(ballX<0 || ballX>600){
ballX=300;
ballY=200;
SDL_Delay(500);
}
ballX+=vitezaX;
ballY+=vitezaY;
//RENDER
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix(); //Begin Render
glColor4ub(255,255,255,255);
glOrtho(0,600,400,0,-1,1);
glBegin(GL_QUADS);//GL_LINES, GL_LINE_STRIP, GL_QUADS, GL_POLIGON,GL_TRIANGLES, GL_LINE_LOOP
glVertex2f(player1.myX,player1.myY);
glVertex2f(player1.myX+player1.width,player1.myY);
glVertex2f(player1.myX+player1.width,player1.myY+player1.height);
glVertex2f(player1.myX,player1.myY+player1.height);
glEnd();//End Draw
glBegin(GL_QUADS);//GL_LINES, GL_LINE_STRIP, GL_QUADS, GL_POLIGON,GL_TRIANGLES, GL_LINE_LOOP
glVertex2f(player2.myX,player2.myY);
glVertex2f(player2.myX+player2.width,player2.myY);
glVertex2f(player2.myX+player2.width,player2.myY+player2.height);
glVertex2f(player2.myX,player2.myY+player2.height);
glEnd();//End Draw
glBegin(GL_QUADS);//GL_LINES, GL_LINE_STRIP, GL_QUADS, GL_POLIGON,GL_TRIANGLES, GL_LINE_LOOP
glVertex2f(ballX,ballY);
glVertex2f(ballX+latura,ballY);
glVertex2f(ballX+latura,ballY+latura);
glVertex2f(ballX,ballY+latura);
glEnd();//End Draw
glPopMatrix(); //End Render
SDL_GL_SwapBuffers();
SDL_Delay(2);
}
SDL_Quit();
return 0;}
NOTE: "latura" is the rectangle's width or height, "viteza" is velocity.
The problem is when i test the game on other machines, on my PC the game moves very slow even though i can say that my PC isn't that bad...(2GB RAM, 8600GT nvidia, and a quad core intel), on other machines the game is moving much faster, regardless of the code have been set at the same velocity. I just can't seem to find the logic under this issue. I want to know how to make this game to work at the same speed on different machines (i've looked for something such as time dependent animations...i don't know how much taht will help; i've also found some topics about software/hardware rendering, could this be the problem? that on my PC the game is using software rendering and on other machines is hardware base?).
Upvotes: 5
Views: 10435
Reputation: 126
The main problem I see is in your game loop. Why are you using a static delay of 2 milliseconds? That's your bottleneck right there. You're trying to render your game at 500 FPS on a machine that likely doesn't have hardware accelerated OpenGL drivers.
First things first, delay your game to something like 50 to 100Hz instead of the 500 you're using here. Start with a time keeping variable at the very beginning of your game loop.
Uint32 time = SDL_GetTicks();
Now we skip all the way to the very end for more code...
if(20>(SDL_GetTicks()-time))
{
SDL_Delay(20-(SDL_GetTicks()-time)); //SDL_Delay pauses the execution.
}
It may look a bit confusing for anyone unfamiliar with SDL, but what this does is delay the code by an exact amount of time, no matter how fast the program goes through it's loop.
To explain it a bit better, let's say that the game loop takes 4 milliseconds (For the sake of argument alone, the loop is likely much faster in actuality) to make it from beginning to end. You're already adding 2 milliseconds onto it, so that makes the total delay 6 milliseconds, or ~130 FPS. Most modern computer displays only have a refresh rate of about 60Hz, or 60 frames per second.
By having the game loop as fast as it is, your game is rendering more than double the frames without even displaying most of them. It's extremely wasteful to think about, but let's look at the common solution above.
SDL_GetTicks() is a functions that tells you the current running time since initialization. You take a snapshot of this time at the very beginning of the loop to get your starting time. You then see SDL_GetTicks() again at the end and use that to compare against your starting value.
Let's say that the starting time is 15 and at the end the time returned by SDL_GetTicks() is 22. The equation compares 22 minus 15 first, 7, and compares whether that number is less than 20, which it is. It then pauses the system for 20 minus 7 milliseconds, 13.
This is useful because the framerate doesn't fluctuate wildly, and if the game loop speed takes longer than 20 milliseconds to reach the end, it doesn't delay it at all, which means you'll never waste precious processing power or frame rendering with it.
Instead of 20, you can also replace it with (1000/FPS) where FPS is the... well... FPS you want your game running at. This makes it easy to do something like 60 FPS without whipping out your calculator first. Simple division, that's all.
End result:
int main(int argc, char *argv[])
{
int FPS = 50 //Framerate
//Setup stuff
while(GAME_RUNNING)
{
Uint32 start_time = SDL_GetTicks();
//Event handling
//Logic stuff
//Rendering things
if((1000/FPS)>(SDL_GetTicks()-start_time))
{
SDL_Delay((1000/FPS)-(SDL_GetTicks()-start_time)) //Yay stable framerate!
}
}
This is pretty much the easiest way to control your game rendering. On a side note, I use a little more complicated method where I create a separate thread for screen rendering at 60Hz while I run the game loop at 100. No wasted processing power and I can have a nice, round number for my in-game calculations. Look up the SDL_CreateThread() function, it makes it extremely simple for this.
The only problem you might run into would be rendering a dynamic number of objects to the screen, however all that can be solved with static vectors, but I digress. I hope this solved most of your problems, but since this post is 3 months old, it may just be more useful for anyone else stumbling upon it asking the same questions.
Upvotes: 11
Reputation: 2363
Looking at the other answers, I'd guess that your machine does not have the h/w accelerated OpenGL driver, which is causing your game to pick up the MESA gl library.
Here's one way to confirm it. From a cmdline, type:
ldd ./program_name
If you see /usr/lib/mesa/libGL.so.1 rather than /usr/lib/libGL.so.1, you'll know why it's so slow.
Upvotes: 1
Reputation:
I have compiled your code on my PC, and is working smoothly (>500 fps) on an integrated graphics card (intel HD 4000).
If you want to check if openGL is running, use flags on your surface.
SDL_Surface* screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL );
if( screen->flags & SDL_OPENGL ) printf("using openGL");
Upvotes: 1