I have recently started to learn SFML and decided to make a brick breaker game to practice with. I have managed to get a paddle, ball and bricks to appear. I can move the paddle just fine and the ball moves and collides with the paddle, and the edges of the wall as well as the the bricks, however when the ball collides with the bricks I am having difficulties with changing the bricks or even removing them.
the set hit function which should be called changes the colour of the rectangle as follows:
1 2 3 4 5
void cBlock::SetHit()
{
hit = true;
rectangle.setFillColor(sf::Color::Red);
}
when I call blocks.GetSquares().at(i).SetHit(); in the collision detection nothing happens. I do not know why as the ball actually collides and the console outputs the correct block number being hit.
The problem may be the return type of the GetSquares function. std::vector<cBlock> it is returning a copy.
Return a reference instead: std::vector<cBlock>& GetSquares( return squares; );
I have run into another problem I have added a new function that returns if a block has been hit already. I use this to determine if the block needs to be removed or not.
I have changed the code in the ball collision at line 12 to be:
1 2 3 4
if (!blocks.GetSquares().at(i).GetHit())
blocks.GetSquares().at(i).SetHit();
else
blocks.GetSquares().erase(blocks.GetSquares().begin()+i);
However I am getting a error message when the program invokes the else part of the statement of "vector subscript out of range". I do not see how it can be though.
When an element is erased the vector size is reduced.
Line 12 is: for (int i = 0; i < squares.size(); i++) where squares is a copy of blocks.GetSquares() that is made for some reason I can't see.
i will be out of range at squares.size()-1 if any erasures were made.
Try using for (int i = 0; i < blocks.GetSquares().size(); i++) instead so the upper limit for i gets adjusted when erasures occur.
EDIT: I see you are using the local variable std::vector<cBlock> squares to substitute for each cBlock in the collision testing. Consider using just a single cBlock variable for this:
void cBall::Collision(cPaddle player, cBlocks &blocks)
{
.....
//Need to add collision with blocks (tricky!)
cBlock square = blocks.GetSquares().at(i);// new
for (int i = 0; i < blocks.GetSquares().size(); i++)// new
{
if (ball.getPosition().y >= square.GetPosition().y && ball.getPosition().y <= square.GetPosition().y + 25)
{
if (ball.getPosition().x >= square.GetPosition().x && ball.getPosition().x <= square.GetPosition().x + 100)
{
blocks.GetSquares().at(i).SetHit();
yVelocity = yVelocity * -1.0;
std::cout<<"Hit block "<<i<<"\n";
}
}
}
........
}
Or, just use blocks.GetSquares().at(i) directly.
EDIT2: The ninja phenomenon is amazing. Over 2 hours with no reply, then 2 replies in 4 minutes. The frequency of occurrence seems impossible (10 standard deviations from the norm = practically impossible)..
Note that erasing things while iterating over it like that might skip members since everything is shifted; at the end of your loop you increase i unconditionally so if you delete the 2nd to last element, then the last element will become i, but you will increment i when you finish the loop and never loop at it.
Are you sure this error is occurring at line 26? The way you have it now only one erasure can occur. k should be in the range 0 to size-1 so the operation should be legal. I don't see anything wrong in the code provided.
It is definitely line 26 that is causing the issues. I have tried it both ways commented and uncommented. When commented no errors occur and no block is being deleted. When uncommented an error occurs when the block should be deleted.
Simply commenting out line 26 doesn't prove that it is where the crash occurs.
A crash could happen because of some following invalid use of blocks.
Example:
1 2 3 4 5 6 7 8 9 10
// code you have posted
if (destroy)
{
blocks.GetSquares().erase(blocks.GetSquares().begin()+k);// the line suspected of causing the crashes
destroy = false;
}
// just below the posted code
for (int i = 0; i < oldSize; i++)
blocks.GetSquares().at(i);// boom at i = oldSize-1 (but only if the erasure was made)
I admit, you are attempting operations that I've never used in practice. Seems like it should work though.
The code that follows checks that the ball is not hitting the boundaries. It has no calls to blocks as it just checks against screen width and height. The code described above is the only time blocks are handled in the entire program except for when they are first initialised.
I have solved the issue fun2code you are right in the blocks draw function I have a for loop that ranges from 0 < 63 rather than 0 < vector.size(). Thank god for breakpoints. I shall mark this as solved.