Advertisement

"Skidding"

Started by September 15, 2003 03:48 PM
11 comments, last by zoidy 21 years, 5 months ago
I am experiencing something a little perculiar. I am using the key capture method in many of Nehes examples (i.e. not DX, which I cant use for reasons I wont bore you with). When one presses the up key, they move forward. All well and good. But when they release it, they keep moving for a little before stopping. The longer they hold the key down, the longer the "skidding" goes on for. Its drastically reduced (but not totally eliminated) on faster machines, so it would appear to be linked with framerate, but why am I having this problem at all? Other projects with similar or greater graphical output dont have this prob. Outputing stuff to the screen shows the program thinks the button is just being held down longer than it is. Any suggestions as to what I could do to solve this, or even track down exactly why it happens, would be greatly appreciated... Thanks zoidy
If you are using a message handler, you are only calling it every frame. So therefore, if you are in the middle of a frame and you press a key, it will take until the next frame for the computer to notice.
Advertisement
Thank you, but if I understand you correctly I dont think thats it. As I say, the problem gets worse the longer you hold the button down. The mouse input still seems to work real-time (movement, rather than buttons) so I have actually been able to release the up button and still been able to steer around corners for a few seconds before the release key was acknowledged and the player came to a stop.
Could it be anything else?
Thanks
zoidy
1. IF it's only a tiny tiny delay it could be a psycological effect.
Your reaction time is about 0.2 seconds, where you command your finger to release the button and 0.2 seconds later you see it happen.

2. the keyboard could have a small delay.

This is not realy a problem, if you add a small acceleration factor to your movements you will have much smoother movement's and this delay that's bugging you will allso not be as apparent as before.
Allso add filers to your mouse movements and your fps counter, the latter one gave me mutch nicer fps numbers(from 15 to 300).


or there may be way to mutch cola in your keyboard.

[edited by - lc_overlord on September 16, 2003 4:42:13 PM]
How are you converting key stroke into motion? Do you use any sort of physics engine? I am developing with a physics engine where the skidding is intentional because of momentum, friction, etc.
variant: basically, when a key is pressed:
xpos += (float)sin(heading*piover180) * MoveDistance;
where MoveDistance is 0.75 and xpos is the position in the level. Obviously that is altered depending on the key in question. So no, there is no kind of physics engine. If the time didnt change so much I might try to claim it was a physics thing though!

lc_overlord: well, the delay has been up to about 12 seconds on my slower computer, and at the time the framerate was about 10-15. Pretty noticable.
And... sorry if I am being dense, but I am not sure what you mean by "add filers to your mouse movements and your fps counter". Could you explain please?
Thanks
zoidy
Advertisement
MY bad that should be filters not filers, basicly you take the last 5-10 values, add them together and then divide by 5-10(you should know how this works).

From what you have said it seams to me that it waits for a certain number of frames before reacting.
THis is odd, so could you please send some code concerning the keychacking ,movement and related.

sidenote: You don''t seem to have some kind of "frame time" value in that movement algo.
movedistance should realy be (30/frametime) instead of just 0.75.
Idon''t think that is the problem though, but youll get a constant speed while moving no matter what your fps
Ok. I have played about, and randomly changed stuff, but to be honest, I am not sure why it is acting like this. As I understand things, I should be getting what the illustrious Anonymous Poster said, i.e. it should only take until the next frame until input is processed. I dont see why it takes multiple frames. Below is (slightly abbreviated, but hopefully still fully understandable, and only unimoprtant things are taken out) code. If anyone can suggest anything, please let me know...

