+7  A: 

You'd need to do something like:

  • translate by (-playerx-playerwidth/2, -playery-playerheight/2)
  • rotate by rotateangle
  • translate by (playerx+playerwidth/2, playery+playerheight/2)

The idea is to center your sprite on the origin then rotate around the origin (glRotate) and after you get the rotated sprite you translate it back in its place.

NB: If your sprite is initially "centered" around the origin, but with a corner not the actual center of the sprite, you first translate the object to center the sprite's center with the origin. So like if your sprite had the top-left corner in the origin, you'd translate by (-playerwidth/2, -playerheight/2), then rotate then translate by (playerx,playery).

Blindy
Could you please clarify what you mean by translate? Sorry.
Sam152
@Sam152: translate means move on one or more axes.
klez
I implemented this with no avail, I cant see how moving a sprite up and to the left then rotating it then moving it the same distance right and down would help to create a pivot axis?
Sam152
Depending on what your package offers, you might only have a rotation around the origin, like OpenGL has. If this is the case, you want to "move the origin" to the center of your sprite so you can use your rotation function. However "moving the origin to the center of your sprite" is the same as "moving your sprite so its center is in the origin", so by doing what I said above youre effectively rotating around an arbitrary point using a fixed point rotation function.
Blindy
Ya see, in the code you just shown you're using a single-parameter rotate, you're giving it an angle. This means that it rotates your geometry around the origin.
Blindy
I still think this isn't correct, but if you implement it into my code and it works, I will accept your answer.
Sam152
+1  A: 

Looking at your image, what you're doing is you're rotating the square in place, you're not translating it at all. This is what you're doing:

^                         ^
|                         |
|                         |
|               ====>     |
|                         |
+--+----->                x---------->
|  |                     / \
+--+                     \ /
                          x

As you can see, your square is with its top-left corner in the origin and all you're doing is rotating it around the origin.

This is what I'm saying you should do:

^                         ^                ^
|                         |                |
|                         |        ===>    |     ==> translate to
|               ====>     |                x     ==> where you want
|                        +-+              /|\    ==> to draw it
+--+----->               |+|--------->     +-------->
|  |                     +-+              \ /
+--+                                       x

You can only rotate around the center, so center the point you want to rotate your primitives around then place them where you want.

Blindy
+2  A: 

When you rotate the object, you are applying a transformation to the points that compose the object. In this case, the four corners each rotate on their own, and the end result is the quad formed in their new locations. As everyone else has mentioned, the critical part of this is knowing where the origin about which the points rotate.

Imagine if instead of a sprite, you only had one point. If its origin was at the same position as that point, rotating it would have no effect (the position of the point would not move). However, if the origin was anywhere else, the point would rotate in a circle, with the origin as the center of that circle. And how would you get that origin to be somewhere other than at the same position as the point? Move the point within the coordinate system. In other words, translate it.

The order of the various transformations (rotate, translate, scale, etc.) is critical to this. If you rotated the point 180 degrees and then translated it to the right, it would end up to the right of where it started, but if you moved it to the right and then rotated it 180 degrees, it would end up on the left.

I'd recommend reading up on 2D transformations. Understanding how matrices play in all this would also be useful, but not strictly necessary to get the effect you're looking for.

Doug Kavendek
+4  A: 

The answers so far are correct in telling you how it should be done but I fear that the Dark GDK API seems to be too primitive to be able to do it that simple way.

Unfortunately dbRotateSprite rotates the sprite about the top left regardless of the sprite's transform which is why you're having no luck with the other suggestions. To simulate rotation about the centre you must manually correct the position of the sprite i.e. you simply have to rotate the sprite and then move it as a two-step process.

I'm not familiar with the API and I don't know if y is measured up or down and which way the angle is measured so I'm going to make some assumptions. If y is measured down like many other 2D graphics systems, and the angle is measured from the x-axis increasing as it goes from the positive x-axis to the positive y-axis, then I believe the correct psuedo-code would look like

// PlayerX and PlayerY denote the sprite centre
// RotateAngle is an absolute rotation i.e. not a relative, incremental rotation

RotateAngle += 5;
RotateAngle %= 360;
RadiansRotate = (RotateAngle * PI) / 180;

