collision detection with a 2d tile map?

Started by
4 comments, last by werdy666 21 years, 6 months ago
hi. i am trying to implement some sort of collision detection for my little tile map using opengl. However it doesn''t want to work for me! at the moment i am just testing the right movement of a quad and it goes over to the right off my map by 2 or 3 tiles before stopping. Here is my rendering and keyboard checking stuff. Maybe someone could help me out ??
  
#define NUMBER_OF_ANIMATIONS 4

using namespace std;
extern Texture texture[3];
extern int mapdata[28][25];

double playerx = -15.0;
double playery = 11.0;
int playerposx = 1;
int playerposy = 1;

float plyx = 0;
float plyy = 0;

double current_anim = 1;

int DrawMap()
{
	//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glDisable(GL_ALPHA_TEST);
	for (int x=0;x < 28;x++)
		{
		for (int y=0;y<25;y++)
			{
			glLoadIdentity();
			glTranslatef(-16.0f+x,12.0f-y,-30.0f);			
			glBindTexture(GL_TEXTURE_2D, texture[(mapdata[x][y])].texID);
			glBegin(GL_QUADS);
				glTexCoord2d(0.0,1.0);
				glVertex3f(-0.5f, 0.5f, 0.0f);
				glTexCoord2d(1.0,1.0);
				glVertex3f(0.5f, 0.5f, 0.0f);
				glTexCoord2d(1.0,0.0);
				glVertex3f(0.5f, -0.5f, 0.0f);
				glTexCoord2d(0.0,0.0);
				glVertex3f(-0.5f, -0.5f, 0.0f);
			glEnd();
			}
		}
	glEnable(GL_ALPHA_TEST);
return true;
}

int DrawPlayer(double anim)
{
			// need to add player x and y pos to translatef command

			// also need to incorporate the anim in the function header

			// aswell as the timer.

	//	angle += (float)(milliseconds) / 5.0f;						// Update angle Based On The Clock


			glLoadIdentity();
			glTranslatef(playerx,playery,-30.0f);			
			glBindTexture(GL_TEXTURE_2D,texture[2].texID);

			float sprite = (anim/NUMBER_OF_ANIMATIONS);
			float sprite2 = sprite-(0.25);

			glBegin(GL_QUADS);
				glTexCoord2d(0.0,1.0-sprite2);
				glVertex3f(-0.5f, 0.5f, 0.0f);
				glTexCoord2d(1.0,1.0-sprite2);
				glVertex3f(0.5f, 0.5f, 0.0f);
				glTexCoord2d(1.0,1.0-sprite);
				glVertex3f(0.5f, -0.5f, 0.0f);
				glTexCoord2d(0.0,1.0-sprite);
				glVertex3f(-0.5f, -0.5f, 0.0f);
			glEnd();

return true;
}

int DrawGLScene(GLvoid)								// Here''s Where We Do All The Drawing

{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// Clear The Screen And The Depth Buffer

	glLoadIdentity();							// Reset The Current Modelview Matrix


	DrawMap();
	DrawPlayer(current_anim);


	return true;								// Everything Went OK



}

int MoveAi()
{
return true;
}

int CheckKeyboardInput(DWORD milliseconds)
{
	double werd = (milliseconds*0.001);
		
	if (keys[VK_ESCAPE])				// Was ESC Pressed?

	{
		done=TRUE;				// ESC Signalled A Quit

	}
	if (keys[VK_F1])					// Is F1 Being Pressed?

	{
		keys[VK_F1]=FALSE;				// If So Make Key FALSE

		KillGLWindow();					// Kill Our Current Window

		fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode

		// Recreate Our OpenGL Window

		if (!CreateGLWindow("Opengl Basecode v0.25",SCREENWIDTH,SCREENHEIGHT,BITSPERPIXEL,fullscreen))
		{
			return 0;				// Quit If Window Was Not Created

		}
	}
	if (keys[VK_LEFT])
	{
	//	keys[VK_LEFT] = false;

		//playerx -= (float) (milliseconds) / 200.0f;

		playerx -= (float) (werd) *5;
		current_anim = 4;
	}
	if (keys[VK_RIGHT])
	{
	//	keys[VK_RIGHT] = false;

		//playerx += (float) (milliseconds) / 200.0f;

		playerx += (werd) *5;
		current_anim = 3;
		plyx += (werd) *5;
		if (mapdata[playerposx][playerposy] == 0)
			{
			playerx -= (werd) *5;
			current_anim = 3;
			plyx -= (werd) *5;
			}
			
		if  (plyx >=1.0f)
			{
			plyx = 0.0f;
			playerposx++;
			}
		
	}
	if (keys[VK_UP])
	{
		//keys[VK_UP] = false;

		//playerx -= (float) (milliseconds) / 200.0f;

		playery += (float) (werd) *5;
		current_anim = 4;
	}
	if (keys[VK_DOWN])
	{
	//	keys[VK_DOWN] = false;

		//playerx += (float) (milliseconds) / 200.0f;

		playery -= (float) (werd) *5;
		current_anim = 3;
	}

return true;
}

void Update (DWORD milliseconds)								// Perform Motion Updates Here

{
	CheckKeyboardInput(milliseconds);
	MoveAi();
	DrawGLScene();
//	angle += (float)(milliseconds) / 5.0f;						// Update angle Based On The Clock

}

  
Advertisement
ok i have managed to get some sort of collision detection happenning but its not perfect. sometimes i can move left and i walk right through the wall if i am not right in line with it, and i can''t fit through some small gaps!

here is my revised drawing and keyboard input functions


  #define NUMBER_OF_ANIMATIONS 4using namespace std;extern Texture texture[3];extern int mapdata[28][25];double playerx = -15.0;double playery = 11.0;double county = 1;double countx = 1;double current_anim = 1;int DrawMap(){	glDisable(GL_ALPHA_TEST);	for (int x=0;x < 28;x++)		{		for (int y=0;y<25;y++)			{			glLoadIdentity();			glTranslatef(-16.0f+x,12.0f-y,-30.0f);						glBindTexture(GL_TEXTURE_2D, texture[(mapdata[x][y])].texID);			glBegin(GL_QUADS);				glTexCoord2d(0.0,1.0);				glVertex3f(-0.5f, 0.5f, 0.0f);				glTexCoord2d(1.0,1.0);				glVertex3f(0.5f, 0.5f, 0.0f);				glTexCoord2d(1.0,0.0);				glVertex3f(0.5f, -0.5f, 0.0f);				glTexCoord2d(0.0,0.0);				glVertex3f(-0.5f, -0.5f, 0.0f);			glEnd();			}		}	glEnable(GL_ALPHA_TEST);return true;}int DrawPlayer(double anim){			glLoadIdentity();			glTranslatef(playerx,playery,-30.0f);						glBindTexture(GL_TEXTURE_2D,texture[2].texID);			float sprite = (anim/NUMBER_OF_ANIMATIONS);			float sprite2 = sprite-(0.25);			glBegin(GL_QUADS);				glTexCoord2d(0.0,1.0-sprite2);				glVertex3f(-0.5f, 0.5f, 0.0f);				glTexCoord2d(1.0,1.0-sprite2);				glVertex3f(0.5f, 0.5f, 0.0f);				glTexCoord2d(1.0,1.0-sprite);				glVertex3f(0.5f, -0.5f, 0.0f);				glTexCoord2d(0.0,1.0-sprite);				glVertex3f(-0.5f, -0.5f, 0.0f);			glEnd();return true;}int DrawGLScene(GLvoid)								// Here''s Where We Do All The Drawing{	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// Clear The Screen And The Depth Buffer	glLoadIdentity();							// Reset The Current Modelview Matrix	DrawMap();	DrawPlayer(current_anim);	return true;								// Everything Went OK}int MoveAi(){return true;}int CheckKeyboardInput(DWORD milliseconds){	double werd = (milliseconds*0.001);			if (keys[VK_ESCAPE])				// Was ESC Pressed?	{		done=TRUE;				// ESC Signalled A Quit	}	if (keys[VK_F1])					// Is F1 Being Pressed?	{		keys[VK_F1]=FALSE;				// If So Make Key FALSE		KillGLWindow();					// Kill Our Current Window		fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode		// Recreate Our OpenGL Window		if (!CreateGLWindow("Opengl Basecode v0.25",SCREENWIDTH,SCREENHEIGHT,BITSPERPIXEL,fullscreen))		{			return 0;				// Quit If Window Was Not Created		}	}	if (keys[VK_LEFT])	{		playerx -= .1;		current_anim = 4;		countx-=.1;		if ( (mapdata[(int)countx][(int)county] == 0) )			{				playerx += 0.1;				countx+=.1;			}	}	if (keys[VK_RIGHT])	{		playerx += 0.1;		current_anim = 3;		countx+=0.1;		if ( (mapdata[(int)countx][(int)county] == 0) || (mapdata[(int)countx+1][(int)county] == 0))			{				playerx -= 0.1;				countx-=.1;			}	}	if (keys[VK_UP])	{		playery += .1;		current_anim = 2;		county-=.1;		if ( mapdata[(int)countx][(int)county] == 0)			{				playery -= .1;				county+=.1;			}	}	if (keys[VK_DOWN])	{		playery -= .1;		current_anim = 1;		county+=.1;		if ( (mapdata[(int)countx][(int)county] == 0) || (mapdata[(int)countx][(int)county+1] == 0))			{				playery += .1;				county-=.1;			}	}return true;}void Update (DWORD milliseconds)								// Perform Motion Updates Here{	CheckKeyboardInput(milliseconds);	MoveAi();	DrawGLScene();}  


