簡體   English   中英

圍繞固定點旋轉三角形

[英]Rotating a triangle around a fixed point

我正在嘗試重新制作《小行星》游戲,目前正在讓飛船在屏幕上顯示和移動。 現在,我有了下面的函數,該函數在屏幕上圍繞原點繪制一個三角形。 我想做的就是也繞原點旋轉船。

此刻三角形完全被該函數扭曲了,我不確定出了什么問題。 我想旋轉的角度是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

該問題似乎與旋轉期間覆蓋x1,y1 ...有關。 介紹坐標轉換后的版本,它可能會更好。

我在數學中看到一些問題:

  1. 當您更改點時,您正在旋轉它們。 這意味着,雖然X可以被正確計算,新的計算Y將采用全新的X ,而不是原始值X 這是錯誤的,並且在計算新點時需要保存舊點。 請在下面的rotatePoint()中查看執行此操作的示例。
  2. 旋轉時需要指定一個樞軸點。 同樣,請參考rotatePoint來了解如何完成此操作。 這基於此處發布的算法。
  3. cos()sin()期望角度為弧度單位。 不知道您是否已經在shipHeading考慮了這shipHeading ,但由於它是int ,因此似乎不太可能。 在我的解決方案中,我假設shipHeading以度為單位,並在調用trig函數之前將其轉換為弧度。
  4. 您將點乘以-1的翻譯想法似乎很奇怪,並且會導致出現各種混亂的翻轉。 在小行星中,應根據當前速度和加速度在點上添加一個整數。

創建算法的步驟是封裝。 不要試圖用所有int在一個函數中做所有事情。 創建諸如Point的抽象數據類型來表示(x,y)對。

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

然后,創建另一個稱為Ship的抽象數據類型,以表示由三點組成的一艘船。

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

接下來,創建一個輔助函數來抽象圍繞樞軸點的旋轉點。 然后創建一個高級功能,使船繞樞軸點旋轉,然后調用roatePoint函數旋轉其三個點。

通過抽象細節,算法變得清晰。 這也意味着錯誤修復僅在一個位置而不是多個位置顯示。 例如,cos()和sin()期望旋轉以弧度表示,但是我們通常以旋轉度來編碼思維。 通過將旋轉隔離到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度后的點。 您可以選擇任何樞軸點。 有關“點旋轉”的更多信息,請參閱 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> 

希望這可以作為起點。 進行更改以適合您的框架。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM