2017-06-25 141 views
1

我需要在它自身周圍旋轉一個三角形(稱爲船)。
這是我到目前爲止,但它不起作用。它越來越小,直到它消失。使用三個頂點旋轉c中的三角形

void RotatePoint(Point *P, float angle) 
{ 
    float theta = angle * (180/3.1415); 
    P->x = (P->x * cos(theta)) - (P->y * sin(theta)); 
    P->y = (P->y * cos(theta)) + (P->x * sin(theta)); 
} 

void RotateShip(Ship *ship) 
{ 
    Rotate(&ship->A, rotateAngle); 
    Rotate(&ship->B, rotateAngle); 
    Rotate(&ship->C, rotateAngle); 
} 

點P是我想要旋轉的點,點C是三角形的中心。我認爲如果我旋轉所有三個頂點,三角形將旋轉。

在我的情況,我初始化這樣:

void initShip(Ship *ship) 
{ 
    ship->center.x = (SCREEN_W)/2.0; 
    ship->center.y = (SCREEN_H)/2.0; 
    ship->A.x = 0; 
    ship->A.y = -5; 
    ship->B.x = 15; 
    ship->B.y = 25; 
    ship->C.x = -15; 
    ship->C.y = 25; 
    ship->color = al_map_rgb(255, 255, 255); 
} 

船A,B和C是從三角形的中心的距離。我畫出它將A,B和C添加到中心頂點。

A=-0.699857,-19.963261 
A=-0.000857,-19.951065 
A=-0.699001,-19.914387 
A=-0.001712,-19.902250 
A=-0.698147,-19.865631 
A=-0.002565,-19.853554 

將一個鍵向後按一個鍵,使其順時針和逆時針旋轉。注意A如何縮小。 我不知道我在做什麼。當它達到頂端時,我應該回到20.00。這樣我的三角形正在縮小。 我使用cos(0.035)和sin(0.035),意思是2度。

+0

它爲什麼不起作用?你做了什麼來調試它? – nicomp

+0

它只是消失。繪圖功能是這樣的: 'void drawShip(ship * ship){ \t al_draw_triangle(ship-> center.x + ship-> Ax,ship-> center.y + ship-> Ay,ship-> center。 x + ship-> Bx,ship-> center.y + ship-> By,ship-> center.x + ship-> Cx,ship-> center.y + ship-> Cy,ship-> color,1) ; }' 當我按下鍵旋轉它時,它消失。我的數學一定是錯的,但我無法弄清楚什麼。 –

+0

請做一個[mcve],不需要整個繪圖和其他圖形的東西,只是一個main(),它打印座標sevaral次;展示他們如何變小,尤其是變得多快。 – Yunnosch

回答

0

我可以用int中的座標重現快速縮小(同時旋轉)。
(基於MCVE會更容易......)。
浮點座標,收縮慢得多,但仍然收縮。

我將這與您的實現以非常明顯的方式收集所有數學錯誤(計算機總是製造的)相關聯。

爲了完全避免萎縮:
,請勿操作相對座標,以旋轉。相反,將相對座標存儲爲常數,並將船的方向作爲一個角度加倍。

然後通過增大/減小角度來旋轉(環繞,保持在-Pi ... + Pi之內)。
然後通過始終將變化的角度應用於常量相對座標進行繪製。

(我只能告訴你詳細,如果你提供一個MCVE。)

這種方式,收集到的錯誤只會造成輕微和緩慢增長的取向差,
其中最有可能不會被察覺由飛行員 - 然後由飛行員糾正。
「嗯,這艘船還沒有完成我想要的360,哦,我會再轉一點。」

在附註中,我不相信您將角度用作cos()和sin()的參數的方式。
或者換句話說,我認爲
theta = angle * (180/3.1415); - >theta = angle;通過Pi掉頭。
theta = angle * (180/3.1415); - >theta = angle * (3.1415/180);用於通過180的U形轉彎。
對於您的實施,您將得到角度掉頭(Pi * 3.1415/180),這是我看不到原因的。

我也推薦使用math.h中的適當常量(例如,M_PI),而不是你自己的小數點後4位的常量。

1

OP有一個經典的錯誤:使用臨時(或中間)值來代替原來的/初始值。

作爲一個簡單的例子,考慮你有三個變量,ab,並c的情況下,想要一個變量轉動它們的值向左:

a = b; 
    b = c; 
    c = a; /* Oops! Won't work! */  

最後的分配是一個問題,因爲a不再是原來的價值!您不能以避免此問題的方式排列作業;唯一的變化就是哪個變量會受到這個問題的影響。爲了解決這個問題,你需要使用一個新的臨時變量來保存原始值:

t = a; 
    a = b; 
    b = c; 
    c = t; 

