salut,
j'ai fait un pong en c windows, et je voudrais que la vitesse de jeu soit la meme pour chaque pc.
comment dois je faire?
Version imprimable
salut,
j'ai fait un pong en c windows, et je voudrais que la vitesse de jeu soit la meme pour chaque pc.
comment dois je faire?
Ca va pas être simple ! Mis à part si tyous tes PC sont identiques, chaque ordi dépend de la vitesse de son processeur et de la qualité de sa carte graphique ! Donc, je ne pense pas que tu obtiennes des FPS égaux sur tous les PC même si le code est optimisé.
@ ++
Il faut que la vitesse de ton jeu ne depende pas de la vitesse d'affichage.
Il faut utiliser des outils de synchronisation, de delais, de gestion de temps...
Utilise des timers ou autres...
dans le traitement des messages windows,
lorsque le message WM_PAINT est recu,
j'appelle ma fonction d'affichage, ca n'est donc pas dépendant de la vitesse du jeu.
pour la vitesse du jeu, j'utilise des Sleep.
Salut,
vu que tu n' as pas donné trop de précision je sais pas trop si la methode conviendra mais dans mes jeux pour corriger le probleme de vitesse suivant la puissance des pc je calcule le temps ecoulé entre chaque frame affiché pour obtenir un coefficiant pour le deplacement de mes perso et objets
genre au lien de faire
tu faisCode:
1
2Perso.x += 1.0f;
Code:
1
2 Perso.x += 1.0f * deltaTime; //
ou deltaTime est l' intervalle de temps entre chaque frame ,
calculé avec une fonction du genre :
va faire un tour sur www.gametutorials.com et regarde dans les tutoriaux openGL pour timebased mouvement pour un exemple d' implémentationCode:
1
2 float Get_Interval();
:wink:
merci pour le lien,
j'ai regardé mais je n'ai pas très bien compris,
je vous donne mon code, si vous pouviez mieux m'expliquer en vous servant de lui:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <windows.h> #include <gl/gl.h> #include <gl/glu.h> #include <gl/glaux.h> #include <string.h> #include <math.h> WNDCLASS wc; MSG msg; HWND hWnd; HDC DC; HGLRC RC; int mv_barre_gauche,mv_barre_droite; int score_gauche,score_droite,mode;//mode: 1 joueur ou 2 ou le menu float pos_barre_gauche,pos_barre_droite; float balle_x,balle_y,vitesse,angle; BOOL pause,fin=false; unsigned texture[12]; AUX_RGBImageRec *texture1[12]; //pour les textures de scores double sx,sy; void InitVariable(){ pause=true; angle=3.14/4; vitesse=0.005; balle_x=0;balle_y=0; pos_barre_gauche=0;pos_barre_droite=-3; mode=0; mv_barre_gauche=0;mv_barre_droite=0;score_droite=0;score_gauche=0; }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 DWORD WINAPI Ia(LPVOID){//thread pour le mode 1 joueur(ordi) while(!fin){ if(pause==false){ Sleep(0.6); if(balle_y>(pos_barre_droite+1) && (cos(angle)<0))mv_barre_droite=2; else if(balle_y<(pos_barre_droite+0.5) && (cos(angle)<0))mv_barre_droite=1; else mv_barre_droite=0; } } fin=false; return true; }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 void Traitement(){ if(mode==0){ } else { if(pause==false){ Sleep(0.5); vitesse+=0.0000001; //mouvement des barres switch (mv_barre_gauche){ case 0:break; case 1:if(pos_barre_gauche>-3.85) pos_barre_gauche = pos_barre_gauche - 0.01; break; case 2:if(pos_barre_gauche<1.15) pos_barre_gauche = pos_barre_gauche + 0.01; break; } switch (mv_barre_droite){ case 0:break; case 1:if(pos_barre_droite>-3.85) pos_barre_droite = pos_barre_droite - 0.006; break; case 2:if(pos_barre_droite<1.15) pos_barre_droite = pos_barre_droite + 0.006; break; } //calcul de la position de la balle balle_x+= vitesse * cos(angle); balle_y+= vitesse * sin(angle); //test du rebond sur les murs if(balle_y>=2.65 || balle_y<=-3.85) angle=-angle; //test points joueur gauche if(balle_x<=-4.9){ if(balle_y<(pos_barre_droite-0.15) || balle_y>(pos_barre_droite+1.65)){ score_gauche++; pause=true; balle_x=0;balle_y=0; vitesse=0.005; } else{ angle=-(angle+3.14); } } //test points joueurs droite if(balle_x>=4.9){ if(balle_y<(pos_barre_gauche-0.15) || balle_y>(pos_barre_gauche+1.65)){ score_droite++; pause=true; balle_x=0;balle_y=0; vitesse=0.005; } else{ angle=-(angle+3.14); } } } } }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 void LoadTexture(char *path,int at) { texture1[at] = auxDIBImageLoad(path); glGenTextures (1, &texture[at]); } void SelectTexture(int s){ glBindTexture (GL_TEXTURE_2D, texture[s]); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1[s]->sizeX, texture1[s]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1[s]->data); }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 void RePaint () { glClear (GL_COLOR_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); //gluLookAt (0,0,-10,0,0,0,0,1,0); glEnable (GL_TEXTURE_2D); if(mode) { gluLookAt (0,0,-10,0,0,0,-1,1,1); //affichage des scores SelectTexture(score_gauche); glBegin(GL_QUADS); glColor3d(1,1,1); glTexCoord2i(1,0);glVertex2f(0.2,3.6); glTexCoord2i(1,1);glVertex2f(0.2,4); glTexCoord2i(0,1);glVertex2f(0.5,4); glTexCoord2i(0,0);glVertex2f(0.5,3.6); glEnd(); SelectTexture(10); glBegin(GL_QUADS); glColor3d(1,1,1); glTexCoord2i(1,0);glVertex2f(-0.2,3.6); glTexCoord2i(1,1);glVertex2f(-0.2,4); glTexCoord2i(0,1);glVertex2f(0.2,4); glTexCoord2i(0,0);glVertex2f(0.2,3.6); glEnd(); SelectTexture(score_droite); glBegin(GL_QUADS); glColor3d(1,1,1); glTexCoord2i(1,0);glVertex2f(-0.5,3.6); glTexCoord2i(1,1);glVertex2f(-0.5,4); glTexCoord2i(0,1);glVertex2f(-0.2,4); glTexCoord2i(0,0);glVertex2f(-0.2,3.6); glEnd(); //affichage des murs glDisable( GL_TEXTURE_2D ); glBegin (GL_QUADS); glColor3d (0,0,1); glVertex2f (5.3,3); glVertex2f (5.3,2.7); glVertex2f (-5.3,2.7); glVertex2f (-5.3,3); glEnd (); glBegin (GL_QUADS); glColor3d (0,0,1); glVertex2f (5.3,-4); glVertex2f (5.3,-3.9); glVertex2f (-5.3,-3.9); glVertex2f (-5.3,-4); glEnd (); //affichage des joueurs glBegin (GL_QUADS); glColor3d (1,1,1); glVertex2f (5,pos_barre_gauche); glVertex2f (5,pos_barre_gauche+1.5); glVertex2f (5.3,pos_barre_gauche+1.5); glVertex2f (5.3,pos_barre_gauche); glEnd (); glBegin (GL_QUADS); glColor3d (1,1,1); glVertex2f (-5,pos_barre_droite); glVertex2f (-5,pos_barre_droite+1.5); glVertex2f (-5.3,pos_barre_droite+1.5); glVertex2f (-5.3,pos_barre_droite); glEnd (); //affichage de la balle glBegin (GL_QUADS); glColor3d (1,0,0); glVertex2f (balle_x+0.1,balle_y-0.1); glVertex2f (balle_x+0.1,balle_y+0.1); glVertex2f (balle_x-0.1,balle_y+0.1); glVertex2f (balle_x-0.1,balle_y-0.1); glEnd (); } else { gluLookAt (0,0,-10,0,0,0,0,1,0); //affichage du menu SelectTexture(11); glBegin(GL_QUADS); glColor3d(1,1,1); glTexCoord2i(1,0);glVertex2f(-5.5,-4); glTexCoord2i(1,1);glVertex2f(-5.5,4); glTexCoord2i(0,1);glVertex2f(5.5,4); glTexCoord2i(0,0);glVertex2f(5.5,-4); glEnd(); } SwapBuffers (DC); }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 void InitPixelFormat (HDC hDC) { PIXELFORMATDESCRIPTOR pfd = { sizeof (PIXELFORMATDESCRIPTOR), 1, PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; SetPixelFormat (hDC, ChoosePixelFormat (hDC, &pfd), &pfd); }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 LRESULT CALLBACK WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_LBUTTONDOWN: sx=LOWORD(lParam); sy=HIWORD(lParam); if(mode==0) { if((sx>74 && sx<534) && (sy>320 && sy<406)) PostMessage(hWnd,WM_CLOSE,0,0); else if((sx>63 && sx<551) && (sy>186 && sy<267)) mode=2; else if((sx>55 && sx<562) && (sy>80 && sy<182)){ mode=1; if(CreateThread(NULL,NULL,Ia,NULL,NULL,NULL)==NULL){ mode=0; } } } break; case WM_KEYDOWN: switch(wParam) { //demande de fermeture du programme case VK_ESCAPE: if(mode==0)PostMessage(hWnd,WM_CLOSE,0,0); else { InitVariable(); fin=true; mode=0; } break; case 0xd: if(pause==true){ pause=false; if(score_gauche==9 || score_droite==9){ InitVariable(); fin=true; mode=0; } } else pause=true; break; case VK_UP: if(mode==2)mv_barre_droite=2; else if(mode==1)mv_barre_gauche=2; break; case VK_DOWN: if(mode==2)mv_barre_droite=1; else if(mode==1)mv_barre_gauche=1; break; case 0x5a: if(mode==2)mv_barre_gauche=2; break; case 0x53: if(mode==2)mv_barre_gauche=1; break; } break; case WM_KEYUP: switch(wParam) { case VK_UP: if(mode==2)mv_barre_droite=0; else if(mode==1)mv_barre_gauche=0; break; case VK_DOWN: if(mode==2)mv_barre_droite=0; else if(mode==1)mv_barre_gauche=0; break; case 0x5a: if(mode==2)mv_barre_gauche=0; break; case 0x53: if(mode==2)mv_barre_gauche=0; break; } break; case WM_CREATE: int i;char par[14],tot[2]; InitVariable(); DC=GetDC (hwnd); InitPixelFormat (DC); RC = wglCreateContext (DC); wglMakeCurrent (DC, RC); for(i=0;i<=9;i++){ strcpy(par,"");strcpy(tot,"");strcpy(par,"score\\"); itoa(i,tot,10);strcat(par,tot); strcat(par,".bmp"); LoadTexture(par,i); } LoadTexture("score\\tiret.bmp",10); LoadTexture("score\\menu.bmp",11); break; case WM_CLOSE: wglMakeCurrent (NULL, NULL); wglDeleteContext (RC); ReleaseDC (hwnd,DC); PostQuitMessage (0); break; case WM_SIZE: glViewport (0,0,LOWORD (lParam),HIWORD (lParam)); glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective (45,(float)(LOWORD(lParam))/(float)(HIWORD(lParam)),1,100); break; case WM_PAINT: RePaint (); break; default: return DefWindowProc (hwnd,uMsg,wParam,lParam); break; } return 0; }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int CmdShow) { wc.style = CS_OWNDC; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "OGL"; RegisterClass(&wc); hWnd = CreateWindow ("OGL", "pong", WS_POPUPWINDOW | WS_VISIBLE, 20, 20, 600, 450, NULL, NULL, hInstance, NULL ); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); Traitement(); } return 0; }
ba j' ai pas tout matté en detail mais des que tu deplace un objet multiplie par un coef deltatime
pour calculer le deltatime , regarde du coté des fonctions QueryPerformanceCounter ou timeGetTime (winmm.lib)Code:
1
2
3 balle_x+= deltatime * vitesse * cos(angle); balle_y+= deltatime * vitesse * sin(angle);
je crois que j'ai compris,
je calcul mes frames par secondes, et je fais un truc du genre:
c'est ca?Code:
1
2 Sleep(frame/100);
et sinon, y a t-il un moyen de limiter directement le nombre de frames à 130 par exemple?
Salut,
je comprends pas trop pourquoi tu veux mettre des sleep a tout prix ...
tiens deja un lien pour comment faire un timer avec QueryPerformanceCounter :
http://nehe.gamedev.net/data/lessons....asp?lesson=21
Sinon plutot que de faire un Sleep() , pour bloquer ton frame rate avec l' API multimedia Win32
tu peux faire un truc genre :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 bool LockFrameRate(int frame_rate) { static float lastTime = 0.0f; float currentTime = GetTickCount() * 0.001f; if((currentTime - lastTime) > (1.0f / frame_rate)) { lastTime = currentTime; return true; } return false; }
et dans ta boucle Win32 principale tu fais
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 while(1) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); } else if(LockFrameRate(60)) // exemple pour 60 fps { Draw_Scene(); // la fonction qui dessine ta scene }
Si je veux faire absolument des Sleep(), c'est pour cadencer la vitesse du jeu, chez moi avec 1000 frames par secondes, je faisait un Sleep(0.5);
Sans le Sleep(), autant dire que l'on ne peut plus suivre la balle des yeux.
oui ok , ca j' ai bien saisi ,
par contre je crois pas que t a lu ou compris les deux derniers bouts de code que je t ai donné sinon tu me dirais pas ca :lol:
bon je vais tenter d' expliquer differemment alors :
imagine un vieux pc qui te sort 1 frame par sec :
en 1 sec ton code fait une boucle affichage + deplacement des objets ....
donc si tu fais
ta balle avance de 1.0f par sec , ok ?Code:
1
2
3balle.x = balle.x + 1.0f;
sur le super PC a 200 fps en une seconde tu fais deux cents boucles
donc ta balle avance de 200.0f en 1 sec ... toujours ok ? 8)
c bien pour cela que tu dois calculer avec une variable deltatime tel que
ton deltaTime ( == l espace entre les frames == temps a la frame courante - temps à la derniere frame) sera alors 200 fois plus petit sur le super pc que sur le pc pourri !Code:
1
2 balle.x = balle.x + ( 1.0f * deltaTime );
Voila :lol:
Bon je coup ci je crois pas que je peux te l' expliquer mieux que ca , regarde les codes que j' ai posté , essaye de les comprendre, de les implementer et rergarde les liens que j' ai posté
A+
je crois que j'ai compris, les FPS correspondent aux nombres de boucles Principale effectuées en une seconde?
désolé de t'embêter à nouveau,
j'ai fait comme tu as dit, mais les déplacements sont saccadés, c'est normal? (je suis à 600 FPS)
oui !Citation:
Envoyé par bakonu
en fait les FPS ca veux dire frame par second (image par seconde) et pour chaque image calculée le programme fais une boucle principale.
Merci,
beaucoup, désolé d'avoir mis du temps à repondre, mais j'ai très peu de temps libre depuis un moments.