Jump to content
  • Advertisement
Sign in to follow this  
hahaha

[Solved]Tile Based Collision Detection

This topic is 4009 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a tile based game that im making. The dimensions are 25*16 tiles. Each tile is 32*32 pixels. My character can move to any position(he isnt forced to be in one tile at a a time). He can also jump up(3 tiles high and 5 tiles far). So now ive got my level editor working i need to add collision detection to the game. I can easily get the position and direction of the character(eg Left right up down...) Ive been battling for hours and i really need help. Any links to tutorials or examples will be greatly appreciated! Thanks [Edited by - hahaha on September 28, 2007 9:04:04 AM]

Share this post


Link to post
Share on other sites
Advertisement
Hi,

I battled with this one when I first started out. It's not that complex (surprisingly). Anyways, what you need to do is separate the axis for the player i.e. y and x and check for collisions in those axis alone. For example check the y-axis for a collision first then check the x-axis (but don't do both!) and respond to the collision accordingly. That should be all you need to know.

Good Luck :)

mameman

Share this post


Link to post
Share on other sites
thanks for the link and the help!
So this is what ive come up with so far to test for collisions and its not working

//CScreen.h
#ifndef CSCREEN_H
#define CSCREEN_H

#include "Main.h"
#include "CEntity.h"

struct sTile
{
bool Transparent;
int Type;
};

struct sScreen
{
CEntity Tiles[25][16];
};

class CScreen
{
private:
std::vector<sScreen> m_Screens;
int m_iActiveScreen;
int m_iNumScreens;
int m_iColX[25];
int m_iColY[16];
public:
CScreen();
virtual ~CScreen();

bool LoadMap(char *Filename);
void Render();

bool CanMove(sEntityPos Pos,eEntityDirection Direction);
};

#endif
//CScreen.cpp
#include "CScreen.h"
#include "CPlayer.h"

extern CPlayer g_Player;

using namespace std;

CScreen::CScreen()
{
m_iActiveScreen = 0;
m_iNumScreens = 0;
for(int i=0;i<25;i++)
{
m_iColX = i*32;
}

for(int i=15;i!=-1;i--)
{
m_iColY = i*32+44;
}
}

CScreen::~CScreen()
{
}

