# Jump n Run...Jump Probleme



## CodeCrafterCpp (20. November 2011)

Hallo,
Ich bin dabei mir ein kleines Jump n Run zu Programmieren mit OpenGL und C++.
Jetzt ist mein Problem das ich nicht weiß wie ich das machen soll das der Spieler beim Springen zb. pro Millisec. 10 Pixel fällt...Es sollte möglichst genau und wenig CPU fressen also flüssig laufen. Eine delay wäre nicht schlecht aber beim Googln hab ich nichts passendes gefunden....

Achja noch was ich möchte ja das man über Löcher Springen muss wie mach ich am besten?
Das ich immer eine Abfrage macht ob der Spieler auf Boden Steht oder das wenn der Spieler in das Loch läuft das er runter fällt?
EDIT: Der Welten werden zufällig aufgebaut....


Hoffe ihr könnt mir Helfen.

mfG
CCC


----------



## sheel (20. November 2011)

Hi

Windows?
Google nach _Query Performance Counter_.

Zu den Löchern:
Wie ist den die Welt generell aufgebaut?
Hast du Leveldateien oder kommt immer alles zufällig oder ...?


----------



## Endurion (20. November 2011)

Ist es Tile-basiert? Generell hast du ja hoffentlich einen Update-Loop mit einer Delta-Zeit.
Grade bei Action-Spielen sollte man damit ein Fixed-Length-Update machen.

D.h. du hast einen interen Zähler, der das Zeitdelta aufnimmt. Solange dieses Delta dann größer-gleich z.Bsp. 0.02s Sekunden ist, machst du ein Fixed-Delta-Time-Update.
Jede Steuerung machst du nur innerhalb dieses Fixed-Update. Dadurch rutschen dir schon mal keine Ungenauigkeiten mit Floats dazwischen.

Zum Springen/Fallen: Verabschiede dich von dem Gedanken der direkten Pause. Sowas macht man in einer Spieleschleife nicht, da ja sonst alles andere steht. Vielmehr merkst du dir für den Spieler den Status (am Boden, springt). 

Zu jedem Fixed Update dann in etwa so (Pseudocode):

Wenn der Spieler springt:
  Sprungzähler hoch. 
  Spieler nach oben bewegen (anfangs mehr, später weniger, abhängig vom Sprungzähler)
  Wenn der Sprungzähler das Maximum erreicht hat
    Sprungstatus entfernen

Einmal einfach so und sonst bei jeder Abwärtsbewegung prüfen, ob der Spieler jetzt am Boden steht.
Steht der Spieler am Boden
  "Spieler am Boden"-Status setzen
Steht der Spieler nicht am Boden
   Wenn nicht im Springen-Status
      Fallzähler hoch
      Spieler nach unten bewegen (anfangs wenig, später schneller, abhängig vom Fallzähler)


----------



## CodeCrafterCpp (20. November 2011)

@Endurion ich versteh das nicht richtig....Ich hab ja DrawGlScene und da hab ich ja auch drinne was passiert wenn man rechts oder klinks drückt....Soll ich jetzt machen und wie mach ich das mit der Delta Zeit....


@ Sheel Schau in ersten Beitrag unter Edit...
Und wie mach ich das mit  Query performance counter bekomm da nur errors...


----------



## Matthias Reitinger (20. November 2011)

Hallo,

wie sieht denn deine Hauptschleife aus? Verwendest du ein Framework (GLUT, SDL, etc.)?

Grüße,
Matthias


----------



## CodeCrafterCpp (20. November 2011)

Also ich benutze DrawGLScene 



```
bool DrawGLScene()									
{
	QueryPerformanceCounter((LARGE_INTEGER*)&g_CurentCount);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	


	
	glLoadIdentity();
	glTranslatef(p1, p2, p3);
	glRotatef(rviereck,0.0f,1.0f,0.0f);

	glBegin(GL_QUADS);
	glColor3f(0.0f,1.0f,0.0f); // Blau (Oben)
    glVertex3f(-1.0f, 1.0f, 0.0f); 
    glVertex3f( 1.0f, 1.0f, 0.0f); 
    glVertex3f( 1.0f,-1.0f, 0.0f); 
    glVertex3f(-1.0f,-1.0f, 0.0f); 
	glEnd();

	if(keys[VK_RIGHT])
	{
	p1 += 0.01f *speed;
	}
	if(keys[VK_LEFT])
	{
	p1 -= 0.01f * speed;
	}
	if(keys[VK_UP])
	{
	boden = false;
	}




	return true;										
}
```


