Klasse Coord
-
Nexus schrieb:
.. ich habe bei einem Jump'n'Run-Spiel einmal eine Kollisionsabfrage bei Tiles (Bausteine) mit 45°-Ebene implementiert.
+-------+ | /#| | /###| | /#####| +-------+Das rechte untere Dreieck kollidiert mit dem Spieler, das obere linke ist "Luft". Jedenfalls fragte ich die X-Koordinate der Spielfigur ab. Dadurch konnte ich die Y-Position neu berechnen (da es sich um eine 45°-Gerade handelt, war das nicht schwierig) und abhängig von der X-Position setzen, damit die Spielfigur sich immer entlang der Diagonale bewegte.
Ist halt etwas sehr spezifisch, vielleicht fällt mir noch was Besseres ein.
Das ist ein schönes Beispiel.
Sobald man das Problem etwas verallgemeinert, sieht man, dass ausschließlich Operationen auf Koordinaten (Vektoren) nötig sind. Mal angenommen, der Spieler bewegt sich auf der 'Oberfläche'. Dann ist der Pfad, auf dem er sich bewegt, vorgegeben - z.B. durch einen Polygonzug. Wenn man es 'realistisch' simulieren will, ist u.a. seine Geschwindigkeit über x natürlich nicht konstant, sondern sie ist z.B. konstant bezogen auf den zurückgelegten Weg. Also es gibt ein Delta pro Zeiteinheit, welches in der Länge konstant ist; eine reine Vektoroperation.Anderer Fall: angenommen, die Spielfigur springt auf die Oberfläche. Dann gibt es einen Schnittpunkt zwischen der 'Sprungkurve' (eine Parabel oder auch eine senkrechte Gerade(Fall)) und dem Polygonzug der Oberfläche. Das Ergebnis ist eine Koordinate. Gerade im Fall einer Senkrechten (ein Fall oder Sprung) tut man sich für eine einigermaßen realistische Simulation keinen Gefallen, das ganze als y=f(x) darzustellen, sondern hier ist ein Coord=f(t) (über die Zeit) angebracht.
Ich bin mir dessen bewusst, dass man insbesondere bei integer-Koordinaten einiges 'vereinfachen' kann. Wenn meine Jump&Run-Umgebung nur aus horizontalen und 45°-Segmenten besteht, so spricht nichts dagegen, es so zu machen, wie Du es angedeutet hast. Aber ich meine, man sollte sich bewußt sein, dass das Programm dann auch auf dem Level stehen bleibt. Zumal ein allgemeinerer Entwurf in der Praxis gar nicht so viel aufwendiger - also teurer - ist.
Gruß
Werner
-
Hallo Werner,
den Punkt mit dem Delta hatte ich ja schon akzeptiert. Durch den Constructor ist ja ein impliziter Setter gegeben, der eben nur als ganzes Objekt fungiert. Aber wie löst du das, wenn du die Koordinate an jemanden übergeben willst, der mit der Klasse nichts anfangen kann? Schreibst du dann eine friend-Funktion als Koordinator?
-
Natürlich kann man das Beispiel so weit verkomplizieren und abstrahieren, dass es auch mit Vektoren geht. Das war aber keine physikalische Simulation mit parametrisierten Kurven, sondern ein 2D-Spiel. Glaubst du im Ernst, die Spielfiguren folgen nach dem Springen einer parabolischen Kurve?

Dass Vektoren prinzipiell keinen Komponentenzugriff benötigen, zeigt bereits die folgende Überlegung: Du kannst die einzelnen Komponenten jeweils durch das Skalarprodukt mit Einheitsvektoren extrahieren. Ebenso kannst du Multiplikation von Einheitsvektoren mit Skalaren und Vektoraddition dazu verwenden, beliebige Vektoren zusammenzubasteln. Ganz ohne Get und Set, nur die mathematischen Operationen müssen halt Zugriff haben.
Naja, für Mathematiker mag das zwar eleganter sein, ich habs jedoch gerne naheliegend. Ausserdem ist es schneller.
-
Nick Unbekannt schrieb:
.. wie löst du das, wenn du die Koordinate an jemanden übergeben willst, der mit der Klasse nichts anfangen kann? Schreibst du dann eine friend-Funktion als Koordinator?
Du sprichst einen neuralgischen Punkt an. Nun - ich rufe getX und getY - gegen die Getter hatte ich in diesem Threads noch nichts gesagt; obwohl ich ihnen durchaus skeptisch gegenüber stehe. Aber genau für diesem Zweck braucht man sie.
Gruß
Werner
-
Werner Salomon schrieb:
Aber genau für diesem Zweck braucht man sie.
Nicht, wenn man Skalarprodukt hat (siehe oben)

