-
I'm trying to implement rotation into my tetris clone and it is going terribly. Basically, when I try and set the tetrimino's sprite's origin to its center so I can rotate it without changing the position any, the sprite moves a lot farther on the screen that it should. Like it moves by tens of pixels each time. Here is the rotate function:
void GamePiece::RotateLeft(){
if(originCount != 10){
bool rotate = true;
int newx, newy;
sf::Vector2f origin(pieceRectangles_[0].getPosition().x + originCount, pieceRectangles_[0].getPosition().y + originCount);
for(int i = 0; i < 4; i++){
newx = (origin.x + origin.y - pieceRectangles_[i].getPosition().y - 10);
newy = (pieceRectangles_[i].getPosition().x + origin.y - origin.x);
sf::RectangleShape temp = pieceRectangles_[i];
temp.setPosition(newx, newy);
sf::FloatRect fr = temp.getGlobalBounds();
for(int j = 0; j < levelCollisions.size(); j++){
if(fr.intersects(levelCollisions[j])){
rotate = false;
}
}
}
if(rotate == true){
for(int i = 0; i < 4; i++){
newx = (origin.x + origin.y - pieceRectangles_[i].getPosition().y - 10);
newy = (pieceRectangles_[i].getPosition().x + origin.y - origin.x);
pieceRectangles_[i].setPosition(newx, newy);
}
pieceShape.setOrigin(pieceShape.getPosition().x + pieceShape.getGlobalBounds().width / 2, pieceShape.getPosition().y + pieceShape.getGlobalBounds ().height / 2);
pieceShape.rotate(90);
pieceShape.setOrigin(pieceShape.getPosition());
}
}
}
The first half with the for loops and such is the part that rotates all the individual squares which I use for collision detection. This part works perfectly (I have their color set to blue so I can see where they are moving versus the new position of the actual sprite). The problem starts at pieceShape.setOrigin(). I'm trying to set the sprite's origin to its center so I can rotate it smoothly, but the sprite spirals out from where it should have been, with increasing distance everytime.
-
Position/Rotation/Scale all happen around the origin when the sprite is drawn, not when rotate(...) is called.
-
Right I read that in the documentation... So, do I have to go through and change all of my other transforming functions to accomodate a new origin?
-
pieceShape.setOrigin(pieceShape.getPosition().x + pieceShape.getGlobalBounds().width / 2, pieceShape.getPosition().y + pieceShape.getGlobalBounds().height / 2);
pieceShape.rotate(90);
pieceShape.setOrigin(pieceShape.getPosition());
Update, if I comment out the last two lines and only set the origin, the sprite is placed back at (0,0). Why?
Update update:: That was a stupid question. But, if I do set the origin to the sprite's center in the constructor, it's still not rotating around its center. This function does set the origin to the center, right: pieceShape.setOrigin(pieceShape.getPosition().x + pieceShape.getGlobalBounds().width / 2, pieceShape.getPosition().y + pieceShape.getGlobalBounds().height / 2);
?
-
That is another thing I didn't see in your original code, but origin is relative to the sprite/transformable - not to the world (position is relative to the world).
-
This function does set the origin to the center, right: pieceShape.setOrigin(pieceShape.getPosition().x + pieceShape.getGlobalBounds().width / 2, pieceShape.getPosition().y + pieceShape.getGlobalBounds().height / 2);
?
Does this work instead:
pieceShape.setOrigin(pieceShape.getLocalBounds().x / 2, pieceShape.getLocalBounds().y / 2);
p.s. Why do I keep just giving the answer to people...
-
p.s. Why do I keep just giving the answer to people...
Because you believe people can't figure out things on their own and they must C&P code to get anywhere. ;)
-
you believe people can't figure out things on their own and they must C&P code to get anywhere.
Not fully true; I guess I'm just 'saving them the trouble'. Unfortunately, this can often have the adverse effect of getting into the habit of having answers spoon-fed. Sometimes, I'm just too nice :(
-
Does this work instead:
pieceShape.setOrigin(pieceShape.getLocalBounds().x / 2, pieceShape.getLocalBounds().y / 2);
p.s. Why do I keep just giving the answer to people...
It does not work, it actually throws an error because getLocalBounds() does not have a member 'x' or 'y'. I believe you meant pieceShape.setOrigin(pieceShape.getLocalBounds().width / 2, pieceShape.getLocalBounds().height / 2);
However, this doesn't work. The piece is still not rotating around its center, but it's not rotating around 0,0 either.
The image below shows the four orientations of my sprite. The blue line is where the piece is supposed to be rotating, and the red line is where is actually ends up. So it's rotating close to its center, but not exactly.
-
Try using floating point division rather than integer division.
ie:
pieceShape.setOrigin(pieceShape.getLocalBounds().width / 2.f, pieceShape.getLocalBounds().height / 2.f);
-
It does not work...I believe you mean.
I see that I'm subconciously still getting people to help themselves ;)
-
Try using floating point division rather than integer division.
ie:
pieceShape.setOrigin(pieceShape.getLocalBounds().width / 2.f, pieceShape.getLocalBounds().height / 2.f);
That produced no change at all. I discovered that if I just comment out the line where I set the origin, then there is also no change in the rotation. In other words, no matter what I set the origin to the piece rotates around the same point.
//pieceShape.setOrigin(pieceShape.getLocalBounds().width / 2.f, pieceShape.getLocalBounds().height / 2.f);
So, this function essentially does nothing, commented out or not
-
Does this work?
pieceShape.setOrigin(static_cast<float>(pieceShape.getLocalBounds().width) / 2.f, static_cast<float>(pieceShape.getLocalBounds().height) / 2.f);
-
Are you sure you read the tutorial about transformables (http://sfml-dev.org/tutorials/2.1/graphics-transform.php)? I think you are forgetting that changing the origin also relatively changes the position of the sprite.
Just draw a sprite at (0,0) with it's origin at (0,0) and then with it's origin changed. See what changes. Hapax last suggestion should not change anything because of how casts work is C++, but it's safer anyway how he writes it.
-
Both operands are floats, the static_cast is totally useless.
-
I did think the casts was more than I usually use. My earlier suggestion (using width instead of x though etc.) will be setting the origin to the centre of the pieceShape.
I suppose the next question is:
Is pieceShape the entire shape or just one of the squares?
-
I did think the casts was more than I usually use. My earlier suggestion (using width instead of x though etc.) will be setting the origin to the centre of the pieceShape.
I suppose the next question is:
Is pieceShape the entire shape or just one of the squares?
pieceShape is the entire shape. Each shape has one sprite to draw, and four invisible sf::RectangleShapes for collision detection. The blue shapes in the images I posted are the rectangle shapes, and are where the sprite (red) should be turning. But what has me so confused is whenever I print the values of the sprite's origin after explicitly changing the origin, the output is still 0,0
-
Did you output the origin immediately after changing it?
If not, then it's being changed back somewhere else, but if so, there is something wrong.
First, try placing the output immediately after to confirm it's actually getting changed as expected then, either move that output further away and find out when it changes, or try to use your debugger to step through it.
Is pieceShape a sprite, rectangle, or a container class with those things in it?
If it's a container class, you might have to get the local bounds of its internal element for the origin.