----------



## FSA (20. November 2011)

Warum machst du nicht einfach wenn up gedrückt wird Spieler nach oben bewegen und dann:

```
Player.y -= 100*speed;
```
Das wären glaube ich 10 pixel die Millisekunde 
MfG


----------



## Matthias Reitinger (21. November 2011)

CodeCrafterCpp hat gesagt.:


> Also ich benutze DrawGLScene
> 
> 
> 
> ...


DrawGLScene heißt die Funktion, aber über das verwendete Framework oder gar deine Hauptschleife verrät uns das genau gar nichts… abgesehen davon: der Name der Funktion deutet darauf hin, dass du in dieser deine Welt nur zeichnen und nicht verändern solltest. Dafür gibt es in der Regel eine eigene Update-Funktion. Wenn du uns verraten würdest, welches Framework du verwendest bzw. wie deine Hauptschleife aussieht, dann könnten wir dir dabei vielleicht sogar helfen.

Grüße,
Matthias


----------



## CodeCrafterCpp (21. November 2011)

Ok hier ist der Komplette Code:


```
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>


#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")

HDC hDC = 0;
HGLRC hRC = 0;
HWND hWnd = 0;
HINSTANCE hInstance;		
LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	
RECT window;



GLfloat rviereck;

float p1 = 0.0f;
float p2 = 0.0f;
float p3 = -20.0f;
float speed = 10.0f;
bool boden = true;
float sprung = 1.0f;
float sprunghöhe = 10.0f;
float sprungspeed = 1.0f;
float akthöhe = 0;
LONGLONG g_Frequency, g_CurentCount, g_LastCount;









bool keys[256];
bool active = true;
bool fullscreen = false;

bool InitGL();
void ReSizeGLScene(unsigned int width, unsigned int height);
bool DrawGLScene();
bool KillGLWindow();
bool CreateGLWindow(LPCWSTR title, int width, int height, int bits, bool fullscreenflag);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nlpCmdLine, int nCmdShow);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nlpCmdLine, int nCmdShow)
{
	MSG	msg;									
	bool done = false;								

	if(MessageBox(0, L"Im Vollbildmodus starten?", L"Vollbild?", MB_YESNO | MB_ICONQUESTION) == IDYES)
	{
		fullscreen = true;							
	}

	if(!CreateGLWindow(L"OpenGL", 640, 480, 16, fullscreen))
	{
		return 0;								
	}

	while(!done)								
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))	
		{
			if(msg.message == WM_QUIT)				
			{
				done = true;							
			}
			else									
			{
				TranslateMessage(&msg);				
				DispatchMessage(&msg);			
			}
		}
		else										
		{
			if((active && !DrawGLScene()) || keys[VK_ESCAPE])	
			{
				done = true;							
			}
			else									
			{
				SwapBuffers(hDC);					
			}
		}	
	}

	KillGLWindow();	

	return (msg.wParam);						
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)									
	{
		case WM_ACTIVATE:							
		{
			if(!HIWORD(wParam))					
			{
				active = true;						
			}
			else
			{
				active = false;						
			}

			return 0;								
		}

		case WM_SYSCOMMAND:							
		{
			switch(wParam)							
			{
				case SC_SCREENSAVE:					
				case SC_MONITORPOWER:				
				return 0;							
			}

			break;									
		}

		case WM_KEYDOWN:							
		{
			keys[wParam] = true;

			return 0;								
		}

		case WM_KEYUP:								
		{
			keys[wParam] = false;	

			return 0;							
		}

		case WM_SIZE:								
		{
			ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));  

			return 0;							
		}
	}

	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

bool CreateGLWindow(LPCWSTR title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint PixelFormat;			
	WNDCLASS wc;						
	DWORD dwExStyle;				
	DWORD dwStyle;				
	RECT WindowRect;				
	WindowRect.left = 0;			
	WindowRect.right = width;		
	WindowRect.top = 0;				
	WindowRect.bottom = height;		

	fullscreen = fullscreenflag;	

	hInstance			= GetModuleHandle(NULL);				
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	
	wc.lpfnWndProc		= (WNDPROC) WndProc;					
	wc.cbClsExtra		= 0;									
	wc.cbWndExtra		= 0;									
	wc.hInstance		= hInstance;							
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			
	wc.hbrBackground	= NULL;									
	wc.lpszMenuName		= NULL;									
	wc.lpszClassName	= L"OpenGL";								

	if(!RegisterClass(&wc))									
	{
		MessageBox(NULL, L"Window-Class konnte nicht regsitriert werden!", L"ERROR", MB_OK|MB_ICONEXCLAMATION);

		return false;											
	}
	
	if(fullscreen)												
	{
		DEVMODE dmScreenSettings;								
		memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));	
		dmScreenSettings.dmSize = sizeof(dmScreenSettings);		
		dmScreenSettings.dmPelsWidth = width;				
		dmScreenSettings.dmPelsHeight = height;				
		dmScreenSettings.dmBitsPerPel = bits;					
		dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			if(MessageBox(0, L"Vollbild-Modus wird nicht unterstützt. Window-Mode nutzen?", L"OpenGl - Info", MB_YESNO|MB_ICONEXCLAMATION) == IDYES)
			{
				fullscreen = false;		
			}
			else
			{
				MessageBox(0, L"Programm wird beendet.", L"ERROR", MB_OK|MB_ICONSTOP);

				return false;
			}
		}
	}

	if(fullscreen)												
	{
		dwExStyle = WS_EX_APPWINDOW;								
		dwStyle = WS_POPUP;										
		ShowCursor(FALSE);										
	}
	else
	{
		dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			
		dwStyle = WS_OVERLAPPEDWINDOW;							
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);	

	if (!(hWnd = CreateWindowEx(dwExStyle, L"OpenGL", (LPCWSTR)title, dwStyle |	WS_CLIPSIBLINGS | WS_CLIPCHILDREN,					
								0, 0, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top,	
								NULL, NULL, hInstance, NULL)))								
	{
		KillGLWindow();								
		MessageBox(NULL, L"Fenster konnte nicht erstellt werden!", L"ERROR", MB_OK|MB_ICONEXCLAMATION);

		return false;								
	}

	static PIXELFORMATDESCRIPTOR pfd =				
	{
	    sizeof(PIXELFORMATDESCRIPTOR), 
		1,											
		PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA,								
		bits,										
		0, 0, 0, 0, 0, 0,							
		0,											
		0,											
		0,											
		0, 0, 0, 0,									
		16,											
		0,											
		0,											
		PFD_MAIN_PLANE,								
		0,											
		0, 0, 0										
	};
	
	hDC = GetDC(hWnd);					
	PixelFormat = ChoosePixelFormat(hDC, &pfd);	
	SetPixelFormat(hDC, PixelFormat, &pfd);		
	hRC = wglCreateContext(hDC);				
	wglMakeCurrent(hDC, hRC);					
	
	ShowWindow(hWnd, SW_SHOW);						
	SetForegroundWindow(hWnd);						
	SetFocus(hWnd);									
	ReSizeGLScene(width, height);					

	if(!InitGL())									
	{
		KillGLWindow();								
		MessageBox(NULL, L"Initialization Failed.", L"ERROR", MB_OK|MB_ICONEXCLAMATION);

		return false;								
	}

	return true;								
}

bool KillGLWindow()								
{
	if(fullscreen)										
	{
		ChangeDisplaySettings(0, 0);					
		ShowCursor(TRUE);								
	}

	if(hRC)											
	{
		wglMakeCurrent(0, 0);				
		wglDeleteContext(hRC);					
		hRC = 0;									
	}

	ReleaseDC(hWnd, hDC);				

	DestroyWindow(hWnd);					

	UnregisterClass(L"OpenGL", hInstance);	

	return true;
}

bool InitGL()										
{
	//glEnable(GL_TEXTURE_2D);							
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);				
	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
	glClearDepth(1.0);									
	glDepthFunc(GL_LEQUAL);								
	glEnable(GL_DEPTH_TEST);							
	glShadeModel(GL_SMOOTH);							
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	return true;										
}

void ReSizeGLScene(unsigned int width, unsigned int height)		
{
	if(height == 0)										
		height = 1;										

	glViewport(0, 0, width, height);						

	glMatrixMode(GL_PROJECTION);						
	glLoadIdentity();									

	gluPerspective(45.0f, (float)width/(float)height, 0.1f, 500.0f);

	glMatrixMode(GL_MODELVIEW);							
	glLoadIdentity();									
}

bool DrawGLScene()									
{
	QueryPerformanceCounter((LARGE_INTEGER*)&g_CurentCount);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	


	
	glLoadIdentity();
	glTranslatef(p1, p2, p3);
	glRotatef(rviereck,0.0f,1.0f,0.0f);

	glBegin(GL_QUADS);
	glColor3f(0.0f,1.0f,0.0f); // Blau (Oben)
    glVertex3f(-1.0f, 1.0f, 0.0f); 
    glVertex3f( 1.0f, 1.0f, 0.0f); 
    glVertex3f( 1.0f,-1.0f, 0.0f); 
    glVertex3f(-1.0f,-1.0f, 0.0f); 
	glEnd();

	if(keys[VK_RIGHT])
	{
	p1 += 0.01f *speed;
	}
	if(keys[VK_LEFT])
	{
	p1 -= 0.01f * speed;
	}
	if(keys[VK_UP])
	{
	boden = false;
	}




	return true;										
}
```


