Ok, I see. Sorry for describing my problem(s) so confusing, I guess it was some kind of deadline panic
My original problem was that I couldnt figure out how to implement a collision detection in a tile map driven game with SFML and with the way I stored my level.
So, by now, I got something similar to a solution:
I found a website (
higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/) where implementing a 2d platformer is described as follows:
- Decompose movement into X and Y axes, step one at a time. If you’re planning on implementing slopes afterwards, step X first, then Y. Otherwise, the order shouldn’t matter much. Then, for each axis:
- Get the coordinate of the forward-facing edge, e.g. : If walking left, the x coordinate of left of bounding box. If walking right, x coordinate of right side. If up, y coordinate of top, etc.
- Figure which lines of tiles the bounding box intersects with – this will give you a minimum and maximum tile value on the OPPOSITE axis. For example, if we’re walking left, perhaps the player intersects with horizontal rows 32, 33 and 34 (that is, tiles with y = 32 * TS, y = 33 * TS, and y = 34 * TS, where TS = tile size).
- Scan along those lines of tiles and towards the direction of movement until you find the closest static obstacle. Then loop through every moving obstacle, and determine which is the closest obstacle that is actually on your path.
- The total movement of the player along that direction is then the minimum between the distance to closest obstacle, and the amount that you wanted to move in the first place.
- Move player to the new position. With this new position, step the other coordinate, if still not done.
I tried to implement it in my update() loop and it looks as follows (this is purely the collision detection, handling input and setting movement has been done before):
// we calculate the x coords of the side of the player which is in the direction of the movement
int coordFwdFEdgeX;
// player.getPosition() yields the upper left corner
if (movement.x < 0)
{
coordFwdFEdgeX = player.getPosition().x;
} else
{
coordFwdFEdgeX = player.getPosition().x + playerSize.x;
}
// if the forward facing edge has negative x coords we don't check for collision because he then is out of the level
if(coordFwdFEdgeX >= 0)
{
// with which line(s) of tiles (resp. rows) does the player collide?
std::vector<int> collidingLinesX;
if(movement.y < 0)
{
for(int i = player.getPosition().y; i >= static_cast<int>(player.getPosition().y+movement.y); --i)
{
// the tole size is 5
collidingLinesX.push_back(i/5);
}
} else if (movement.y == 0)
{
collidingLinesX.push_back(player.getPosition().y);
} else
{
for(int i = player.getPosition().y; i <= static_cast<int>(player.getPosition().y+movement.y); ++i)
{
collidingLinesX.push_back(i/5);
}
}
// we scan along these lines for obstacles
// the x coord of the closest obstacle is stored
// at the moment it is a random number, later this number is used to make sure there has been a collision
int closestObstacleX = 30111995;
if(movement.x < 0)
{
for(uint i = 0; i < collidingLinesX.size(); ++i)
{
// each row I check every tile between the column of the player position and the column of the new player position
for(int x =(coordFwdFEdgeX+movement.x)/5; x < (coordFwdFEdgeX/5); ++x)
{
// levelMap contains the level data and is a vector<vector<int> >, it is stored as follows: levelMap[y][x]
// empty blocks are stored as 0
if(myLevelMap[collidingLinesX[i]][x] != 0)
{
// if there has been an obstacle the x position is stored
closestObstacleX = x*5;
}
}
}
// if there has been a collision we only allow the player to move just before the obstacle
if(closestObstacleX != 30111995)
{
movement.x = -(coordFwdFEdgeX - closestObstacleX);
}
} else
// we do the same as before with a positive move
{
for(uint i = 0; i < collidingLinesX.size(); ++i)
{
for(int x = (coordFwdFEdgeX+movement.x)/5; x > (coordFwdFEdgeX/5); --x)
{
if(Play::getInstance()->getPhysicsMap()[collidingLinesX[i]][x] != 0)
{
closestObstacleX = x*5;
}
}
}
if(closestObstacleX != 30111995)
{
movement.x = closestObstacleX - coordFwdFEdgeX;
}
}
}
// now the y-axis
// determining the side which faces the moving direction
int coordFwdFEdgeY;
if(movement.y < 0)
{
coordFwdFEdgeY = player.getPosition().y;
} else
{
coordFwdFEdgeY = player.getPosition().y + playerSize.y;
}
// we don't want to try to access a negative value by index
if(coordFwdFEdgeY >= 0)
{
// with which line(s) of tiles does the player collide?
std::vector<int> collidingLinesY;
if(movement.x < 0)
{
for(int i = player.getPosition().x; i >= static_cast<int>(player.getPosition().x+movement.x); --i)
{
collidingLinesY.push_back(i);
}
} else if(movement.x == 0)
{
collidingLinesY.push_back(player.getPosition().x);
} else
{
for(int i = player.getPosition().x; i <= static_cast<int>(player.getPosition().x+movement.x); ++i)
{
collidingLinesY.push_back(i);
}
}
// we scan along these lines for obstacles
int closestObstacleY = 30111995;
if(movement.y < 0)
{
for(int i = 0; i < collidingLinesY.size(); ++i)
{
for(int y = static_cast<float>(coordFwdFEdgeY+movement.y)/5; y < static_cast<float>(coordFwdFEdgeY)/5; ++y)
{
if(Play::getInstance()->getPhysicsMap()[y][collidingLinesY[i]] != 0)
{
closestObstacleY = y*5;
}
}
}
if(closestObstacleY != 30111995)
{
movement.y = closestObstacleY - coordFwdFEdgeY;
}
} else
{
for(int i = 0; i < collidingLinesY.size(); ++i)
{
for(int y = static_cast<float>(coordFwdFEdgeY+movement.y)/5; y > static_cast<float>(coordFwdFEdgeY)/5; --y)
{
if(Play::getInstance()->getPhysicsMap()[y][collidingLinesY[i]] != 0)
{
closestObstacleY = y*5;
}
}
}
if(closestObstacleY != 30111995)
{
movement.y = -(coordFwdFEdgeY - closestObstacleY);
}
}
}
I hope the code is properly documentated and understandable. I really just tried to implement what the website described.
Unfortunately, the collision detection doesn't work, I can move right throught the solid blocks.
But interestingly, when I replace
for(int y = static_cast<float>(coordFwdFEdgeY+movement.y)/5; y > static_cast<float>(coordFwdFEdge[b]Y[/b])/5; --y)
in the check for the y obstacles with
for(int y = static_cast<float>(coordFwdFEdgeY+movement.y)/5; y > static_cast<float>(coordFwdFEdge[b]X[/b])/5; --y)
I get a a vertical obstacle detection, although the player sometimes get randomly teleported. The same doesn't apply for x.
Any hints?