[英]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 ...有關。 介紹坐標轉換后的版本,它可能會更好。
我在數學中看到一些問題:
X
可以被正確計算,新的計算Y
將采用全新的X
,而不是原始值X
。 這是錯誤的,並且在計算新點時需要保存舊點。 請在下面的rotatePoint()
中查看執行此操作的示例。 rotatePoint
來了解如何完成此操作。 這基於此處發布的算法。 cos()
和sin()
期望角度為弧度單位。 不知道您是否已經在shipHeading
考慮了這shipHeading
,但由於它是int
,因此似乎不太可能。 在我的解決方案中,我假設shipHeading
以度為單位,並在調用trig函數之前將其轉換為弧度。 創建算法的步驟是封裝。 不要試圖用所有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.