And if u would like the complete program go here http://werdy666.20megsfree.com
Im, not exactly sure about this sort of game, never spent too much time thinking tile based, but I had a similar broblem with a tetris clone i was making.

Firstly are u sure u need to be using an OR clause in the collision check? I assume the code says, "if the tile im on is clear OR the next tile is clear, then walk...". I would have thought that you would only want to move if the tile your on AND the next tile were clear.

The way I managed to get round this was, to slice the space up into squares (your tiles) and then decide which square the player co-ords were in. Looking at ur code I think u shouldn''t rely on the conversion of float to int to convert from point to square... calculate it ur self. Id be more help but I can''t look at my own code now, and that was years ago...
Thanks for your input TheSyan.

The main reason for the OR instead of AND is that cause i only move my player 0.1 at a time, if i was moving left and had just moved into the last tile before a wall, wouldn''t it stop me straight away without allowing me to move right up against the wall? But it is something i will put more thought into.

I am a beginner, so could you maybe give me some hints or point me to a website that will help me understand converting a float such as 1.245 to an int?

again thanks for your input!




Werdy666

My Homepage : http://werdy666.20megsfree.com/
Ok... the conversion method... there''s no garentee this is correct, its all from memory...

U know the size of your tile grid, say 100.0f gl co-ordinates square, and your player co-ords, say for example ( 20.3f, 10.2f ). Oh and your tile size, Ill say 10.0f by 10.0f.

So you start by finding the player co-ords relative to the grid, say the grids 0,0 cell starts at gl(10.0f,0.0f,0.0f). The player co-ords relative would be ( 10.3f, 10.2f ).

Then you round up/down the player co-ords to the nearest integer. Theres a function somewhere in the C++ math libs, look in the help files for that. It goes something like,

int player_tile_x = rounddown( player_x );int player_tile_y = rounddown( player_y );This gives you a player tile of (10, 10) if u round down. Whether you round up or down, I think changes whether the player_tile_ values start from 0 or 1...Example:  |0 | 1 | 2 | 3 | ...          -----|---|---|---| ...0 |  |   |   |   | ...-----|---|---|---| ...1 |  |   |   |   | ...-----|---|---|---| ...2 |  |   |   |   | ...-----|---|---|---| ...3 |  |   | P |   | ...-----|---|---|---| ...Now u can use these co-ords to check against your tile grid (but get the start point right or u end up going off the grid''n''stuff).That was a bit messy and I confused my self halfway throught writing, when I get home, If you still have problems ill look at my code and post some of my solutions...     
I havn''t been able to find the rounding down method in the msdn for c++. So any extra info u can provide would be great!

My only other idea was to increase the size of my map array. So like if i move 10 points to go from 1 tile to the next, then increase the array 10x to [280][250] and basically fill in the first tile by filling the array 10 times instead of 1. so like when i have my original array of [28][25] the first array would be [0][0] would say equal 1, where as with the new [280][250] from [0][0] to [9][0] would all equal 1. Would this work too? but it does take quite a bit of extra memory!

Thanks for helping me TheSyan!



Werdy666

My Homepage : http://werdy666.20megsfree.com/

This topic is closed to new replies.

Advertisement