Hello there GameDev community,
I am creating a small game project for myself where the player controls a ball which bounces, the player can move the ball left and right. Depending on what side the ball bounces from depends on how the ball should react, so if the ball bounces from its bottom it will bounce upwards, if from the left side it will bounce to the right and so on.
So let me explain some variables for my player, the player's width and height is 60 and its Y velocity may not be greater than 14,
I have a bunch of displayObjects (displayobject is just an object with a sf::Sprite, it is a custom class of course) which are checked to see if the player collides with them.
So first off here is a screenshot of my game so you understand it graphically.
So first off I have a function that checks to see if the player is hitting any of the displayobjects, if the player is intersecting them the sf::IntRect is stored into a vector of sf::IntRects ready to be used later (They are stored because the player could hit multiple blocks)
void LevelState::CheckPlayerCollisions()
{
std::vector<sf::IntRect> blocks;
sf::IntRect playerRect(Player.XPos - 30, Player.YPos - 30, Player.Sprite.getTextureRect().width, Player.Sprite.getTextureRect().height);
for (int i = 0; i < DisplayObjects.size(); i++)
{
sf::IntRect objectRect(DisplayObjects.at(i).XPos, DisplayObjects.at(i).YPos, DisplayObjects.at(i).Sprite.getTextureRect().width, DisplayObjects.at(i).Sprite.getTextureRect().height);
if (objectRect.intersects(playerRect))
{
blocks.push_back(objectRect);
}
}
if (blocks.size() != 0)
{
std::cout << "Collision !" << std::endl;
CollisionSide collisionSide = _mathsService.Debug(blocks, playerRect);
Player.HitObjectUpdate(14, collisionSide);
}
}
Once all of the displayObjects have been checked I call my mathsService Debug function (the function is called debug as I am testing this collision detection, once fully working I will of course rename it), this checks the player against each sf::IntRect in the vector, it works out the centre of the player and the centre of each sf::IntRect in the vector and states which one the player was closest to and which side the player ball bounces from.
CollisionSide MathsService::Debug(std::vector<sf::IntRect> blocks, sf::IntRect player)
{
int playerXCentre = player.left + (player.width / 2);
int playerYCentre = player.top + (player.height / 2);
int blockId = 0;
int difference = 0;
CollisionSide side = CollisionSide::None;
for (int i = 0; i < blocks.size(); i++)
{
int blockXCentre = (blocks.at(i).left + (blocks.at(i).width / 2));
int blockYCentre = (blocks.at(i).top + (blocks.at(i).height / 2));
int xDifference = playerXCentre - blockXCentre;
int yDifference = playerYCentre - blockYCentre;
int positiveX = 0;
int positiveY = 0;
if (xDifference < 0)
{
positiveX = xDifference * -1;
}
else
{
positiveX = xDifference;
}
if (yDifference < 0)
{
positiveY = yDifference * -1;
}
else
{
positiveY = yDifference;
}
//Work out which side was hit
if (positiveX > positiveY)
{
//It is left or right
if (xDifference < 0)
{
side = CollisionSide::Left;
}
else
{
side = CollisionSide::Right;
}
}
else
{
//It is top or bottom
if (yDifference < 0)
{
side = CollisionSide::Bottom;
}
else
{
side = CollisionSide::Top;
}
}
if (difference != 0)
{
int newDifference = positiveX + positiveY;
if (newDifference < difference)
{
difference = newDifference;
blockId = i;
}
}
else
{
difference = xDifference + yDifference;
}
}
return side;
}
Once it goes through the vector it will return a CollisionSide which can be Top, Right, Bottom or Left, depending on that result depends on what the player does, so then I call Player.HitObjectUpdate which then forces the ball to move correctly
void Player::HitObjectUpdate(int forceSet, CollisionSide side)
{
if (side == CollisionSide::Top)
{
YVelocity = 0;
}
else if (side == CollisionSide::Left && XSpeed > 0)
{
XVelocity = XVelocity * -1;
XSpeed = XSpeed * -1;
}
else if (side == CollisionSide::Right && XSpeed < 0)
{
XVelocity = XVelocity * -1;
XSpeed = XSpeed * -1;
}
else if (side == CollisionSide::Bottom)
{
YVelocity = forceSet;
XSpeed = XVelocity;
}
}
Now this works fine for a few seconds or even minutes but now and then the ball will get stuck in a block and do weird movement then jump out or just go off the screen, I'm really confused on how to check for this collision. I don't want to use any existing 2D c++ physics engine. If anyone can give me a hand with this or know of a better way to work out collision detection please let me know.
Also you can view a video at http://tinypic.com/r/2u90aqe/8 to see the weird out come of the ball when it collides with a block and goes inside of it.