Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

29.11.2009, 22:48

Problem: Objekt um Punkt kreisen lassen 2D (Sonnensystem)

Hallo Programmierer,

ich habe das Problem ein Objekt um einen beliebigen (sich bewegenden[kann man auf Objekt um Punkt reduzieren]) Punkt kreisen zu lassen. (Problem Sonnensystem)

Ausgangssituation:
Objekt (Planet) mit x, y Koordinate
Beliebiger Punkt mit x, y Koordinate
Koordinatensystem = MM_TEXT (Ursprung [0,0] = obere linke Ecke)

---------->
| x
|
| y
\/

Zielsetzung:
Abbildung eines Sonnensystems mit Sonne Planeten und Monden.

Benötigt:
void DreheumPunkt (float ObjektX, float ObjektY, PunktX, PunktY, Geschwindigkeit/Zeit);
(können auch arrays sein)

Ich habe schon eine 2D-Vektorklasse erstellt, die mir einen Vektor zwischen zwei Punkten erstellt und dessen Länge (Kreisradius) zurückgibt. Genau hiernach komme ich aber nicht weiter. Zwar weiß ich, dass x=r*cos(w*t) und y=r*sin(w*t) ist, dies gilt aber nur für den Einheitskreis. Ich bin mir noch unschlüssig ob eine Fallunterscheidung stattfinden muss oder nicht. Da ich wohl nicht der erste mit diesem Problem bin und ich nach langem Suche keine Lösung fand, hoffe ich hier auf Hilfe. (Mathe liegt leider länger hinter mir)

Mfg

HighligerBimBam

the[V]oid

Alter Hase

Beiträge: 775

Wohnort: Aachen

  • Private Nachricht senden

2

29.11.2009, 22:53

Vielleicht solltest du für deine Objekte eine Klasse schreiben, die den momentanen Rotationswinkel zum übergeordneten Objekt (Mond -> Planet, Planet -> Sonne) speichert. Mit der voranschreitenden Zeit erhöst du dann alle Winkel um einen bestimmten Wert und wenn dies geschieht, kannst du die Position jedes beliebigen Objekts über einfache cos/sin-Operationen berechnen.

Pseudocode:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Objekt
{
  float fDegOverTime = 1;
  float fDeg;
  float fDist;
  List<Objekt> subobjekte;
  Objekt (float _fDist, float _fDeg = 0) { fDeg = _fDeg; fDist = _fDist; }
  void move (float fDeltaTime) { fDeg += fDegOverTime * fDeltaTime; }
}

main ()
{
  Objekt sonne (0);
  Objekt erde (10);
  Objekt mond (0.1f);
  Objekt merkur (3);
  Sonne.subobjekte.add (merkur);
  Sonne.subobjekte.add (erde);
  Erde.subobjekte.add (mond);
  float fZeit = currentTime ();
  while (true)
  {
    float fZeitNeu = currentTime ();
    float fDeltaTime = fZeitNeu - fZeit;
    for all (x IN sonne.subobjekte VEREINIGT erde.subobjekte)
    {
      x.move (fDeltaTime);
    }
    zeichneObjekt (sonne);
  }
}

void zeichneObjekt (Objekt o, float fOriginX = 0, float fOriginY = 0)
{
  drawPoint (fOriginX, fOriginY);
  for all (obj IN o.subobjekte)
  {
    float x = fOriginX + cos (obj.fDeg) * obj.fDist;
    float y = fOriginY + sin (obj.fDeg) * obj.fDist;
    zeichneObjekt (obj, x, y);
  }
}
<< an dieser Stelle ist eine Signatur verstorben >>

3

29.11.2009, 23:15

Die Frage, die sich stellt, ist, ob du nur ein simples Problem mit 2 Körpern (z.B. Mond und Erde oder Sonne u. Erde) darstellen willst, oder ob du eine physikalisch halbwegs korrekte Simulation erstellen willst.

Für den ersten Punkt, reicht es völlig, deinem Objekt entsprechend der Zeit die x und y koordinaten aus cos(t) und sin(t).

Allgemein schaut der Code den du suchst vermutlich irgendwie so aus (keine Garantie auf Richtigkeit)

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PositionVector GetPosition(float Time, PositionVector Offset)  
{
float Radius = 200.f;
float AngularSpeed = 500.f;

PositionVector Pos;

Pos.x = cos ( Time * AngularSpeed  );
Pos.x = sin ( Time * AngularSpeed  );

Pos *= Radius;

Pos += Offset;

return Pos;
}