dbRotateSprite( Handle, RotateAngle );

HalfSpriteWidth = dbSpriteWidth( Handle ) / 2;
HalfSpriteHeight = dbSpriteHeight( Handle ) / 2;

SpriteX = PlayerX
        - HalfSpriteWidth * cos(RadiansRotate)
        + HalfSpriteHeight * sin(RadiansRotate);
SpriteY = PlayerY
        - HalfSpriteHeight * cos(RadiansRotate)
        - HalfSpriteWidth * sin(RadiansRotate);

// Position the top left of the sprite at ( SpriteX, SpriteY )
dbSprite ( 1 , SpriteX , SpriteY , Handle );
Troubadour
I thought it would come down to something like this. I started drawing crazy diagrams (http://img252.imageshack.us/img252/8020/pic3m.jpg) and trying to solve for the x and y values between the squares. I will give it a shot, cheers.
Sam152
If you want to check the maths, which would be a good idea anyway, then draw a diagram with both the rotated and unrotated squares centred at the same point. All you need to work out then is the position of the top left of the rotated square w.r.t. the centre (as the centre is just (`PlayerX`,`PlayerY`)). Each component of that point actually breaks down into a sum of two lengths where each length is a side of a right-angled triangle with hypotenuse w/2 and h/2 respectively. If you have any problems then let me know and I'll try to add a diagram at the weekend.
Troubadour
I tried implementing it like this, and got nowhere unfortunately: http://codepad.org/GMji2PXA
Sam152
@Sam152, I believe Troubadour is correct. I've had this problem in flash as well because the pivot isn't necessarily where you might want it sometimes. Your "PlayerX -= " is not really correct. Thats saying PlayerX = PlayerX - (width*cos + height*sin), which becomes PlayerX = PlayerX - width*cose - height*sin, which is somewhat backwards. Also, you would be updating your initial position on each rotation, which will slowly start making your sprite shift out of place because of floating point. Use different variables for rotated position and player position.
kidnamedlox
The reason it's not working could also be that `sin` and `cos` don't take degrees as an argument. It must be radians so multiply your degree values by pi/180.
Troubadour
Really!? Radians? That's a surprise, that means I have been rotating it by more than 360 degrees each step. Oh well, thanks for the help guys, it now rotates very nicely. Now to just fix the collision detection.
Sam152
Just updated the question to include the extra info for anyone else who may be having the same problem.
Sam152
+1  A: 

OMG ive been tryna do this for a while now to, n i found this page, just copy this. this is based on one of the previous posts.

void dbRotateSpriteCenter(int iID, int iX, int iY, int fRotate, int iImage)
{
int x = iX 
    - dbSpriteWidth(iID) / 2 * cos(fRotate * 3.1415926536 / 180) 
    + dbSpriteHeight(iID) / 2 * sin(fRotate * 3.1415926536 / 180);
int y = iY 
    - dbSpriteHeight(iID) / 2 * cos(fRotate * 3.1415926536 / 180)
    - dbSpriteWidth(iID) / 2 * sin(fRotate * 3.1415926536 / 180);
dbRotateSprite(iID, fRotate);
dbSprite(iID, x, y, iImage);
}
Jimi Browning
Yeah man, I figured other people would be searching for this. The documentation isn't awesome. Thanks for the code dude.
Sam152
+1  A: 

you could use dbOffsetSprite();

when sprites are created, their insertion point is upper-left corner by default (and dbRotateSprite(); rotates them around the insertion point), you can use this function to change the insertion point. its format is dbOffsetSprite(sprite number, amount to offset X, amount to offset Y);

so you could say

dbOffsetSprite(NUMBER, dbSpriteWidth(NUMBER) / 2, dbSpriteHeight(NUMBER) / 2);

where NUMBER is the sprite ID number.

The sprite's insertion point is now in the center of its image.

Of course, this might open a whole new can of worms, as the insertion point is now in the center of the sprite (or where ever you set it), meaning calling dbSpriteX(NUMBER); will give you the center of the sprite instead of the edge.

Burr
Wow, this actually clears up a lot. A few modifications to the collision detection code and this would have solved all problems.
Sam152