I'm creating a simple Mario-style game. It's my first project like this. I have problem with collision system in my game.
My map object has this method for checking collisions:
int Map::checkPosition(double x, double y, bool returnY)
{
if(x>800 || x<0 || y>600 || y<0)
if(returnY == false) return false;
else return 600;
else
for(sf::Sprite sprite : mapEnviromentSprites_)
if(x > sprite.getPosition().x && x < sprite.getPosition().x + sprite.getGlobalBounds().width && y > sprite.getPosition().y && y < sprite.getPosition().y + sprite.getGlobalBounds().height)
if(returnY == false) return false;
else return sprite.getPosition().y;
return true;
}
My player object uses it by checking few "checkpoints" on character sprite and, if every returns true, allows change to character position made by this method:
void Player::movePlayer(Map& map, int frameTime)
{
//temporary variables until everything is working fine here
const float moveSpeed = 150.0f;
static float jumpTime = 0;
static float jumpBeginY = 0;
static bool jumpBeginYMarker = false;
static float deltaTime;
const float jumpMaxHeight = 100.0f;
const float jumpMaxTime = 1.0f;
const float a = 4*jumpMaxHeight/(jumpMaxTime*jumpMaxTime);
const float b = 4*jumpMaxHeight/jumpMaxTime;
//I'm taking current values of position of character sprite to modify them later
x = player.getPosition().x;
y = player.getPosition().y;
//I get frame time right after displaying window in main loop, as microseconds
deltaTime = frameTime*0.000001f;
//I'm using PlayerState enum type to determine what texture should I set to character spite
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
playerState_ = PlayerState::CROUCH;
//I want to move character sprite only if he isn't pressing at obstacle at any point (up, down corners and middle point at approbate site)
//Here is one problem - if I check raw values I can "freeze" on obstacle until I release left/right arrow, but if I check a little further, no less than 2 pixels, everything is fine
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && map.checkPosition(x+player.getGlobalBounds().width/2+0.1,y+player.getGlobalBounds().height/2) && map.checkPosition(x+player.getGlobalBounds().width/2+0.1,y-player.getGlobalBounds().height/2) && map.checkPosition(x+player.getGlobalBounds().width/2+0.1,y))
{
playerState_ = PlayerState::WALK;
x += moveSpeed * deltaTime;
player.setScale(1,1);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && map.checkPosition(x-player.getGlobalBounds().width/2-0.1,y+player.getGlobalBounds().height/2) && map.checkPosition(x-player.getGlobalBounds().width/2-0.1,y-player.getGlobalBounds().height/2) && map.checkPosition(x-player.getGlobalBounds().width/2-0.1,y))
{
playerState_ = PlayerState::WALK;
x -= moveSpeed * deltaTime;
player.setScale(-1,1);
}
//Obviously I don't want to allow jumping while jumping or falling)
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && !isFalling) isJumping = true;
//I want player sprite to be in falling state always if it does not stand still on obstacle
//Here is something bugged I think, isFalling is always on
if(!isJumping && map.checkPosition(x+player.getGlobalBounds().width/2,y+player.getGlobalBounds().height/2-5) && map.checkPosition(x-player.getGlobalBounds().width/2,y+player.getGlobalBounds().height/2-5))
isFalling = true;
else isFalling = false;
//again, PlayerState setting
if(isJumping || isFalling)
{
playerState_ = PlayerState::JUMP;
//a part for taking y_0 of my jump
if(!jumpBeginYMarker)
{
jumpBeginY = player.getPosition().y;
jumpBeginYMarker = true;
}
//equations for jumping and falling
if(isJumping) y = jumpBeginY -b*jumpTime + a*jumpTime*jumpTime;
if(isFalling) y = jumpBeginY + a*jumpTime*jumpTime;
//updating jumping time, necessary in above equations
jumpTime += deltaTime;
//I don't want to jump any longer if I hit obstacle with my head, so I start a fall
if(!map.checkPosition(x+player.getGlobalBounds().width/2,y-player.getGlobalBounds().height/2) || !map.checkPosition(x-player.getGlobalBounds().width/2,y-player.getGlobalBounds().height/2))
{
jumpTime = 0;
isJumping = false;
isFalling = true;
jumpBeginYMarker = false;
}
//and again, I don't want to fall any longer if I hit obstacle with my feets
if(!map.checkPosition(x-player.getGlobalBounds().width/2,y+player.getGlobalBounds().height/2) || !map.checkPosition(x+player.getGlobalBounds().width/2,y+player.getGlobalBounds().height/2))
{
jumpTime = 0;
isJumping = false;
isFalling = false;
jumpBeginYMarker = false;
jumpBeginY = 0;
}
}
//another PlayerState stuff
if(!sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && isJumping == false && isFalling == false)
playerState_ = PlayerState::STAND;
//6 control points - up left/right, down left/right and middles of both sides
//I don't want to allow player to take inaccessible areas, so I check above control points for collissions
if(map.checkPosition(x+player.getGlobalBounds().width/2,y+player.getGlobalBounds().height/2) && map.checkPosition(x+player.getGlobalBounds().width/2,y-player.getGlobalBounds().height/2) && map.checkPosition(x-player.getGlobalBounds().width/2,y+player.getGlobalBounds().height/2) && map.checkPosition(x-player.getGlobalBounds().width/2,y-player.getGlobalBounds().height/2) && map.checkPosition(x+player.getGlobalBounds().width/2,y) && map.checkPosition(x-player.getGlobalBounds().width/2,y))
player.setPosition(x,y);
}
There are three problems:
1. Falling never stops - when character is very close to surface of obstacle, it's just keep doing "little jumps", that last for around 0.001 second according to console log.
2. When I move on alone obstacle (70 pixel width), my character stands still (jumping ofc, like stated above) only on edges, but if it crosses centre (wide-wise) of this obstacle, it falls down through it. This problem doesn't exist if two or more obstacles are placed next to each other. It's like collision detecting method checks only corners of obstacles and all pixels around character sprite, but it's clearly designed in opposite way.
3. When I move horizontally towards an obstacle, especially when jumping, I freeze on it until I release left/right arrow. However if I set condition to check a two pixels further than player sprite, it works (in pasted code I tried to set 0.1, with negative result).
I'm sorry for my bad English, especially grammatical ones, it's not my primary language.