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

08.08.2010, 18:24

SFML - Position von Shapes

Hallo zusammen,

ich habe mich grade mal daran gesetzt, ein erstes Spiel per SFML zu schreiben (es soll ein simples Pong werden).

Dazu habe ich erstmal einen Kreis erstellt, der initial genau in der Mitte des Fensters liegt. Den Kreis habe ich als Shape erstellt.

Als ich diesen dann bewegen wollte, bin ich darauf gestoßen, dass die Koordinaten, die die verschiedenen Setter und Getter nutzen, relativ zum Zentrum des Shape liegen. Somit ist z.B. die Kollisionsberechnung sehr unschön, da ich jeweils manuell auf absolute Koordinaten umrechnen muss. Denn die Wände und Schläger liegen logischerweise in ihren eigenen Koordinatensystemen vor.

Ich bin auch auf die beiden Funktionen TransformToGlobal und TransformToLocal gestoßen. Als ich das laß, dachte ich, das wäre genau das richtige für mich, da sie Koordinaten vom einen in das andere System umwandeln. Aber als ich es dann getestet habe, habe ich festgestellt, dass nur auf die ursprünglichen Koordinaten transformiert wird. Wenn ich also das Objekt in der Mitte erstelle und nicht verschiebe, ist bei beiden Funktionen Ausgabe=Eingabe. Finde ich allerdings auch logisch dieses Verhalten, denn das Shape weiß ja gar nichts von der Größe des Fensters und seiner Position darin.

Natürlich könnte ich auch alle Objekte einfach an Position 0,0 initialisieren und dann entsprechend verschieben. Aber, wenn das die "richtige" Lösung ist, dann frage ich mich, warum es dieses System mit den lokalen Koordinaten gibt. Denn der Vorteil davon will sich mir nicht erschließen. Dann könnte man es ja auch einfach so machen, wie bei Sprites, wo bei der Initialisierung gar keine Position vorgegeben wird.

Könnt ihr mir weiterhelfen, was hier der gängige Weg ist? Wo liegt mein Verständnisfehler?

Gruß
Maddin

CBenni::O

1x Contest-Sieger

Beiträge: 1 145

Wohnort: Stuttgart

  • Private Nachricht senden

2

08.08.2010, 18:37

Es gibt die Funktion SetOrigin ;)

TransformToLocal transformiert einen absoluten Vektor (in Pixeln ab der oberen linken Ecke) in Lokale (ab Origin - Ursprung) um.
TransformToGlobal dementsprechend andersherum ;)

mfg CBenni::O
Ein Mitglied der VEGeiCoUndGraSonMaWiGeS Bewegung.
42!
Aufräumen kann jeder, nur das Genie überblickt das Chaos!
Metal will never die!
1. Sppro Gamecontest - mein Beitrag

3

08.08.2010, 18:37

Hallo Maddin,

da sowohl die Sprite- als auch die Shape-Klasse der SFML von der Klasse Drawable abgeleitet werden - sprich erben - stehen für beide Klassen die Funktionen TransformToLocal und TransformToGlobal zur Verfügung. Mit diesen Funktionen kannst du entsprechende Koordinaten umrechnen lassen. Hier gehts zu beiden Funktionen in der offiziellen SFML Dokumentation .

Gruß
SaRu_

*EDIT*: Sorry, CBenni::O war ein Stückchen schneller... :whistling:

4

09.08.2010, 18:39

Danke erstmal für die Antworten.

Kann es sein, dass die Funktion SetOrigin ab Version 2.0 die Funktion SetCenter ablöst. Denn in der Doku zu 1.6 (meine Version) finde ich zwar SetCenter, aber nicht SetOrigin (in der Klasse Drawable). In der Doku zu Version 2.0 ist es genau umgekehrt. Und wenn ich mir die Beschreibung so durchlese, finde ich keinen inhaltlichen Unterschied. Ist das nicht ziemlich unklug? Denn jeder, der SetCenter mit 1.6 genutzt hat, wird bei dem Umstieg auf 2.0 viel Änderungsaufwand haben.

Um wieder zu meinem Problem zurück zu kommen:
Die Funktion SetOrigin (bzw. SetCenter) bezieht sich aber jeweils nur auf die relativen Koordinaten des Objekts. 0,0 ist also in der oberen, linken Ecke des Objekts - und nicht des Fensters. Bedeutet das, dass ich Folgendes machen müsste, um absolute Koordinaten zu erhalten:

C-/C++-Quelltext

1
2
3
sf::Shape kreis=sf::Shape::Circle(300.0f,200.0f,10.0f); //Kreis an Position 300,200 mit Radius 10
kreis.SetCenter(-300.0f,-200.0f); //300-300=0 = obere linke Ecke des Fensters
sf::Vector2f v=kreis.TransformToGlobal(0.0f,0.0f); //Mittelpunkt des Kreises in absoluten Koordinaten


So funktioniert es zwar, aber ist das wirklich die beste Lösung?
Außerdem kann ich so nicht besonders gut rotieren, da es immer um die obere linke Ecke des Fensters dreht.

5

09.08.2010, 19:50

Hallo Maddin,