typedef struct {			// Contains information vital to a window	HWND		hWnd;		// Window handle	HDC		hDC;		// Device context	HGLRC		hRC;		// Rendering context	HINSTANCE	hInstance;	// Application instance	const char*	className;	// Application class name	char*		title;		// Window title	int		width;		// Width	int		height;		// Height	int		bits;		// Bits per pixel	bool		FullScreen;	// Are we running in fullscreen?} BC_WindowData;			// GL_Window//// Global VarsBC_WindowData Win;bool KeyPressed [256];bool PreviousKeys [256];GLuint base;bool CreateWindow = TRUE;float MoveDistance = 1.750;float heading=90;const float piover180 = 0.0174532925f;float lookupdown = 0.0f;float Timer;//FRAME COUNTER CODE: for debugging / optimisingstatic FLOAT fps = 0.0f;static FLOAT last_time = 0.0f;static DWORD frames = 0L;float times;// END// Initialises stuff for the programvoid Initialise (void){	// **** Load and create font ****	glDepthFunc (GL_LEQUAL);	// Less or equal depth testing	glEnable (GL_DEPTH_TEST);	// Enable depth testing		SetCursorPos(320,240);		// Set the mouse position as the centre of the window}void TerminateWindow (HWND hwnd){	// **** Delete font ****	// **** Release device context etc ****}// Functions to set the pixel format for the device contextvoid SetupPixelFormat (HDC hDC){	int nPixelFormat;	// Pixel Format Index	static PIXELFORMATDESCRIPTOR pfd = {		sizeof (PIXELFORMATDESCRIPTOR),		// size of structure			1,				// version, always ''1''			PFD_DRAW_TO_WINDOW |		// support window			PFD_SUPPORT_OPENGL |		// support opengl			PFD_DOUBLEBUFFER,		// support double buffering			PFD_TYPE_RGBA,			32,				// 32 bit colour mode			0, 0, 0, 0, 0, 0,		// ignore colour bits			0,				// no alpha buffer			0,				// ignore shift bit			0,				// no accumulation buffer			0, 0, 0, 0,			// ignore accumulation bits			16,				// 16 bit z-buffer size			0,				// no stencil buffer			0,				// no auxiliary buffer			PFD_MAIN_PLANE,			// main drawing plane 			0,				// reserved			0, 0, 0};			// layer masks ignored	// choose best matching pixel format, return index	nPixelFormat = ChoosePixelFormat (hDC, &pfd);	// set pixel format to device context	SetPixelFormat (hDC, nPixelFormat, &pfd);}// the Windows procedure event handlerLRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HGLRC hRC;			// rendering context	static HDC hDC;				// device context	int width, height;			// window width and height	switch (message)	{		case WM_SYSCOMMAND:		// Intercept system commands		{			switch (wParam)		// Check system calls			{				case SC_SCREENSAVE:	// Screensaver trying to start?				case SC_MONITORPOWER:	// Monitor trying to enter powersave?				return 0;		// Prevent from happening			}			break;				// Exit		}		return 0;				// Return		case WM_CREATE:				// window is being created			hDC = GetDC (hwnd);		// get current windows device context			Win.hDC = hDC;			SetupPixelFormat (hDC);			// create rendering context and make it current			hRC = wglCreateContext (hDC);			wglMakeCurrent (hDC, hRC);			return 0;			break;		case WM_CLOSE:				// window is closing			// send WM_QUIT to message queue			PostQuitMessage (0);			return 0;			break;		case WM_SIZE:			height = HIWORD (lParam);			width = LOWORD (lParam);			if (height == 0)		// avoid divide by zero				height = 1;			// reset the viewport to new dimensions			glViewport (0, 0, width, height);			glMatrixMode (GL_PROJECTION);	// set projection matrix			glLoadIdentity ();		// reset projection matrix			// calculate aspect ratio of window			gluPerspective (45.0f, (GLfloat)width / (GLfloat)height,							0.25f, 1000.0f);			glMatrixMode (GL_MODELVIEW);	// set modelview matrix			glLoadIdentity ();			return 0;			break;		case WM_KEYDOWN:			KeyPressed[wParam] = true;			return 0;			break;		case WM_KEYUP:			KeyPressed[wParam] = false;			return 0;			break;		default:			break;	}	return (DefWindowProc (hwnd, message, wParam, lParam));}bool windowsetup (RECT &windowRect, DWORD &dwExStyle, DWORD &dwStyle){	WNDCLASSEX windowClass;	// fill out the window class structure	windowClass.cbSize = sizeof (WNDCLASSEX);	windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	windowClass.lpfnWndProc = WndProc;	windowClass.cbClsExtra = 0;	windowClass.cbWndExtra = 0;	windowClass.hInstance = Win.hInstance;	windowClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);	// default icon	windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);	// default arrow	windowClass.hbrBackground = NULL;			// dont need background	windowClass.lpszMenuName = NULL;			// no menu	windowClass.lpszClassName = Win.className;	windowClass.hIconSm = LoadIcon (NULL, IDI_WINLOGO);	// small logo	// register the window class	if (!RegisterClassEx (&windowClass))		return 0;	if (Win.FullScreen)	{		DEVMODE dmScreenSettings;			// device mode		memset (&dmScreenSettings, 0, sizeof(dmScreenSettings));		dmScreenSettings.dmSize = sizeof(dmScreenSettings);		dmScreenSettings.dmPelsWidth = Win.width;		dmScreenSettings.dmPelsHeight = Win.height;		dmScreenSettings.dmBitsPerPel = Win.bits;		dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;		if (ChangeDisplaySettings (&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)		{			// setting display mode failed, switch to windowed			MessageBox (NULL, "Display mode failed", NULL, MB_OK);			Win.FullScreen = false;		}	}	if (Win.FullScreen)					// if we are still fullscreen	{		dwExStyle = WS_EX_APPWINDOW | WS_EX_TOPMOST;		dwStyle = WS_POPUP;		ShowCursor (FALSE);	}	else							// windowed mode	{		dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;		dwStyle = WS_OVERLAPPEDWINDOW;	}	AdjustWindowRectEx (&windowRect, dwStyle, FALSE, dwExStyle);	// class registered, so now create window	Win.hWnd = CreateWindowEx (dwExStyle,			// extended style			Win.className,				// class name			Win.title,				// app name			dwStyle | WS_CLIPCHILDREN |			WS_CLIPSIBLINGS,			// style			0, 0,					// x, y coordinate			Win.width, 			Win.height,				// width, height			HWND_DESKTOP,				// handle to parent			NULL,					// handle to menu			Win.hInstance,				// application instance			NULL);					// no extra params	// check if window creation failed (hwnd would equal null)	if (!Win.hWnd)		return true;					// Failed, so we are done, quit	ShowWindow (Win.hWnd, SW_SHOW);				// display the window	UpdateWindow (Win.hWnd);				// update the window	return false;						// Success, were not done}bool ValidKey (char Key){	// If the key has been pressed, and it wasnt pressed in the previous cycle	if ((KeyPressed [Key] == true)&&(PreviousKeys [Key] == false))		return true;					// Return true (ie successful)	else return false;					// Otherwise return false}void Update (bool &done, POINT &mpos, Poly Quad[Wallno], Box Rack [Rackno]){	mpos = GetMousePosition ();	if (mpos.y != 240)	lookupdown += (mpos.y - 240)/MouseSensitivity;	if (mpos.x != 320)		heading -= (mpos.x - 320)/MouseSensitivity;	if (heading > 360) heading -= 360;	else if (heading < 0) heading += 360;	SetCursorPos(320,240);			// Set the mouse position as the centre of the window	if (ValidKey(VK_F12))	{		if (Win.FullScreen)		// Is window in fullscreen mode		{			ChangeDisplaySettings (NULL,0);	// Switch back to desktop resolution			ShowCursor (TRUE);		// Show cursor		}			Win.FullScreen = (Win.FullScreen == true) ? false : true;		done = true;	}	if (ValidKey(VK_F7))		lighting = (lighting == true) ? false : true;	float newx = xmov;	float newz = zmov;	MoveDistance = 1.75f/(times*0.005f);	if ((KeyPressed [VK_UP])&&(!KeyPressed [VK_DOWN]))	{		newx -= (float)sin(heading*piover180) * MoveDistance;		newz -= (float)cos(heading*piover180) * MoveDistance;	}	else if ((KeyPressed [VK_DOWN])&&(!KeyPressed [VK_UP]))	{		newx += (float)sin(heading*piover180) * MoveDistance;		newz += (float)cos(heading*piover180) * MoveDistance;	}	if ((KeyPressed [VK_LEFT])&&(!KeyPressed [VK_RIGHT]))	{		newx += (float)sin((heading - 90)*piover180) * MoveDistance;		newz += (float)cos((heading - 90)*piover180) * MoveDistance;	}	else if ((KeyPressed [VK_RIGHT])&&(!KeyPressed [VK_LEFT]))	{		newx += (float)sin((heading + 90)*piover180) * MoveDistance;		newz += (float)cos((heading + 90)*piover180) * MoveDistance;	}	// **** COLLISION DETECTION ****	xpos = newx;	zpos = newz;			for (int i = 0; i < 256; i++)		PreviousKeys [i] = KeyPressed[i];}void Draw (POINT mpos, Poly Quad[Wallno], Box Rack[Rackno]){	// do rendering here	// clear screen and depth buffer	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	glLoadIdentity ();	// reset modelview matrix	glPushMatrix();	glRotatef(lookupdown,1.0f,0,0);	glRotatef(360.0f-heading,0,1.0f,0);	glTranslatef (-xmov, 0.0f, -zmov);	glBegin (GL_QUADS);		for (int i = 0; i < Wallno-2; i++)		{			glNormal3f (Quad[i].Normal[0], Quad[i].Normal[1], Quad[i].Normal[2]);			glVertex3f (Quad[i].One[0],   Quad[i].One[1],   Quad[i].One[2]);			glVertex3f (Quad[i].Two[0],   Quad[i].Two[1],   Quad[i].Two[2]);			glVertex3f (Quad[i].Three[0], Quad[i].Three[1], Quad[i].Three[2]);			glVertex3f (Quad[i].Four[0],  Quad[i].Four[1],  Quad[i].Four[2]);		}	glEnd();			glColor3f (0.0f, 0.0f, 1.0f);	glPopMatrix();	glMatrixMode(GL_PROJECTION);			// Select The Projection Matrix	glPushMatrix();					// Store The Projection Matrix	glLoadIdentity();				// Reset The Projection Matrix	glOrtho(0,640,480,0,-1,1);			// Set Up An Ortho Screen	glMatrixMode(GL_MODELVIEW);			// Select The Modelview Matrix	glTranslated(0.0f, 0.0f, 1.0f);			// Move To The Current Mouse Position	glPrint (5.0f, 10.0f, "Press Esc to quit");	glMatrixMode(GL_PROJECTION);			// Select The Projection Matrix	glPopMatrix();					// Restore The Old Projection Matrix	glMatrixMode(GL_MODELVIEW);			// Select The Modelview Matrix	glFlush();}// the main Windows entry pointint WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 					LPSTR lpCmdLine, int nShowCmd){	MSG msg;				// message	bool done;				// "app complete" flag	DWORD dwExStyle;			// Windows extended style	DWORD dwStyle;				// Window style	RECT windowRect;	// Window Properties:	Win.hInstance = hInstance;	Win.className = "BaseCode";	Win.title = "OpenGL Basecode";	Win.width = 640;	Win.height = 480;	Win.bits = 16;	Win.FullScreen = false;	windowRect.left = (long)0;	windowRect.right = (long)Win.width;	windowRect.top = (long)0;	windowRect.bottom = (long)Win.height;	POINT mpos;	Poly Quad[Wallno];	done = false;				// initialise the loop condition variable	while (ProgramLooping)	{		done = windowsetup (windowRect, dwExStyle, dwStyle);		Initialise ();		// main message loop		while (!done)		{			PeekMessage (&msg, Win.hWnd, NULL, NULL, PM_REMOVE);			if ((msg.message == WM_QUIT)||			// received a WM_QUIT message?				(KeyPressed[VK_ESCAPE]))		// Pressed Escape			{				ProgramLooping = false;				done = true;				// if so, time to quit the app			}			else			{				// Main logic loop				// FRAMES COUNT processing				times = timeGetTime()*0.001f;//get current time in seconds				++frames;				// update the frame rate 1ce per second				if (times-last_time>1.0f)				{					fps = frames/(times-last_time);					last_time = times;					frames = 0L;				}				// END				Update (done, mpos, Quad, Rack);				Draw (mpos, Quad, Rack);								SwapBuffers (Win.hDC);				TranslateMessage (&msg);				DispatchMessage (&msg);			}		} // while (done)		TerminateWindow (Win.hWnd);		UnregisterClass (Win.className, Win.hInstance);		// UnRegister window class	}	return msg.wParam;}

For those of you who waded through that thank you. I hope inspiration strikes.
For those of you who didnt, another puzzler. In fullscreen, textures work fine. However, in a window they are all distorted and jagged, as if at regular intervals it is being pulled in opposite directions. Any ideas?
Thanks...
zoidy
Well this is coming from a physics enthusiast, but you may want a fancier way of calculating skid which results from static friction from the surface the thing is moving on pulling in the opposite direction of the thing at some force. But it sounds to me just like you need to decelerate the thing time-based instead of frame-based which would involve calculating a desirable deceleration at fps = 1 then dividing this number by the FPS each frame so that all the frames combined movement in one second would equal the desired movement in one second. Hope that helps
My fellow Americans I have just signed legislation that outlaws Russia forever. Bombing will commence in five minutes.
Just an idea might be that, while holding the directional button, you are queueing (sp?) up events. Kind of like holding down a key when you are typing. Then, maybe your engine can only execute N of those keypresses every frame. That would explain why the longer you hold it, the longer you "skid". Hopefully this helps,

[ XtaC ]

This topic is closed to new replies.

Advertisement