2017-03-31 17 views
2

私はゲームの小惑星を再現しようとしていますが、現在、船を表示して画面上を移動させています。現時点では、三角形を原点の周りに描く関数があります。私がしようとしているのは、船を原点の周りにも回転させることです。固定小数点の周りの三角を回転する

現在のところ、この関数で三角形が完全に歪んでしまい、何がうまくいかないのか分かりません。私は周りに回転させるようにしようとしている角度はshipHeadingであり、私は、この式に従うことをしようとしている: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 

答えて

3

問題の角度に等しい

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

回転中にx1、y1、...を上書きすることに関連しているようです。 座標変換の後変換バージョンを導入してください。より効果的です。

0

私はあなたの数学で見るいくつかの問題:

  1. あなたがそれらを変更している間、あなたはあなたのポイントを回転しています。これは、Xが正しく計算されるかもしれないが、新しいYの計算は、Xの元の値の代わりに新しいXを使用することを意味する。それは間違っており、新しいポイントを計算するときに古いポイントを保存する必要があります。下記のrotatePoint()でこれを行う例を見てください。
  2. 回転するときにピボットポイントを指定する必要があります。これがどのように行われるかは、rotatePointを参照してください。これは投稿されたアルゴリズムhereに基づいています。
  3. cos()およびsin()は、角度がラジアン単位であると予想します。すでにshipHeadingでこれを考慮しているかどうかはわかりませんが、intであるため考えられません。私の解答では、shipHeadingが度であると仮定し、trig関数を呼び出す前にそれをラジアンに変換します。
  4. ポイントに-1を乗算すると、あなたのトランケーションのアイデアは変わったように見えます。小惑星では、これは現在の速度と加速に基づいてポイントにintを加えるべきです。

アルゴリズムを作成する手順はカプセル化です。すべてのintで1つの関数内のすべてを実行しようとしないでください。 (x、y)のペアを表すPointのような抽象データ型を作成します。

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

次に、3つのポイントで構成される船を表す別の抽象データ型を作成します。

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

次に、ピボット点を中心に回転する点を抽象化するヘルパー関数を作成します。次に、ピボットポイントを中心に船を回転させる高水準の関数を作成します。この関数は、3つのポイントのそれぞれを回転するroatePoint関数を呼び出します。

詳細を抽象化することで、アルゴリズムが明確になります。また、バグ修正が多くの代わりに1か所に表示されることを意味します。たとえば、cos()とsin()は回転をRadianで表現すると考えていますが、通常は回転の度合いで考えることができます。回転をPivotPoint()に分離することで、すべての数学がこの1か所に配置されます。ここで

はスタブ不足している機能のいくつかと、私のソリューションです:

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

出力は最初、私は(10,10)にデフォルト設定された(右)(左)船の三点(トップ)が表示されます画面の左上部分が(0,0)であるXウィンドウ記法(X、Y)を使用して、(20,5)(20,15) 2番目の出力行は、90度回転した後の点です(10,10)。ピボットポイントを選択できます。ポイントローテーションの詳細については、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> 

これは出発点として役立ちます。フレームワークに合わせて変更します。

関連する問題