在OP的情況下,船舶的結構不應該混船的當前形狀,而真正的/在同樣的變量下,船的未旋轉形狀。即使你避免了上述問題,你仍然會遭受累積舍入誤差;它可能需要幾小時的遊戲玩法,但最終你的船最終會看起來不一樣。

的解決方案是描述在單獨的變量船舶形狀,或在船舶更新功能使用的常數。)

假設我們有一個可變dir指定以弧度的方向,從上逆時針旋轉時,0向上(朝向負y軸),π/ 2(和-3π/ 2)向左(朝向負x軸),π(和-π)向下,3π/ 2(和-π/ 2)向右,等等。如果deg是度,dir = deg * 3.14159265358979323846/180.0。我們還可以使用atan2()函數來找出dirdir = atan2(-x, y)

dir = 0,OP想要A = { 0, -5 },B = { 15, 25 }C = { -15, 25 }。如果我們定義Adir = 3.14159Ar = 5Bdir = -0.54042Br = sqrt(15*15+25*25) = 29.15476,和Cr = 29.15476,然後船頂點

A.x = center.x + Ar*sin(dir + Adir); 
A.y = center.y + Ar*cos(dir + Adir); 
B.x = center.x + Br*sin(dir + Bdir); 
B.y = center.y + Br*cos(dir + Bdir); 
C.x = center.x + Cr*sin(dir + Cdir); 
C.y = center.y + Cr*cos(dir + Cdir); 

如果OP要解決船型在rotateShip功能,然後

void rotateShip(Ship *s, double rotateAngle) 
{ 
    s->A.x = s->center.x + 5.00000 * sin(rotateAngle + 3.14159); 
    s->A.y = s->center.y + 5.00000 * cos(rotateAngle + 3.14159); 
    s->B.x = s->center.x + 29.15476 * sin(rotateAngle - 0.54042); 
    s->B.y = s->center.y + 29.15476 * cos(rotateAngle - 0.54042); 
    s->C.x = s->center.x + 29.15476 * sin(rotateAngle + 0.54042); 
    s->C.y = s->center.y + 29.15476 * cos(rotateAngle + 0.54042); 
} 

個人而言,我會使用可變數量的頂點定義船形:

typedef struct { 
    double x; 
    double y; 
} vec2d; 

typedef struct { 
    vec2d  center; 
    size_t  vertices; 
    const vec2d *shape;  /* Un-rotated ship vertices */ 
    double  direction; /* Ship direction, in radians */ 
    vec2d  *vertex; /* Rotated ship vertices */ 
} Ship; 

const vec2d default_shape[] = { 
    { 0.0, -5.0 }, 
    { -15.0, 25.0 }, 
    { 15.0, 25.0 }, 
}; 

void updateShip(Ship *ship) 
{ 
    const double c = cos(ship->direction); 
    const double s = sin(ship->direction); 
    size_t  i; 

    for (i = 0; i < ship->vertices; i++) { 
     ship->vertex[i].x = ship->center.x + c*ship->shape[i].x - s*ship->shape[i].y; 
     ship->vertex[i].y = ship->center.y + s*ship->shape[i].x + c*ship->shape[i].y; 
    } 
} 

void initShip(Ship *ship, const size_t vertices, const vec2d *shape) 
{ 
    ship->center.x = 0.5 * SCREEN_W; 
    ship->center.y = 0.5 * SCREEN_H; 

    if (vertices > 2 && shape != NULL) { 
     ship->vertices = vertices; 
     ship->shape = shape; 
    } else { 
     ship->vertices = (sizeof default_shape)/(sizeof default_shape[0]); 
     ship->shape = default_shape; 
    } 

    ship->direction = 0; 

    ship->vertex = malloc(ship->vertices * sizeof ship->vertex[0]); 
    if (!ship->vertex) { 
     fprintf(stderr, "Out of memory.\n"); 
     exit(EXIT_FAILURE); 
    } 

    updateShip(ship); 
} 

updateShip中,我們使用了2D旋轉ship->direction來旋轉由shape[]中頂點指定的船模型,將旋轉和平移的座標保存爲vertex[]

x_current = x_center + x_original * cos(direction) - y_original * sin(direction); 
    y_current = y_center + x_original * sin(direction) + y_original * cos(direction); 

如在例如,維基百科有關rotation的文章。請注意,原始座標x_originaly_original(或Ship結構中的shape[]陣列中的值)永遠不會被修改。

通過這種方式,您可以讓玩家通過更改shape指向新的船形來「升級」他們的船,並且vertices反映該數字。

+0

你想'default_shape' - >'default_ship'嗎? – chux

+1

@chux:好的,謝謝!實際上,因爲我想確保OP(和其他讀這個答案的人)瞭解船的當前頂點(以其當前的翻譯和方向)與船的(原始,未旋轉和未翻譯的)形狀之間的差異,我決定使用'default_shape'。我不知道它是否有效(有助於區分原始/未旋轉和當前/旋轉和翻譯),但這是目前我能做的最好的。 –