bool CScreen::LoadMap(char *Filename)
{
//Clear Vector of screens
m_Screens.clear();

//Open File for reading
ifstream In(Filename,ios::binary);
if(In.is_open() == false)return false;

//Read the amount of screens
In.read((char *)&m_iNumScreens,sizeof(int));

//Read all tile data
for(int a=0;a<m_iNumScreens;a++)
{
sScreen Screen;
for(int i=0;i<25;i++)
{
for(int b=15;b!=-1;b--)
{
sTile Tile;
In.read((char *)&Tile,sizeof(sTile));

sEntityPos Pos((float)i*32,(float)(b*32)+44);
CEntity Entity;
Entity.SetEntityPos(Pos);

if(Tile.Type == 0) //Blue Brick
{
Entity.SetEntityColor(E_BLUE);
Entity.SetEntityType(E_BRICK);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 1) //Blue Diamond
{
Entity.SetEntityColor(E_BLUE);
Entity.SetEntityType(E_DIAMOND);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 2) //Blue Platform
{
Entity.SetEntityColor(E_BLUE);
Entity.SetEntityType(E_PLATFORM);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 3) //Blue Sphere
{
Entity.SetEntityColor(E_BLUE);
Entity.SetEntityType(E_SPHERE);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 4) //Box
{
Entity.SetEntityType(E_BOX);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 5) //Crown
{
Entity.SetEntityType(E_CROWN);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 6) //Dirt
{
Entity.SetEntityType(E_DIRT);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 7) //Door
{
Entity.SetEntityType(E_DOOR);
Entity.SetBaseEntityType(E_OTHER);
}
else if(Tile.Type == 8) // Empty
{
Entity.SetEntityType(E_EMPTY);
Entity.SetBaseEntityType(E_OTHER);
}
else if(Tile.Type == 9) // Fire
{
Entity.SetEntityType(E_FIRE);
Entity.SetBaseEntityType(E_KILLABLE);
}
else if(Tile.Type == 10) //Grass
{
Entity.SetEntityType(E_GRASS);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 11) // Ladder
{
Entity.SetEntityType(E_LADDER);
Entity.SetBaseEntityType(E_OTHER);
}
else if(Tile.Type == 12) // Lava
{
Entity.SetEntityType(E_LAVA);
Entity.SetBaseEntityType(E_KILLABLE);
}
else if(Tile.Type == 13) // Mg
{
Entity.SetEntityType(E_MG);
Entity.SetBaseEntityType(E_OTHER);
}
else if(Tile.Type == 14) // Mud
{
Entity.SetEntityType(E_MUD);
Entity.SetBaseEntityType(E_KILLABLE);
}
else if(Tile.Type == 15) // Pistol
{
Entity.SetEntityType(E_PISTOL);
Entity.SetBaseEntityType(E_OTHER);
}
else if(Tile.Type == 16) //Pole
{
Entity.SetEntityType(E_POLE);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 17) //Purple Diamond
{
Entity.SetEntityColor(E_PURPLE);
Entity.SetEntityType(E_DIAMOND);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 18) //Purple Platform
{
Entity.SetEntityColor(E_PURPLE);
Entity.SetEntityType(E_PLATFORM);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 19) //Purple Sphere
{
Entity.SetEntityColor(E_PURPLE);
Entity.SetEntityType(E_SPHERE);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 20) //Red Brick
{
Entity.SetEntityColor(E_RED);
Entity.SetEntityType(E_BRICK);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 21) //Red Diamond
{
Entity.SetEntityColor(E_RED);
Entity.SetEntityType(E_DIAMOND);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 22) //Red Platform
{
Entity.SetEntityColor(E_RED);
Entity.SetEntityType(E_PLATFORM);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 23) //Red Sphere
{
Entity.SetEntityColor(E_RED);
Entity.SetEntityType(E_SPHERE);
Entity.SetBaseEntityType(E_COLLECTABLE);
}
else if(Tile.Type == 24) // Reed
{
Entity.SetEntityType(E_REED);
Entity.SetBaseEntityType(E_KILLABLE);
}
else if(Tile.Type == 25) //Sand
{
Entity.SetEntityType(E_SAND);
Entity.SetBaseEntityType(E_COLLIDABLE);
}
else if(Tile.Type == 26) // Smg
{
Entity.SetEntityType(E_SMG);
Entity.SetBaseEntityType(E_OTHER);
}
else if(Tile.Type == 27) // Spikes
{
Entity.SetEntityType(E_SPIKE);
Entity.SetBaseEntityType(E_KILLABLE);
}
else if(Tile.Type == 28) // Start Point
{
Entity.SetEntityType(E_EMPTY);
Entity.SetBaseEntityType(E_OTHER);
Pos.x+=3;
g_Player.SetPos(Pos);
}
else if(Tile.Type == 29) // Water
{
Entity.SetEntityType(E_WATER);
Entity.SetBaseEntityType(E_KILLABLE);
}
else if(Tile.Type == 30) //Weed
{
Entity.SetEntityType(E_WEED);
Entity.SetBaseEntityType(E_COLLECTABLE);
}

Screen.Tiles = Entity;
}
}
m_Screens.push_back(Screen);
}
return true;
}

void CScreen::Render()
{
for(int i=0;i<25;i++)
{
for(int a=0;a<16;a++)
{
m_Screens[m_iActiveScreen].Tiles[a].UpdateAndRender();
}
}
}