----------



## CodeCrafterCpp (22. November 2011)

Sprachlos noch nie so ein guten Code gesehen? 
Ich hab es einfach zusammengewürfelt aus meinen Wissen könnt ihr mir helfen oder mir Tipps geben falls ich etwas ganz schrecklich geschreiben habe....

mfG


----------



## CPoly (22. November 2011)

Ich habe jetzt nicht alle Posts im Details gelesen und auch deinen Code nicht ganz durchsehen, aber ich denke du solltest dir unbedingt folgenden Artikel durchlesen:
http://www.koonsolo.com/news/dewitters-gameloop/

Auch wenn ich jetzt mit Spielentwicklung nichts mehr zu tun habe, hat mir dieser Artikel damals sehr viel geholfen.


----------



## CodeCrafterCpp (22. November 2011)

Ich hab mal ein bisschen rumprobiert aber nicht richtig weiter gekommen. Soll ich jetzt durch ein Game-Loop immer wieder DrawGLScene aufrufen oder wie? Ich hab da auch ein bisschen rumgespielt und das weiteste war das ich ohne Fehlermeldung starten konnte aber dann nur ein Windows Fenster gekommen ist aber nichts mehr und das hat dann zeimlich stark gehangen also VS2010


----------



## CPoly (22. November 2011)

