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

22.02.2015, 21:30

Winkelberechnung mit 2 Punkten

Hallo Programmierer,
ich bin seit einer Weile wieder wie wild am programmieren und möchte ein neues Spiel zusammenschrauben. Nun habe ich wieder ein Problem, welches ich schon ein paar mal gesehen habe:
Berechnung von Winkeln.
Ich habe mich da früher immer mit irgendwelchen Notlösungen und Workarounds dran vorbeigemogelt, aber diesmal möchte ich es "richtig" machen.

Zum Problem:
Ich habe eine Grafik auf dem Bildschirm, die sich an einer bestimmten X- und Y- Position befindet. Der Mauszeiger befindet sich ebenfalls an einer X- und einer Y- Koordinate.
Nun wirds komplizierter:
Ich denke mir eine Parallele zur Y-Achse, die durch die X-Koordinate meiner Grafik geht, also die kürzeste Verbindung zwischen Grafik und oberen Bildschirmrand.
Nun möchte ich den Winkel zwischen dieser Parallele und der gedachten Gerade, auf der sich die Grafik und der Mauszeiger befinden, berechnen.

Der Zweck:
Es soll später dazu dienen, eine Charaktergrafik in Richtung des Mauszeigers gucken zu lassen.

Nun habe ich zwei Lösungsansätze entwickelt:
Nr. 1 (Standard-Trigonometrie):

Quellcode

1
2
3
4
double difx = controller.getMouseX () - player.getX ();
double dify = controller.getMouseY () - player.getY ();

System.out.println (Math.toDegrees (Math.atan (difx/dify)));


Nr. 2 (2D-Vektorrechnung, Skalarprodukt (iwo muss man ja die langweiligen Mathestunden mal anwenden):

Quellcode

1
2
3
4
5
6
7
8
9
10
 int zerovectorx = 0;
int zerovectory = -1;
int playervectorx = controller.getMouseX () - player.getX ();
int playervectory = controller.getMouseY () - player.getY ();

double zähler = zerovectorx * playervectorx + zerovectory * playervectory;
double nenner1 = Math.sqrt (zerovectorx * zerovectorx + zerovectory * zerovectory);
double nenner2 = Math.sqrt (playervectorx * playervectorx + playervectory * playervectory);

System.out.println (Math.toDegrees (Math.acos(zähler / (nenner1 * nenner2))));


Mein Testverfahren:
Ich habe, während das Programm lief einfach mal die Maus kreisförmig um die Grafik herumbewegt, sollte eigentlich einen Output in der Richtung

0
23
54
78
97
126
150
195
206
258
296
312
345
360
0
34

ergeben. Oder so Ähnlich. Je nachdem, wie sehr man mit der Maus verwackelt. Jedenfalls von ungefähr 0 bis ungefähr 360 und dann wieder von 0 beginnend.

Jedenfalls tut das keiner von Beiden und ich wollte fragen, wie ihr solche Fälle realisiert? Irgendwie muss man doch vernünftig Winkel zwischen 2 Punkten ausrechnen können, egal wie die zueinander stehen, braucht man doch schließlich mindestens 3 Mal pro Spiel...

Danke für eure Tipps
LG Max

PS: Ich hab die Outputs nachträglich rausgenommen, weil die einfach zu groß waren und ich das "Spoiler"-Tag nicht gefunden habe.

birdfreeyahoo

Alter Hase

Beiträge: 756

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

2

22.02.2015, 21:49

Was ist jetzt das Problem?

Zu Nr.2 kann ich dir sagen, dass der Winkel immer zwischen 0 und 180 liegen wird, also immer der kleine Winkel.

Wenn du das nicht willst, musst du schauen ob z.B. die Maus rechts von der Grafik liegt (also x größer ist), wenn ja addierst du 180 zu dem Ergebnis. Wenn sie links ist ist es ja schon richtig.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

3

22.02.2015, 22:01

Irgendwie muss man doch vernünftig Winkel zwischen 2 Punkten ausrechnen können
Nun, mathematisch geht das nicht ;) Winkel gibt es nur zwischen zwei Vektoren, Strecken oder Geraden ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