Anderes Beispiel: Eine Kugel mit (x,y)-Geschwindigkeitsvektor prallt an einer vertikalen Wand ab. Ich würde einfach
x = -x;setzen. Wie machst du das?
-
Nexus schrieb:
Natürlich kann man das Beispiel so weit verkomplizieren ..
ich habe die Erfahrung gemacht, dass das gar nicht komplizierter ist
Nexus schrieb:
Glaubst du im Ernst, die Spielfiguren folgen nach dem Springen einer parabolischen Kurve?

warum nicht!

Es ist völlig ok, wenn Du das 2D-Spiel so angehst, wie beschrieben. Ich habe nur die Erfahrung gemacht (und das ist meine Erfahrung), dass solche Setter zu einem unsauberen Programmierstil verführen, der die Kapselung bricht und bei größeren Projekten schnell zu unpflegbaren Programmen führt. Ich empfehle jedem, es einfach ohne Setter zu versuchen; oder es zumindest sparsam einzusetzen.
Was ich schlimm finde, ist dieser Automatismus: da ist ein Attribut und schon wird eine Getter- und Setter-Methode geschrieben. Das ist mit Sicherheit die falsche Vorgehensweise. Es gibt genug Tools, die OO im Namen führen, die genau das machen.Nexus schrieb:
Ausserdem ist es schneller.
wie oben schon erbeten:
Werner Salomon schrieb:
Aber jetzt lasst bitte die Performancekeule stecken
.Gruß
Werner
-
Nexus schrieb:
Anderes Beispiel: Eine Kugel mit (x,y)-Geschwindigkeitsvektor prallt an einer vertikalen Wand ab. Ich würde einfach
x = -x;setzen. Wie machst du das?Na ja - mit dem vorher gesagten sollte das doch klar sein. Wieso sind alle Wände immer vertikal? das ist doch wieder eine Einschränkung der Allgemeinheit - die hier auch nichts bringt. Die Wand hätte in meinem Modell einen Normalenvektor und an dem wird reflektiert. Das passt dann für alle anderen Wände auch. Hier spare ich die Fallunterscheidung.
-
Werner Salomon schrieb:
ich habe die Erfahrung gemacht, dass das gar nicht komplizierter ist
Also ich persönlich finde eine Kurve mit Parametrisierung der Zeit und Schnittpunktberechnung schon ein bisschen komplizierter als ein
y = x.Werner Salomon schrieb:
warum nicht!

Wäre doch schade, wenn man sich in der Luft nicht mehr bewegen könnte und bei Sprüngen aus grosser Höhe so schnell würde, dass die Spielfigur unkontrollierbar wird. Aber wir scheinen uns im Bezug auf das 2D-Spiel ja einig zu sein.

Werner Salomon schrieb:
Ich habe nur die Erfahrung gemacht (und das ist meine Erfahrung), dass solche Setter zu einem unsauberen Programmierstil verführen, der die Kapselung bricht und bei größeren Projekten schnell zu unpflegbaren Programmen führt. Ich empfehle jedem, es einfach ohne Setter zu versuchen; oder es zumindest sparsam einzusetzen.
Du sagst es, weg mit den Settern! Genau deshalb habe ich ja öffentlichen Zugriff auf die Variablen!

Scherz beiseite: Ich achte auch darauf, Methoden nur anzubieten, wenn sie sinnvoll sind. Aber nur solange es auch vernünftige und intuitive Alternativen gibt. Ansonsten machen gut gewählte Methoden den Code verständlicher und einfacher. Teilweise sind gewisse Methoden prinzipiell redundant, aber doch von Nutzen. Anderes Beispiel:
object.SetPosition(object.GetPosition() + offset); // vs. object.Move(offset);Werner Salomon schrieb:
Wieso sind alle Wände immer vertikal? das ist doch wieder eine Einschränkung der Allgemeinheit - die hier auch nichts bringt.
Sie bringt Einfachheit. Warum kann es nicht Situationen geben, die nur vertikale Wände erfordern? Man muss nicht immer alles so allgemeingültig und erweiterbar wie möglich halten. Du schreibst ja auch nicht jede Klasse als Template, nur weil sich in ferner Zukunft mal ein Typ ändern könnte.
Natürlich hast du völlig Recht, wenn sich die Tendenz abzeichnet, dass mehr Wände kommen. Aber präventive, kategorische Generizität halte ich nicht immer für eine gute Idee.
-
Ich würde nur
SetPosition()anbieten. WeilMove()könnte alsSetPosition()missinterpretiert werden. Oder wenn es sein muss dann ganz klarMoveRel()undMoveAbs(). Kommt aber auch auf die Häufigkeit der Verwendung an.
-
Nick Unbekannt schrieb:
Ich würde nur
SetPosition()anbieten. WeilMove()könnte alsSetPosition()missinterpretiert werden."To move" heisst bewegen/verschieben. Meiner Meinung nach ist relative Bewegung naheliegender, gerade wenn es noch zusätzlich ein
SetPosition()gibt. Und sonst Doku lesen
MoveRel()undMoveAbs()gefällt mir hingegen nicht.