PositionVector ist jetzt mal deine 2D-Vectorklasse mit .x und .y, Offset ist der Rotationsmittelpunkt (also bei dir die Sonne oder um was halt gekreiselt wird) und Time die aktuelle Zeit. Radius gibt den Kreisradius an und AngularSpeed die Winkelgeschwindigkeit, also wie schnell das ganze abdüst.

Die Werte sind total willkprlich gewählt, es kann gut sein, dass sich garnichts tut, oder aber, dass das ganze so schnell läuft, dass du garnichts mehr siehst ^^

Das das ganze physikalisch gesehen keinen Sinn macht, muss ich dir aber nicht erklären, oder? :P

Edit:

Da tippt man sich nen Wolf und dann editiert einer drüber ganz frech seinen Beitrag xD

Hier noch ein dazu vll interessantes Projekt:
http://www.sfml-dev.org/wiki/en/projects/solarcreation

So Far..

Laguna

Crush

Alter Hase

Beiträge: 383

Wohnort: Stuttgart

Beruf: Softwareentwickler

  • Private Nachricht senden

4

29.11.2009, 23:33

Dabei fliegen die Planeten um die Sonne gar nicht wirklich in einer Kreisbahn, sondern in Ellipsen in deren Mittelpunkt nicht die Sonne liegt :D (kann man schön in dieser Simulation sehen: http://www.fernstudium-physik.de/mediens…ravitation.html - einfach auf Earth´s companions stellen und start drücken)

5

29.11.2009, 23:36

:lol: Ab und zu ist das simpelste das schwerste...

Pos += Offset :D

Nice: Einheitskreis + Vektor + Offset = Rotation um beliebigen Punkt

Auf Offset wäre ich wohl niemehr drauf gekommen :lol:

Ich danke euch für eure schnelle Hilfe und werde die Implementation morgen in Angriff nehmen und mich bei Problemen oder Erfolg nochmals melden.

Mfg

HighligerBimBam

6

30.11.2009, 16:18

Hi,

leider habe ich es noch nicht geschafft. :(

Das Programm macht... naja wie soll ich sagen... merkwürdiges. Es nimmt ungefähr die obere Rechte Ecke des Bildschirms und läst sie in einer teilkreisbewegung um den Mittelpunkt auf der X-achse halber Bildschirmhöhe flackern. :oops:

Wie dem auch sein hier hilft nur noch Code... (ich beschränke mich auf das wesendlichste) Lässt sich ohne Fehler ausführen, maybe hab ich eine Include vergessen (glaub nicht).

Ich wäre über das Finden des Fehlers sehr dankbar. In MoveGame kann man anhand des Beispiels sehen, dass der Rest wohl funktioniert. (Sterne bewegen sich von links nach rechts.)

Hauptklasse

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TimeFrame
{
private:
    DWORD loopStart, loopEnd;
    float Time;

    void CalculateTime();

public:
    TimeFrame ();
    ~TimeFrame ();

    void SetStart();
    void SetEnd();
    void MoveGame(HWND hWnd);
    void RenderGame(HWND hWnd);
    void InitGame(HWND hWnd);
};


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//Globale Spielvariablen

list<BackgroundStars> BackgroundStarsList;

//Ermitteln der Auflösung

static int cxClient = GetSystemMetrics(SM_CXSCREEN);
static int cyClient = GetSystemMetrics(SM_CYSCREEN);
static int cxChar, cyChar, cxCaps;

TimeFrame::TimeFrame ()
{
    Time = 0.0f;
}
TimeFrame::~TimeFrame ()
{

}

//PRIVATE

void TimeFrame::CalculateTime()
{
    Time = (float)(loopEnd - loopStart) / 1000.0f;
}

void TimeFrame::SetStart()
{
    loopStart = timeGetTime(); //Benötigt winmm.lib LINKER

}

void TimeFrame::SetEnd()
{
    loopEnd = timeGetTime(); //Benötigt winmm.lib LINKER

    CalculateTime(); //Berechnet benötigte Zeit für Messageloop

}

void TimeFrame::MoveGame(HWND hWnd)
{
    //Bewegung der Objekte um einen mit Time multiplizierten Wert BEISPIEL FUNKTIONIERT

    /*list<BackgroundStars>::iterator j;
    for (j = BackgroundStarsList.begin(); j != BackgroundStarsList.end(); j++)
    {

        j->SetXY(j->GetX() + 10 * Time, j->GetY());
        
        if (j->GetX() >= cxClient)
            j->SetXY(0, j->GetY());
    }*/

    //???????????????????????????????????????????????????????????????????

    list<BackgroundStars>::iterator j;
    for (j = BackgroundStarsList.begin(); j != BackgroundStarsList.end(); j++)
    {
        float XYarr[2], Mittearr[2];
        XYarr[0] = j->GetX();
        XYarr[1] = j->GetY();
        Mittearr[0] = (float)cxClient / 2;
        Mittearr[1] = (float)cyClient / 2;

        float x, y;

        DreheUmPunkt(Time, 10, XYarr, Mittearr, x, y); //x, y = Referenz


        j->SetXY(x, y);
    }
    //??????????????????????????????????????????????????????????????????????

}

void TimeFrame::RenderGame(HWND hWnd)
{
    //Zeichnen der Objekte um einen mit fTime multiplizierten Wert

    HDC             hdc;
    HBRUSH          hBrush;
    PAINTSTRUCT     ps;
    RECT            rect;

    //Zeichnen Hintergrund-Objekte

    list<BackgroundStars>::iterator j;
    for (j = BackgroundStarsList.begin(); j != BackgroundStarsList.end(); j++)
    {
        rect.bottom = (int)j->GetY()+1;
        rect.top = (int)j->GetY()-1;
        rect.right = (int)j->GetX()+1;
        rect.left = (int)j->GetX()-1;
        InvalidateRect(hWnd, &rect, TRUE);
        hdc = BeginPaint(hWnd, &ps);
        SetPixel(hdc, (int)j->GetX(), (int)j->GetY(), RGB(j->GetColor(), j->GetColor(), j->GetColor()));
        EndPaint(hWnd, &ps);
    }

    /* GEHÖRT ZU BEISPIEL FUNKTIONIERT
    rect.bottom = cyClient;
    rect.top = 0;
    rect.right = cxClient;
    rect.left = cxClient - 1;
    InvalidateRect(hWnd, &rect, TRUE);
    hdc = BeginPaint(hWnd, &ps);
    hBrush = CreateSolidBrush (RGB (0,0,0));
    FillRect (hdc, &rect, hBrush);
    EndPaint(hWnd, &ps);*/
}

void TimeFrame::InitGame(HWND hWnd)
{
    TEXTMETRIC      tm;
    HDC             hdc;

    //Startwert für Zufallsvariablen

    srand ((unsigned int)time(NULL));

    hdc = GetDC(hWnd);
    GetTextMetrics(hdc, &tm);
    cxChar = tm.tmAveCharWidth;
    cyChar = tm.tmHeight + tm.tmExternalLeading;
    cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
    ReleaseDC(hWnd, hdc);

    //Initialisieren der Hintergrundsterne

    BackgroundStars* BStars;
    float BStarX, BStarY;
    int BStarC;
    int Stars = rand() % 500 + 501;
    for (int i=0; i <= Stars; i++)
    {
        BStarX = (float)(rand() % cxClient);
        BStarY = (float)(rand() % cyClient);
        BStarC = rand() % 256;
        BStars = new BackgroundStars(BStarX, BStarY, BStarC);
        BackgroundStarsList.push_back(*BStars);
    }
}



C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
void DreheUmPunkt(float Time, float Speed, float O[2], float M[2], float &x, float &y)
{
    Vektor2D *Vektor;
    Vektor = new Vektor2D(O, M);

    x = Vektor->GetLength() * cosf (Time * Speed + Vektor->GetAngle()) + M[0];
    y = Vektor->GetLength() * sinf (Time * Speed + Vektor->GetAngle()) + M[1];

    delete Vektor;
}


Vektor2D

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Vektor2D
{
private:
    float x;
    float y;
    float length;
    float angle;
    float xN;
    float yN;

    void VektorLength();
    void VektorAngle();

public:
    Vektor2D(float O[2], float M[2]);
    ~Vektor2D();
    void SetLength(float nlength);
    float GetAngle();
    float GetLength();
    float GetX();
    float GetY();
    float GetXN();
    float GetYN();
};


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Vektor2D::Vektor2D(float O[2], float M[2])
{
    x = O[0] - M[0];
    y = O[1] - M[1];
    VektorLength();
    xN = x / length;
    yN = y / length;
    VektorAngle();
}

Vektor2D::~Vektor2D()
{

}

void Vektor2D::VektorLength()
{
    length = sqrtf(x * x + y * y);
}

void Vektor2D::SetLength(float nlength)
{
    length = nlength;
    x = xN * nlength;
    y = yN * nlength;
}

void Vektor2D::VektorAngle()
{
    //Winkel zwischen Vektor und X-Achse [1,0]

    angle = acosf((x * 1 + y * 0) / sqrtf((x * x + y * y) * (1 * 1 + 0 * 0)));
}

float Vektor2D::GetLength()
{
    return length;
}

float Vektor2D::GetAngle()
{
    return angle;
}

float Vektor2D::GetX()
{
    return x;
}

float Vektor2D::GetY()
{
    return y;
}

float Vektor2D::GetXN()
{
    return xN;
}

float Vektor2D::GetYN()
{
    return yN;
}


Hintergrundsterne (beispielhaftig)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BackgroundStars
{
private:
    int Color;
    float x;
    float y;

public:
    BackgroundStars(float ix, float iy, int iColor);
    ~BackgroundStars();

    void SetXY(float ix, float iy);
    float GetX();
    float GetY();
    int GetColor();
};


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
BackgroundStars::BackgroundStars(float ix, float iy, int iColor)
{
    x = ix;
    y = iy;
    Color = iColor;
}

BackgroundStars::~BackgroundStars()
{

}

float BackgroundStars::GetX()
{
    return x;
}

float BackgroundStars::GetY()
{
    return y;
}

int BackgroundStars::GetColor()
{
    return Color;
}

void BackgroundStars::SetXY(float ix, float iy)
{
    x = ix;
    y = iy;
}


Includeliste

C-/C++-Quelltext

1
2
3
4
5
6
7
8
#include <windows.h>        //Windows Bibliotheken

#include <stdlib.h>         //Für Zufallszahlen

#include <stdio.h>          //Standard Input-Output

#include <time.h>           //Zufallszahlen

#include <cmath>
#include <list>         //Ermöglicht den Gebracuh von Listen


using namespace std;


Winmain

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int APIENTRY _tWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    //Erstellen des Window-Handles

    HWND hWnd;

    //Initialisieren des Fensters

    if (!initMainWindow(hWnd, hInstance)) return 0;

    //Erzeugen des Spielobjektes

    TimeFrame Game;

    //Initialisieren des Spielobjektes

    Game.InitGame(hWnd);

    //Haupt Nachrichtenschleife

    MSG msg = {0};
    while (WM_QUIT != msg.message)
    {
        Game.SetStart(); //Zeit bestimmen


        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        Game.MoveGame(hWnd); //Bewegen der Objekte

        Game.RenderGame(hWnd); //Zeichnen der Objekte


        Game.SetEnd(); //Zeit bestimmen und Differenz berechnen

    }

    //Ausstiegspunkt des Programms

    return (int) msg.wParam;
}

In der CALLBACK steht nichts.

Mfg

HighligerBimBam

7

30.11.2009, 17:43

Ich glaube nicht, dass sich jemand durch diesen riesigen Batzen Code liest...

Noch zum Thema Vectorklasse: Du nutzt ja sicherlich irgendeine 2D Api. Diese bringen meist schon Vektoren mit. Nutz doch die, dann kannst du fehler dort schonmal ausschliessen. (Ausser zu Übungszwecken würde ich sowieso davon absehen, solch elementaren Klassen selbst zu schreiben.

Schreib dir die EINE entsprechende Funktion doch einfach mal in ein Konsolenprogramm und lass dir laufend Werte ausgeben (also
Frame 1 x = 200, y = 0
Frame 1 x = 199, y = 1
...)
Dann siehst du auch, ob der Fehler in der Berechnungsfunktion liegt, oder ganz wo anders...

So Far...

Laguna

8

30.11.2009, 17:56

Wo ist da DreheUmPunkt deklariert??
Metal ist keine Musik sondern eine Religion.

9

30.11.2009, 18:11

DreheUmPunkt ist nur eine Funktion

sah so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
void DreheUmPunkt(float Time, float Speed, float O[2], float M[2], float &x, float &y)
{
    Vektor2D *Vektor;
    Vektor = new Vektor2D(O, M);

    x = Vektor->GetLength() * cosf (Time * Speed + Vektor->GetAngle()) + M[0];
    y = Vektor->GetLength() * sinf (Time * Speed + Vektor->GetAngle()) + M[1];

    delete Vektor;
}


sieht nun so aus:

C-/C++-Quelltext

1
2
3
4
5
void DreheUmPunkt(float Time, float Speed, float O[2], float M[2], float &x, float &y)
{
    x = (int)((O[0] - M[0]) * cosf(Time * Speed) - (O[1] - M[1]) * sinf(Time * Speed)) + M[0];
    y = (int)((O[0] - M[0]) * sinf(Time * Speed) + (O[1] - M[1]) * cosf(Time * Speed)) + M[1];
}


Die Formel war wohl nicht ganz korrekt. Nur habe ich mit dieser Formel das Problem, dass der Abstand nicht immer gleich ist... Rundung sei dank :/

10

30.11.2009, 18:21

Wieso nimmst du x und y als float Parameter, wenn du sowieso nach int castest ? Das gibt doch gewaltige Ungenauigkeit.

Werbeanzeige