CodeCrafterCpp hat gesagt.:


> Soll ich jetzt durch ein Game-Loop immer wieder DrawGLScene aufrufen oder wie?



Wenn ich in deinen Code gucke (Zeile 66 und 82) machst du genau das ja bereits.

Es geht darum, dass der Loop eine gewisse Zeit braucht, um einmal durchzulaufen. Diese Zeit kannst du messen und anhand der Dauer dann berechnen, wie weit sich die Figur bewegen muss (Geschwindigkeit und Zeit sind bekannt, also kannst du den Weg ausrechnen).

Mehr wollte ich mit dem Link nicht sagen. Was darüber hinaus geht, z.B. die exakte Implementierung, da kann ich dir nicht weiter helfen.


----------



## FSA (23. November 2011)

Also du brauchst halt einen Timer der von Anfang bis Ende der Update und Render Methoden läuft und dann stoppt und auf 0 gesetzt wird.
Dann bekommst eine Zahl. Mit der musst du halt alles malnehmen. Sonst läuft das Spiel unterschiedlich schnell auf anderen PCs. Und wenn du dann auch wirklich reales springen darstellen willst empfehle ich dir Box 2D. Dann einfach mal nach der Funktion setvelocity suchen.
MfG


----------



## CodeCrafterCpp (23. November 2011)

Wie ok das hab ich ja alles verstanden aber wie mach ich ein game_update und ein Display update mit OpenGL also ich brauch eine Funktion die alle berechnet und so und eine die das dann Zeichnet richtig?
Und wie mach ich das am schlausten? Ok danke für den Vorschlag mit Box 2D möchte dann aber lieber selber den Sprung machen....

mfG


----------



## FSA (24. November 2011)

Also wenn du nur eine Update und Render Funkion willst mache es doch so:

```
while( !bEndGame )
{
  Update();
  Render();
}
```
Ich verstehe irgendwie dein Problem nicht richtig...
In der Update Methode würde ich dann die Nachrichten von deinem Fenster handeln. Und wenn sich im Spiel was bewegen soll musst halt noch 'ne Move() Funktion einbauen 
Und ich glaube du weißt wie du die Nachrichten abfängst, oder?
MfG


----------



## CodeCrafterCpp (24. November 2011)

Ja das verstehe ich auch aber  ich verstehe nicht aber wie die Render Funktion auszusehen hat mit OpenGL...


----------



## FSA (24. November 2011)

Also jetzt verstehe ich das nicht.
Hast du denn überhaupt schon eine renderfunktion geschrieben?
Also wenn nicht dann beschäftige dich nochmal mit den Grundlagen.
Und ich bin ja directx ler aber ich denke mal scene beginnen rendern Scene beenden und bildpuffer sichtbar machen. Aber wenn du wirklich nicht weißt wie man das macht dann lass das erstmal mit der spieleprogrammiereung