mit deinem Quellcode setzt du das Zentrum deines Kreises in die linke, obere Ecke deines Fensters - das hast du ja selbst auch schon geschrieben. Das das für deine Rotation nicht von Vorteil ist hast du auch erkannt. Also warum machst du es dann? Die Funktion SetCenter dient dazu das Drehzentrum für Rotationen festzulegen und gehört in deinem Fall wahrscheinlich in den Mittelpunkt des Kreises.

Nur noch mal zur Klärung der Funktionen:

SetCenter - Setzt das Drehzentrum für Rotationen, ändert aber an der Position des - in diesem Fall - Kreises nichts.

SetRotation - Dreht den Kreis um das mit SetCenter festgelegte Drehzentrum.

SetPosition - Positioniert das Drawable (in diesem Fall Shape) an die gegebenen - globalen - Koordinaten.

Mir ist nicht ganz klar, was du genau mit globalen Koordinaten anfangen willst? Vielleicht erklärst du das noch mal genauer.

Gruß
SaRu_

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »SaRu« (09.08.2010, 19:57)


NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

6

09.08.2010, 20:35

SetCenter - Setzt das Drehzentrum für Rotationen, ändert aber an der Position des - in diesem Fall - Kreises nichts.

doch! leider wird die position davon auch beeinflusst. wurde setcenter auf die 40|40 gesetzt, wird die linke obere ecke des bilds an positionX-40|positionY-40 gezeichnet. meist ist das ziemlich nervig aber für diesen fall wohl perfekt.(so ist es jedenfalls in der 1.6er version)
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

7

09.08.2010, 20:35

Zitat

SetPosition - Positioniert das Drawable (in diesem Fall Shape) an die gegebenen - globalen - Koordinaten.

Das tut es eben leider nicht. SetPosition setzt die Position in lokalen Koordinaten. Wie ich jetzt festgestellt habe, wird dabei nur die Verschiebung berücksichtigt. Bei einer Rotation gebe ich dir Recht, dass es sich um die globalen Koordinaten verschiebt. Das ist wirklich sehr verwirrend. :S

Folgendes Beispiel:

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
#include <SFML\Window.hpp>
#include <SFML\Graphics.hpp>

int main()
{
    sf::RenderWindow app(sf::VideoMode(1000,600,32),"Mein SFML-Test-Fenster");
    sf::Event evt;
    
    sf::Shape s=sf::Shape::Circle(sf::Vector2f(500,300),20.0f,sf::Color::Black);
    s.SetPosition(200.0f,200.0f);

    while(app.IsOpened())
    {   
        while(app.GetEvent(evt))
        {
            switch(evt.Type)
            {
            case sf::Event::Closed:
                app.Close();
                break;
            case sf::Event::KeyPressed:
                switch(evt.Key.Code)
                {
                case sf::Key::Escape:
                    app.Close();
                    break;
                }
                break;
            }
        }

        app.Clear(sf::Color(230,230,230));
    
        app.Draw(s);
        
        app.Display();
    }
    return 0;
}


Ich erzeuge einen Kreis, genau in der Mitte des Fensters. Anschließend sage ich mit SetPosition, dass der Kreis an die globale Position 200,200 gesetzt werden soll. Er wird aber um die angegebenen Werte verschoben. D.h. der Kreis liegt jetzt - in globalen Koordinaten - bei 700,500. Das kann man in der Ausgabe auch deutlich sehen.

Globale Koordinaten hätte ich gerne, damit alle Objekte sich auf das gleiche Koordinatensystem beziehen, sonst ist Kollisionsberechnung unmöglich.

Um eine Kollision des obigen Kreises mit der oberen Kante zu erkennen, müsste ich folgendes testen (Radius ignoriert): if(s.GetPosition().y<=-300) -> Kollision. Das bedeutet, dass ich die anfängliche globale Position (300) irgendwo speichern müsste, damit ich umrechnen kann. Oder ich müsste sagen: Für den Kreis liegt die Kante 300 Pixel weit weg. Für einen anderen Kreis, der an Position 200,100 initialisiert wurde, liegt die Kante 100 Pixel weit weg. Das ist aber sehr unschön.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

8

09.08.2010, 20:38

das kann nicht sein. vielleicht hast du einmal ausversehen die move methode und nicht die setposition methode benutzt?
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

9

09.08.2010, 20:40

Ich habe es genauso, wie es oben zu sehen ist, ausgeführt und hierher kopiert. Der Kreis ist eindeutig unten rechts in der Ecke.

CBenni::O

1x Contest-Sieger

Beiträge: 1 145

Wohnort: Stuttgart

  • Private Nachricht senden

10

09.08.2010, 20:47

Aus diesem Grund habe ich meinem Framework eine FloatingObj.Klasse spendiert, die Sprites kapselt, mit dem Vorteil, dass sie um die Mitte rotieren und die Position an der linken oberen Ecke gemessen wird ;)

mfg CBenni::O
Ein Mitglied der VEGeiCoUndGraSonMaWiGeS Bewegung.
42!
Aufräumen kann jeder, nur das Genie überblickt das Chaos!
Metal will never die!
1. Sppro Gamecontest - mein Beitrag

Werbeanzeige