bool CScreen::CanMove(sEntityPos Pos,eEntityDirection Direction)
{
int PlayerColX = 0;
int PlayerColY = 0;

for(int i=0;i<25;i++)
{
if(Pos.x > m_iColX && Pos.x < m_iColX[i+1]+32)
{
PlayerColX = i;
}
}

for(int i=0;i<16;i++)
{
if(Pos.y >= m_iColY)
{
PlayerColY = i;
}
}

sEntityPos EntityPos;
eEntityBaseType BaseType;

switch(Direction)
{
case E_LEFT:
BaseType = m_Screens[m_iActiveScreen].Tiles[PlayerColX-1][PlayerColY].GetBaseEntityType();
if(BaseType == E_COLLIDABLE)
{
EntityPos = m_Screens[m_iActiveScreen].Tiles[PlayerColX-1][PlayerColY].GetEntityPos();
if(Pos.x-3 < EntityPos.x+32)return false;
}
break;
case E_RIGHT:
BaseType = m_Screens[m_iActiveScreen].Tiles[PlayerColX+1][PlayerColY].GetBaseEntityType();
if(BaseType == E_COLLIDABLE)
{
EntityPos = m_Screens[m_iActiveScreen].Tiles[PlayerColX+1][PlayerColY].GetEntityPos();
if(Pos.x+35 > EntityPos.x)return false;
}
break;
case E_UP:
BaseType = m_Screens[m_iActiveScreen].Tiles[PlayerColX][PlayerColY+1].GetBaseEntityType();
if(BaseType == E_COLLIDABLE)
{
EntityPos = m_Screens[m_iActiveScreen].Tiles[PlayerColX][PlayerColY+1].GetEntityPos();
if(Pos.y+35 >= EntityPos.y)return false;
}
break;
case E_DOWN:
BaseType = m_Screens[m_iActiveScreen].Tiles[PlayerColX][PlayerColY-1].GetBaseEntityType();
if(BaseType == E_COLLIDABLE)
{
EntityPos = m_Screens[m_iActiveScreen].Tiles[PlayerColX][PlayerColY-1].GetEntityPos();
if(Pos.y-3 <= EntityPos.y)return false;
}
break;
};

return true;
}



this is what my players update function is doing

void CPlayer::Update()
{
if(m_bLButtonUp == false)
{
m_Direction = E_LEFT;
if(g_Screen.CanMove(m_Pos,m_Direction) == true)
{
m_Pos.x -= 2.5f;
}
}
else if(m_bRButtonUp == false)
{
m_Direction = E_RIGHT;
if(g_Screen.CanMove(m_Pos,m_Direction) == true)
{
m_Pos.x += 2.5f;
}
}

if(m_bUButtonUp == false)m_bJumping = true;

if(m_bJumping == true)
{
if(m_bReverse == false)
{
m_Direction = E_UP;
if(g_Screen.CanMove(m_Pos,m_Direction) == true)
{
m_Pos.y += 3;
}
}
else
{
m_Direction = E_DOWN;
if(g_Screen.CanMove(m_Pos,m_Direction) == true)
{
m_Pos.y -= 3;
}
}
m_iElapsedJump++;
if(m_iElapsedJump == 32)
{
m_bReverse = true;
}
else if(m_iElapsedJump == 64)
{
m_iElapsedJump = 0;
m_bReverse = false;
m_bJumping = false;
}
}

g_Renderer->BindTexture(g_TextureManager.Weed);
g_Renderer->DrawSquare(m_Pos.x,m_Pos.y);
}



The collision on the x axis seems to be working except for when i jump. The y axis collision doesnt work. Sometimes on both the x and the y axis when it does seem to work my player seems to be about 2 or 3 pixels into the tile where it was supposed to stop.

Heres a link to the full game source and a built binary to see whats going on (868Kb)

I know this is a lot to go through but i would really appreciate it someone could help me.

Thanks

Share this post


Link to post
Share on other sites
Thanks for the links they were quite useful! I solved it by calculating which column and row i was in and seeing if i could move before i moved

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!