围绕固定点旋转三角形

时间:2017-03-31 22:51:13

标签: c

我试图重新创建游戏小行星,而我现在正在让船显示并在屏幕上移动。目前我已经获得了下面的功能,它在屏幕上围绕原点绘制一个三角形。我想要做的就是绕着原点旋转船。

此时三角形被这个功能完全扭曲了,我不知道出了什么问题。我尝试旋转的角度是shipHeading,我试图遵循这个公式:

x' = x cos f - y sin f y' = y cos f + x sin f

其中f等于旋转角度

void drawShip(void){
    int shipX = getShipX();
    int shipY = getShipY();
    int shipHeading = getShipHeading();

    int x1, y1, x2, y2, x3, y3;

    x1 = shipX;
    y1 = shipY - 20;
    x2 = shipX - 10;
    y2 = shipY + 10;
    x3 = shipX + 10;
    y3 = shipY + 10;

    screen->drawTriangle(x1, y1, x2, y2, x3, y3, RED); //pre rotation

    x1 = (x1 * cos(double(shipHeading))) - (y1 * sin(double(shipHeading)));
    y1 = (x1 * sin(double(shipHeading))) + (y1 * cos(double(shipHeading)));
    x2 = (x2 * cos(double(shipHeading))) - (y2 * sin(double(shipHeading)));
    y2 = (x2 * sin(double(shipHeading))) + (y2 * cos(double(shipHeading)));
    x3 = (x3 * cos(double(shipHeading))) - (y3 * sin(double(shipHeading)));
    y3 = (x3 * sin(double(shipHeading))) + (y3 * cos(double(shipHeading)));

    x1 *= -1;
    y1 *= -1;
    x2 *= -1;
    y2 *= -1;
    x3 *= -1;
    y3 *= -1;

    screen->drawTriangle(x1, y1, x2, y2, x3, y3, BLUE); //post rotation

2 个答案:

答案 0 :(得分:3)

问题似乎与在旋转期间覆盖x1,y1,...有关。 介绍坐标的后转换版本,它可能会更好。

答案 1 :(得分:0)

我在数学中看到的一些问题:

  1. 您在更换点时旋转点数。这意味着虽然可以正确计算X,但新Y的计算将使用新的X而不是X的原始值。这是错误的,你需要在计算新点时保存旧点。请参阅下面的rotatePoint()中执行此操作的示例。
  2. 旋转时需要指定一个轴心点。再次,请参阅rotatePoint以了解如何完成此操作。这基于发布的here算法。
  3. cos()sin()期望角度为弧度单位。不确定您是否已将shipHeading考虑在内,但似乎不太可能,因为它是int。在我的解决方案中,我假设shipHeading是度,并在调用trig函数之前将其转换为弧度。
  4. 你将这些点乘以-1的翻译想法似乎很奇怪,并且会导致翻转的混乱。在小行星中,这应该是根据当前速度和加速度为点添加一个int。
  5. 创建算法的步骤是封装。不要尝试使用所有整数在一个函数中执行所有操作。创建像Point这样的抽象数据类型来表示(x,y)对。

    typedef struct {
              int x;
              int y;
            } Point;
    

    然后创建另一个名为Ship的抽象数据类型来表示由三个点组成的船。

    typedef struct {
               Point top;
               Point left;
               Point right;
            } Ship;
    

    接下来,创建一个辅助函数来抽象枢轴点周围的旋转点。然后创建一个高级函数,围绕一个枢轴点旋转船,调用roatePoint函数旋转其三个点中的每一个。

    通过抽象细节,算法变得清晰。它还意味着错误修复显示在一个地方,而不是很多。例如,cos()和sin()期望旋转以Radians表示,但我们通常根据旋转度来编码思考。通过将旋转隔离到PivotPoint(),所有数学都位于这一个位置。

    这是我的解决方案,其中包含几个缺失的函数:

    #include <stdio.h>
    #include <math.h>
    
    
    typedef struct {
              int x;
              int y;
            } Point;
    
    typedef struct {
               Point top;
               Point left;
               Point right;
            } Ship;
    
    // See https://stackoverflow.com/a/2259502/6693299 for point rotation algorithm
    Point rotatePoint(Point pivotPoint, Point point, int shipHeading)
    {
     Point newPoint = {0};
    
     // Translate point back to the origin
     point.x -= pivotPoint.x;
     point.y -= pivotPoint.y;
    
     // Cos and Sin expect angle in radians, but let's use shipHeading in degrees
     // To convert shipHeading in degrees to radians, multiply by 0.0174533
     double radians = ((double) shipHeading) * 0.0174533;
    
     // Rotate Point 
     // Compute new point based on old point and shipHeading
     newPoint.x = (point.x * cos(radians)) - (point.y * sin(radians));
     newPoint.y = (point.x * sin(radians)) + (point.y * cos(radians));
    
     // Translate the point back 
     newPoint.x += pivotPoint.x;
     newPoint.y += pivotPoint.y;
    
     return newPoint;
    }
    
    Ship rotateShip(Ship* ship, int shipHeading)
    {
     Ship newPosition = {0};
    
     // Rotate ship by shipHeading degrees, centered around top
     newPosition.top   = rotatePoint(ship->top, ship->top,   shipHeading);
     newPosition.left  = rotatePoint(ship->top, ship->left,  shipHeading);
     newPosition.right = rotatePoint(ship->top, ship->right, shipHeading);
    
     return newPosition;
    }
    
    Point newPoint(int x, int y)
    {
     Point point = {0};
     point.x = x;
     point.y = y;
     return point;
    }
    
    Ship newShip(int shipX, int shipY)
    {
     Ship newShip    = {0};
     newShip.top     = newPoint(shipX, shipY);
     newShip.left    = newPoint(shipX + 10, shipY - 5);
     newShip.right   = newPoint(shipX + 10, shipY + 5);
     return newShip;
    }
    
    // stubs
    int getShipX(void) { return 10;}
    int getShipY(void) { return 10;}
    int getShipHeading(void) {return 90;} // Expressed in degrees
    
    void drawTriangle(int x1, int y1, int x2, int y2, int x3, 
    {
     // stub
     printf("Ship location: (%d,%d) (%d,%d) (%d,%d)\n", x1,y1, x2,y2, x3,y3);
    }
    
    void drawShip(void){
        Ship ship        = newShip(getShipX(), getShipY());
        int  shipHeading = getShipHeading();
        int  RED         = 0; // stub
    
        drawTriangle(ship.top.x,   ship.top.y,
                     ship.left.x,  ship.left.y,
                     ship.right.x, ship.right.y, RED); //pre rotation
    
        ship = rotateShip(&ship, shipHeading);
    
    #if 0
        // Multiplying by -1 will Flip the ship? 
        // Use += instead to move the ship up by one 
        // Better to use a function like moveShip()
        ship.top.x   += -1;
        ship.top.y   += -1;
        ship.left.x  += -1;
        ship.left.y  += -1;
        ship.right.x += -1;
        ship.right.y += -1;
    #endif
    
        drawTriangle(ship.top.x,   ship.top.y,
                     ship.left.x,  ship.left.y,
                     ship.right.x, ship.right.y, RED); //pre rotation
    }
    
    int main(int argc, char** argv)
    {
     drawShip();
    }
    

    输出首先显示船的三个点(顶部)(左)(右),我使用X窗口符号(X,Y)默认为(10,10)(20,5)(20,15)屏幕的左上部分是(0,0)。第二行输出是围绕顶点(10,10)旋转90度后的点。您可以选择任何支点。有关Point Rotation的更多信息,请参阅this stackOverflow文章。

    scott> gcc asteroids.c -lm
    scott> a.out
    Ship location: (10,10) (20,5) (20,15)
    Ship location: (10,10) (14,20) (5,19)
    scott> 
    

    希望这有助于作为一个起点。进行更改以适应您的框架。