----------



## CodeCrafterCpp (25. November 2011)

Also ich versteh nicht den Unterschied oder was es macht ist Update() einfach auslesen welche Taste ist gedrückt und Pos in einer Variable reinschreiben und Render() einfach DrawGLScene also Zeichnen oder wie?


----------



## FSA (26. November 2011)

Kommt drauf an wie du es möchtest 
Mach doch in Update erstmal ein Message Handler rein. in Render machst du nichts anderes außer den Bildschirm zu leeren. Dann vll noch Tastaturabfrage das wenn ESC gedrückt-> Beenden. Move lass erstmal weg. Was hast du denn eigentlich bis jezt schon? Denn wenn du noch nichtmal was anzeigst nützt dir ne Variable auch nicht viel 
MfG


----------



## CodeCrafterCpp (26. November 2011)

Wofür eigendlich Message Handler ist es nicht einfach mit Variablem zu Arbieten?


----------



## FSA (30. November 2011)

Also das muss ich nicht verstehen. Hast du denn überhaupt ein Fenster!? Hast du das Fenster als Render-target?
Du brauchst eine Nachrichtenfunktion damit du dein Fenster benutzen kannst 
Und wie auch immer du das mit Variablen machen willst->weiß ich nicht.
MfG


----------



## CodeCrafterCpp (1. Dezember 2011)

Ja ok wusste nicht so was ein Message Handler ist hab mir mal Win-Api ein bisschen gelernt wusste nicht das ich das brauch soll das in der Update Funktion? Ich hab auf MSDN geschaut ist der Handler jetzt die Callback oder wie?


----------



## FSA (2. Dezember 2011)

Also in welche Funktion du das schreibst ist dir überlassen. Von mir aus kannst du die Funktion auch Wurst nennen, wäre aber übersichtshalber nicht empfehlenswert  Also meine Spiele sind eigentlich immer mit der GameLoop ausgestattet. Diese ruft dann erst Update, Move und schließlich noch Render auf  In Update behandle ich die Fenster nachrichten, obwohl ich damit nichts mache(ich arbeite nur mit DirectInput). In Move werde dann alle möglichen Bewegungen ausgeführt, sowie die Physik geupdatet, und in Render wird halt alles gerendert. Daher das ich mir eine Engine schreibe, ist die GameLoop in der Engine und die vergangene Zeit rechnet mein Engine auch noch aus und übergibt sie dann der Move und Render Methode.
Wie genau das funnktioniert möchte ich nicht unbedingt erklären, aber gucke dir mal QueryPerformanceCounter an um die Zeiten zu messen 
MfG


----------



## CodeCrafterCpp (2. Dezember 2011)

Ok Danke...
Also mach die Update so WM und so ein kram  die Move halt welche taste gedrückt ist und Render macht dann das Bild...Mein Problem war ja eigendlich nur das mit den Springen also das mit den Zählen aber wie Mess ich das mach ich vor den aufrufen von Update die erste Messung und unter Rendern die Zweite? Und wie rechne ich das denn?


----------



## FSA (2. Dezember 2011)

Also wie du das misst: Anfang bis Ende  Du ließt die Zeit aus mit der Funktion die ich schon geschrieben habe. Dann machst du Meesage Handler, Move, Render und nimmst wieder die Zeit. Dann hast du 2 Zeiten. Anschließend rechnest du so:

```
Zeit = Zeit2 - Zeit1;
```
Das war nicht schwer oder 
Und in move werde Tasten abgefangen ja aber auch Objekte gedreht bewegt usw...
PS In welcher reihfolge die GameLoop alles abfrag ist dir überlassen. Es währe aber ratsam den Message Handler am Anfang aufzurufen.
Also:

```
// Startzeitpunkt messen
QueryPerformanceCounter(...);

// Nachrichten verarbeiten
while( PeekMessage( &Message, NULL, 0, 0, PM_REMOVE ) )
{
	TranslateMessage( &Message );
	DispatchMessage( &Message );

        if( Message.message == WM_QUIT )
	{
		// Game Loop verlassen
		bEndGame = true;
	}	
}

// Render
// Move
// und was du sonst noch brauchst
QueryPerformanceCounter(...);
```
MfG
EDIT: Wenn du es ganz genau haben willst mit Frame Limiter dann musst du noch geteilt durch die Frequenz nehemen


----------

