如何通过计算新的x和y位置围绕其中心旋转精灵?

时间:2009-10-17 09:02:40

标签: c++

我正在使用Dark GDK和C ++创建一个简单的2D游戏。我正在旋转一个物体,但它从精灵的左上角旋转。

我有以下变量:

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

是否有一种算法可以修改精灵的枢轴点,优于中心?

这是一个代码示例:

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

修改

我正在考虑为这个问题开辟一些声誉,我还没有得到一个适合我的答案。如果有人可以提供完成工作的实际代码示例,我会非常高兴。

Blindy回答的问题是,无论我多么简单地来回翻译,spirte仍围绕左上角旋转并将其移动到绕左上角旋转的某处,然后将其移回到相同位置立场什么都没有完成。以下是我认为将要发生的事情:

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

就是这样,没有混淆我创造了一个正在发生的事情的图像。左边显示实际发生的情况,右边显示我需要发生的事情。

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

6 个答案:

答案 0 :(得分:7)

您需要执行以下操作:

  • 翻译( - playerx - playerwidth / 2, - playery - playerheight / 2)
  • rotateangle
  • 旋转
  • 翻译(playerx + playerwidth / 2,playery + playerheight / 2)

我们的想法是将您的精灵集中在原点上,然后围绕原点(glRotate)旋转,然后在获得旋转的精灵后,将其转换回原位。

注意:如果您的精灵最初在原点周围“居中”,但是角落不是精灵的实际中心,则首先将对象平移到精灵的中心与原点居中。因此,如果你的精灵在原点的左上角,你会翻译(-playerwidth / 2,-playerheight / 2),然后旋转然后翻译(playerx,playery)。

答案 1 :(得分:4)

到目前为止,答案是正确的,告诉你应该如何完成,但我担心Dark GDK API似乎过于原始,无法以那么简单的方式完成。

不幸的是,dbRotateSprite将精灵旋转到左上角,而不管精灵的变换如何,这就是为什么你对其他建议没有运气的原因。要模拟围绕中心的旋转,您必须手动校正精灵的位置,即您只需旋转精灵然后将其移动为两步过程。

我不熟悉API,我不知道y是上升还是下降以及测量角度的方式,所以我将做一些假设。如果y像许多其他2D图形系统一样被测量,并且从x轴测量的角度随着从正x轴到正y轴的增加而增加,那么我相信正确的伪代码看起来像

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

答案 2 :(得分:2)

旋转对象时,您将对构成对象的点应用变换。在这种情况下,四个角各自自行旋转,最终结果是在新位置形成的四边形。正如其他人提到的那样,关键部分是知道点旋转的原点。

想象一下,如果不是精灵,你只有一个点。如果它的原点位于与该点相同的位置,则旋转它将没有效果(点的位置不会移动)。但是,如果原点位于其他任何位置,则该点将以圆形旋转,原点为该圆的中心。你怎么会把这个起源变成某个地方而不是与该点相同的位置呢?在坐标系内移动点。换句话说,翻译它。

各种变换的顺序(旋转,平移,缩放等)对此非常重要。如果您将点旋转180度然后将其平移到右侧,它将结束到它开始的位置的右​​侧,但是如果您将其向右移动然后将其旋转180度,它将最终在

我建议阅读2D转换。了解矩阵在所有这些方面的作用也很有用,但并不是绝对必要的,以获得你正在寻找的效果。

答案 3 :(得分:1)

看着你的形象,你正在做的是你正在旋转广场,你根本就没有翻译它。这就是你正在做的事情:

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

正如您所看到的,您的方块的左上角位于原点,而您所做的只是围绕原点旋转。

这就是我说你应该做的事情:

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

您只能围绕中心旋转,因此将要旋转图元的点居中,然后将它们放在您想要的位置。

答案 4 :(得分:1)

OMG我已经尝试过一段时间了,我找到了这个页面,只需复制一下。 这是基于以前的一篇文章。

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

答案 5 :(得分:1)

你可以使用dbOffsetSprite();

创建精灵时,默认情况下它们的插入点是左上角(和dbRotateSprite();它们围绕插入点旋转),您可以使用此函数来更改插入点。它的格式是dbOffsetSprite(精灵数,偏移量X,偏移量Y);

所以你可以说

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

其中NUMBER是精灵ID号。

精灵的插入点现在位于其图像的中心。

当然,这可能会打开一个全新的蠕虫,因为插入点现在位于精灵的中心(或者你设置它的地方),这意味着调用dbSpriteX(NUMBER);会给你精灵的中心而不是边缘。