birdfreeyahoo

Alter Hase

Beiträge: 756

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

4

22.02.2015, 23:19

Die Geraden hat er ja angegeben, das ist einmal eine Y-Parallele an der Position des Spielers und die Verbindung zwischen Spieler und Maus.
Mit dem Skalarprodukt sollte man da Winkel bekommen.

5

22.02.2015, 23:30

Ok, danke erst mal bis hier her :)
Dass 2. mathematisch bedingt unmöglich ist, habe ich mir schon fast gedacht, ich wollte eig nur sicher gehen. Vektoren gefallen mir prinzipiell besser, weil ich sie mir leichter bildlich vorstellen kann als "Sinuse" und "Tangense". Aber wenn ich noch die Maus bestimmen muss kommt ja noch mal Code dazu. Wie ist das eig mit der Performance? Muss ich da bei größeren Spielen auch ein Auge drauf haben, oder ist das bei 2D generell kein Problem? Meiner Erfahrung nach wirs erst bei exzessiver Schleifenbenutzung kritisch, aber kann es auch schlimm werden, wenn ich tausende if/elses in der Spielschleife abfrage?

@BlueCobold: natürlich gibt es Winkel zwischen Punkten. Aber bekanntlich erst nach 22:00 und if (getCoffeeAmount() == 0)

TGGC

1x Rätselkönig

Beiträge: 1 799

Beruf: Software Entwickler

  • Private Nachricht senden

6

23.02.2015, 00:21

Falls es einfach um den Winkel zwischen x Achse und der Verbindungstrecke der zwei Punkte geht, schau doch mal nach atan2.

7

05.03.2015, 20:17

Danke für die Tipps

Ok, ich wollt mich noch mal kurz melden und mich für die Hilfe bedanken. Ich habe mir die Ratschläge durchgelesen und mich entschieden bei den Vektoren zu bleiben indem ich birdfreeyahoos Lösung verbaut habe, damit ich eine korrekte Volldrehung hinkriege.

Falls jemand mal ein ähnliches Problem hat werde ich hier mal die vollständige Methode (wunderschön gekapselt) reinstellen:

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
public void controlCreatureRotation (Creature creature, double fastturnspeed, double slowturnspeed)
        {       
        vectormousex = mousex - creature.getX ();
        vectormousey = mousey - creature.getY ();
        amountmouse = Math.sqrt (vectormousex * vectormousex + vectormousey * vectormousey);
        creatureangle = creature.getRot ();

        mouseangle = Math.acos ((vectorzerox * vectormousex + vectorzeroy * vectormousey) / (amountmouse));
        if (vectormousex < 0)
            {
            mouseangle = 2 * Math.PI - mouseangle;
            }

        mouseangle -= creatureangle;
        if (Math.abs (mouseangle) > Math.PI)
            {
            mouseangle = -(mouseangle - Math.PI);
            }
        
        if (mouseangle > fastturnspeed)
            {
            creature.rotate (fastturnspeed);
            }
        else if (mouseangle < -fastturnspeed)
            {
            creature.rotate (-fastturnspeed);
            }
        else if (mouseangle > slowturnspeed)
            {
            creature.rotate (slowturnspeed);
            }
        else if (mouseangle < -slowturnspeed)
            {
            creature.rotate (-slowturnspeed);
            }
        }


Creature ist dabei eine Klasse, die das Objekt repräsentiert das gesteuert werden soll. Für die Methode ist eig nur wichtig, dass die Creature eine X- und Y-Koordinate und einen Rotationswinkel hält, was ja aus dem Quelltext hervorgehen sollte. Die Figur dreht sich erst relativ schnell zum Mauszeiger (mit fastturnspeed rad pro Durchlauf) und macht danach eine Feinausrichtung mit slowturnspeed rad pro Durchlauf).

Ich hoffe, es hilft jemandem :)

Werbeanzeige