开发者

How do you rotate a sprite around its center by calculating a new x and y position?

I'm using Dark GDK and C++ to create a simple 2d game. I'm rotating an object but it rotates from the top left corner of the sprite.

I have the following variables available:

  • PlayerX
  • PlayerY
  • PlayerWidth
  • PlayerHeight
  • RotateAngle (360 > x > 0)

Is there an algorithm that will modify the pivot point of the sprite, preferable to the center?

Here is a small code sample:

void Player::Move( void )
{

    if ( checkLeft() )
    {
        PlayerX -= PlayerSpeed;
        if ( PlayerX < 0 )
            PlayerX = 0;
    }

    if ( checkRight() )
    {
        PlayerX += PlayerSpeed ;
        if ( PlayerX > 800 - PlayerWidth )
            PlayerX = 800 - PlayerWidth;
    }

    if ( checkUp())
    {
        PlayerY -= PlayerSpeed;
        if ( PlayerY < 0 )
            PlayerY = 0;
    }

    if ( checkDown())
    {
        PlayerY += PlayerSpeed;
        if ( PlayerY > 600 -  PlayerHeight)
            PlayerY = 600 - PlayerHeight;
    }

    RotateAngle += 5;
    if(RotateAngle > 360)
        RotateAngle -=360;

    dbRotateSprite(Handle,RotateAngle);
    dbSprite ( 1 , PlayerX , PlayerY , Handle );
}

Edit

I'm considering opening up some reputation for this question, I have yet to be provided with an answer that works for me. If someone can provide an actual code sample that does the job, I'd be very happy.

The problem with Blindy's answer is that no matter how much I simply translate it back or forth, the spirte still rotates around the top left hand corner and moving it somewhere rotating around the top left corner, then moving it back to the same position accomplishes noth开发者_开发知识库ing. Here is what I believe to be going on:

alt text http://img248.imageshack.us/img248/6717/36512474.png

Just so there is no confusion I have created a an image of what is going on. The left shows what is actually happening and the right shows what I need to happen.

alt text http://img101.imageshack.us/img101/1593/36679446.png


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).


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 );


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.


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.


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);
}


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