Zielwinkel errechnen (mathematisches Problem)

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

 

proggerkind

Betreff: Zielwinkel errechnen (mathematisches Problem)

BeitragSo, Jun 21, 2009 18:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi Leute,

folgendes Problem:
ich bin gerade dabei, ein kleines 2D-Weltraumspielchen zu programmieren und hänge an den Bots.

Für diese soll unter Berücksichtigung ihrer Bewegungen, der Bewegung des Ziels (beides linear) und der Schussgeschwindigkeit der richtige Zielwinkel errechnet werden.

Wäre dankbar wenn mir jemand eine Funktion schreiben könnte, die den richtigen Zielwinkel zurückgibt. Smile


PS: Die Koordinaten sollten natürlich auch berücksichtigt werden Laughing
 

da_poller

BeitragSo, Jun 21, 2009 18:26
Antworten mit Zitat
Benutzer-Profile anzeigen
vielleicht wäe es besser wenn du das selber versuchst und wenn du code probleme hast postest du den hier und wir versuchen zu helfen..

ansonsten gehört sowas eher in den stellenmarkt.
 

ke^kx

BeitragSo, Jun 21, 2009 18:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Als kleiner Denkanstoss: Guck dir mal Geraden an... und Vektoren. Oder machs einfach geometrisch, du brauchst eigentlich nichts mehr als sin(, cos, tan) und dreiecksgesetze.
http://i3u8.blogspot.com
Asus Striker II
Intel Core2Quad Q9300 @ 2,5 GHz (aber nur zwei Kerne aktiv aufgrund der Instabilität -.-)
Geforce 9800 GTX
2GB RAM
 

proggerkind

BeitragSo, Jun 21, 2009 20:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Natürlich habe ich es schon selber versucht, schließlich geht es mir nicht darum um jeden Preis ein Spiel fertigzustellen, sondern um das Programmieren selbst.

Selbstverständlich habe ich auch schon mit Geraden, Vektoren und Dreieckssätzen herumexperimentiert, jedoch bin ich dabei auf Probleme gestoßen die meine mathematischen Kenntnisse bei weitem übertreffen (ich bin in der 9. Klasse, das heißt, dass ich eigentlich noch gar nicht wissen dürfte was Trigonometrie überhaupt ist).

Ich habe zunächst versucht, mithilfe von Cosinus und Sinus eines unbekannten Winkels die Vektoren eines Objekts so zu verändern, dass die Funktionen für die X- und Y-Koordinatendifferenz der beiden Objekte sich auf der Y-Achse schneiden. Danach wollte ich die Gleichung nach diesem Winkel auflösen...

Allerdings müsst ihr verstehen, dass ich - trotz zahlreicher Versuche - bei Additionstheoremen, inversen Tangensfunktionen usw. mit meinem Latein am Ende bin.

Ich versuche hier nicht mir ein Spiel von anderen zusammenprogrammieren zu lassen, ich habe in den 15 Monaten Entwicklungszeit bisher alles selbst gemacht. An dieser Stelle komme ich allerdings nicht weiter und ich brauche die beschriebene Funktion unbedingt, um endlich weiterprogrammieren zu können.

Xeres

Moderator

BeitragSo, Jun 21, 2009 20:06
Antworten mit Zitat
Benutzer-Profile anzeigen
2 Objekte, Ziel und Schuss, beide bewegen sich auf einer Geraden. Du musst den Schnittpunkt der beiden Geraden berechnen, dann kannst du mittels Atan2 den Zielwinkel berechnen.
Such dazu mal im Codearchiv unter "Schnittpunkt zweier Strecken berechnen"oder so...
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

Holzchopf

Meisterpacker

BeitragSo, Jun 21, 2009 20:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Das Problem ist ja, dass er den Winkel der Schussgerade nicht kennt :> und ergo so auch keinen genauen Schnittpunkt bestimmen kann =/
Ich setz mich nachher kurz mal dahinter und mach n paar Skizzen, ich denke, mit ein paar Funktionen sollte das machbar sein. Ich hoffs zumindest... Allerdings kann ich schon jetzt sagen, dass es ziemlich kompliziert wird, da ja ein Gegner einem langsamen Geschoss entfliehen kann ( = keine Lösung) oder es kann sein, dass es zwei Möglichkeiten gibt...
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

Xeres

Moderator

BeitragSo, Jun 21, 2009 20:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Man kann immer aus Koordinaten und Geschwindigkeit die Bewegungsrichtung (=Winkel) des Objekts berechnen, bzw. die lineare Funktion aus den Zwei Koordinaten berechnen.
Bisschen herumrechnerei aber nicht gar so schwer.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

Holzchopf

Meisterpacker

BeitragSo, Jun 21, 2009 23:10
Antworten mit Zitat
Benutzer-Profile anzeigen
*Erfolg* \o/

Code: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer BackBuffer()
Global TIMER = CreateTimer(60)

; (Start)position des Geschosses, resp des Schützens
Local P#[2], P0[2]
P0[0] = 200: P[0] = P0[0]
P0[1] = 200: P[1] = P0[1]
; Geschwindigkeit des Geschosses
Local vP# = 5
; Winkel des Geschosses
Local wP#

; (Start)position des Gegners
Local G#[2], G0[2]
G0[0] = 400: G[0] = G0[0]
G0[1] = 500: G[1] = G0[1]
; Geschwindigkeit des Gegners
Local vG#
; Winkel des Gegners
Local wG#

; Ob ein Schuss unterwegs ist
Local active = False

Local mh
While Not KeyDown(1)
   Cls
   mh = MouseHit(1)
   
   ; Schuss auslösen (Maustaste)
   If mh=1 And active=False
      ; Bewegung des Gegners richtung Maus
      Local dx = MouseX() -G0[0], dy = MouseY() -G0[1]
      wG = ATan2( dy, dx )
      vG = Sqr( dx *dx +dy *dy ) *0.01
      ; Schusswinkel berechnen
      wP = Schusswinkel( P0, G0, vP, vG, wG )
      ; *voodoo* aktivieren
      If wP > -1 Then active = True
   ; Zurücksetzen
   ElseIf mh=1 And active=True
      ; Beides auf Startpunkt setzen
      P[0] = P0[0]
      P[1] = P0[1]
      G[0] = G0[0]
      G[1] = G0[1]
      ; *voodoo* deaktivieren
      active = False
   EndIf
   If active
      ; Schuss bewegen
      P[0] = P[0] +Cos(wP) *vP
      P[1] = P[1] +Sin(wP) *vP
      ; Gegner bewegen
      G[0] = G[0] +Cos(wG) *vG
      G[1] = G[1] +Sin(wG) *vG
   EndIf

   Oval P[0]-1, P[1]-1, 3,3
   Oval G[0]-3, G[1]-3, 7,7
   
   Flip 0
   WaitTimer( TIMER )
Wend

End

Function Schusswinkel#( PunktA[2], PunktB[2], GeschwA#, GeschwB#, WinkelB# )
   ; Komponenten berechnen
   Local Sx# = PunktB[0] -PunktA[0]
   Local Sy# = PunktB[1] -PunktA[1]
   Local Vx# = Cos( WinkelB ) *GeschwB
   Local Vy# = Sin( WinkelB ) *GeschwB
   ; Koeffizienten für die Quadr. Gleichung
   Local a# = Vx *Vx +Vy *Vy -GeschwA *GeschwA
   Local b# = 2 *Sx *Vx + 2 *Sy *Vy
   Local c# = Sx *Sx +Sy *Sy
   ; Diskriminante
   Local D# = b *b -4 *a *c
   
   ; Wenn keine Lösung existiert, -1 zurückgeben
   If D < 0 Return -1
   
   ; Zeitpunkte berechnen
   Local t1# = ( -b +Sqr(D) ) /( 2*a )
   Local t2# = ( -b -Sqr(D) ) /( 2*a )
   ; Zeitpunkt negativ -> keine Lösung
   If t1 < 0 And t2 < 0 Return -1
   ; günstigeren Zeitpunkt wählen
   Local t# = t1
   If t2 > 0 And t2 < t1
      t = t2
   ElseIf t1 < 0
      t = t2
   EndIf

   ; Koordinaten des Treffpunkts bez. Punkt A
   Local x# = Sx +Vx *t
   Local y# = Sy +Vy *t
   
   ; Winkel zurückgeben
   Return ( ATan2( y#, x# ) +360 ) Mod 360
End Function


Hintergrund /Lösung(sansatz):
1. Ich hab zwei Funktionen gemacht, eine für die Distanz Geschoss-Schütze (lediglich y1(t) = v*t) und eine für die Distanz Schütze-Ziel ( y2(t) = |Zo + u*t - Po|, Zo = Startposition des Ziels, Po = Position des Schützens, u = Geschwindigkeit des Ziels )
2. Die Schnittpunkte dieser Funktionen geben an, wann eine Kollision stattfinden kann. Es kann auch sein, dass keine Lösung existiert.
3. Die daraus entstehende quadratische Gleichung wird umgeformt und
4. gelöst
5. Die Lösung (der Zeitpunkt) wird in die Bewegung des Ziels eingesetzt und schon hat man die Koordinaten, wo Schuss und Gegner sich treffen (/me zahlt n Batzen in die Wortwitzkasse)
6. Aus den Koordinaten wird der Winkel berechnet.

Die Funktion oben gibt einen Winkel im Bereich 0° -360° oder -1, wenn keine Lösung existiert, zurück. Ich habe sie bereits so optimiert, dass sie immer die kürzere Zeitspanne einsetzt.

Viel Spass damit!

mfG
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

mpmxyz

Betreff: Tolles Teil!

BeitragMo, Jun 22, 2009 17:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Nicht schlecht...
Ich hatte mir auch mal darüber Gedanken gemacht, habe es aber erst einmal verworfen, da ich nicht so schnell auf eine Lösung kam...
Es gibt aber noch Optimierungsmöglichkeiten:
Denn:
1. Sin(X)^2+Cos(X)^2=1
2. Die Größe eines Arrays fängt bei 0 an.

Code: [AUSKLAPPEN]
Function Schusswinkel#( PunktA[1], PunktB[1], GeschwA#, GeschwB#, WinkelB# )
   ; Komponenten berechnen
   Local Sx# = PunktB[0] -PunktA[0]
   Local Sy# = PunktB[1] -PunktA[1]
   Local Vx# = Cos( WinkelB ) *GeschwB
   Local Vy# = Sin( WinkelB ) *GeschwB
   ; Koeffizienten für die Quadr. Gleichung
   Local a# = GeschwB * GeschwB -GeschwA *GeschwA
   Local b# = 2 *Sx *Vx + 2 *Sy *Vy
   Local c# = Sx *Sx +Sy *Sy
   ; Diskriminante
   Local D# = b *b -4 *a *c
   
   ; Wenn keine Lösung existiert, -1 zurückgeben
   If D < 0 Then Return -1
   
   ; Zeitpunkte berechnen
   Local t1# = ( -b +Sqr(D) ) /( 2*a )
   Local t2# = ( -b -Sqr(D) ) /( 2*a )
   ; Zeitpunkt negativ -> keine Lösung
   If t1 < 0 And t2 < 0 Then Return -1
   ; günstigeren Zeitpunkt wählen
   Local t# = t1
   If t2 > 0 And t2 < t1
      t = t2
   ElseIf t1 < 0
      t = t2
   EndIf
   
   ; Koordinaten des Treffpunkts bez. Punkt A
   Local x# = Sx +Vx *t
   Local y# = Sy +Vy *t
   
   ; Winkel zurückgeben
   Return ( ATan2( y#, x# ) +360 ) Mod 360
End Function


mfG
mpmxyz

P.S.: Denke daran, die anderen Arrays auch zu ändern!
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer

Holzchopf

Meisterpacker

BeitragMo, Jun 22, 2009 17:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Mist, dass mit dem sin² +cos² ist mir glatt durch die Lappen gegangen Embarassed
Und wegen den Arrays: Ich vergess immer wieder, dass in BB beim Initialisieren ja ein Element mehr erstellt wird, als angegeben. In BMax ist's halt anders und ich arbeite in letzter Zeit fast nur noch mit BMax...

Naja die Funktion wäre bestimmt noch an anderen Stellen optimierbar... Aber s war halt schon spät gestern und irgendwann wurde ich dann doch ein bissl sehr müde.

mfG
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

mpmxyz

BeitragDi, Jun 23, 2009 14:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Moin moin,
ich habe mich jetzt mal an meinen Lösungsansatz gesetzt:

Code: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer BackBuffer()
Global TIMER = CreateTimer(60)

; (Start)position des Geschosses, resp des Schützens
Local P#[1], P0[1]
P0[0] = 200: P[0] = P0[0]
P0[1] = 200: P[1] = P0[1]
; Geschwindigkeit des Geschosses
Local vP# = 5
; Winkel des Geschosses
Local wP#

; (Start)position des Gegners
Local G#[1], G0[1]
G0[0] = 400: G[0] = G0[0]
G0[1] = 500: G[1] = G0[1]
; Geschwindigkeit des Gegners
Local vG#
; Winkel des Gegners
Local wG#

; Ob ein Schuss unterwegs ist
Local active = False

Local mh
While Not KeyDown(1)
   Cls
   mh = MouseHit(1)
   
   ; Schuss auslösen (Maustaste)
   If mh=1 And active=False
      ; Bewegung des Gegners richtung Maus
      Local dx = MouseX() -G0[0], dy = MouseY() -G0[1]
      wG = ATan2( dx,-dy )
      vG = Sqr( dx *dx +dy *dy ) *0.01
      ; Schusswinkel berechnen
      wP = BesteRichtung( P[0], P[1], 0, 0,G0[0] ,G0[1],+Sin(wG)*vG,-Cos(wG) *vG,vP )
      ; *voodoo* aktivieren
      If wP > -1 Then active = True
   ; Zurücksetzen
   ElseIf (mh=1 Or Sqr((P[0]-G[0])^2+(P[1]-G[1])^2)<5) And active=True
      ; Beides auf Startpunkt setzen
      P[0] = P0[0]
      P[1] = P0[1]
      G[0] = G0[0]
      G[1] = G0[1]
      ; *voodoo* deaktivieren
      active = False
   EndIf
   If active
      ; Schuss bewegen
      P[0] = P[0] +Sin(wP) *vP+0
      P[1] = P[1] -Cos(wP) *vP+0
      ; Gegner bewegen
      G[0] = G[0] +Sin(wG) *vG
      G[1] = G[1] -Cos(wG) *vG
   EndIf
   
   Oval P[0]-1, P[1]-1, 3,3
   Oval G[0]-3, G[1]-3, 7,7
   
   Flip 1
   WaitTimer( TIMER )
Wend

End




Function BesteRichtung#(VonX#,VonY#,VonXs#,VonYs#,ZuX#,ZuY#,ZuXs#,ZuYs#,Geschwindigkeit#)
   
   Local RelXs#=VonXs-ZuXs   ;Geschwingkeitsvektor relativ zum Ziel
   Local RelYs#=VonYs-ZuYs   ;
   
   ZuX= ZuX -VonX   ;Zu ist jetzt der Sollvektor
   ZuY= ZuY -VonY   ;Vom Schützen zum Ziel
   
   Local ZuSpd#=ZuX*ZuX+ZuY*ZuY   ;Normalisieren des Vektors
   ZuSpd#=Sqr(ZuSpd#)
   Local DX#=ZuX/ZuSpd
   Local DY#=ZuY/ZuSpd
   
   VonXs#=RelXs*DY#-RelYs*DX#      ;Der 2D-Raum wird so gedreht, dass der Sollvektor im BB-Koordinatensystem nach unten zeigt.
   VonYs#=RelYs*DY#+RelXs*DX#      ;"Von" ist jetzt der gedrehte relative Geschwindigkeitsvektor.
                           ;+Y ist in Sollrichtung
   
   If Geschwindigkeit#*Geschwindigkeit#<VonXs#*VonXs# Then Return -1   ;Ein zu großer Geschwindigkeitunterschied lässt sich nicht ausgleichen.
   
   Local SollL#=VonYs#+Sqr(Geschwindigkeit#*Geschwindigkeit#-VonXs*VonXs)
   ;Multipliziert mit dem Sollvektor gibt es die relative Geschossgeschwindigkeit an.
   ;Zeit=ZuSpd#/SollL#
   If SollL#<0 Then Return -1
   
   Local ErgX#=-RelXs#+SollL#*DX#   ;Vektor mit der Schussrichtung
   Local ErgY#=-RelYs#+SollL#*DY#   
   
   Return (360+ATan2(ErgX,-ErgY))Mod 360
End Function


Wenn die "Bälle" kollidieren, dann wird im Beispiel alles zurückgesetzt.

Prinzip:
Zuerst drehe ich den 2D-"Raum" so, dass das Ziel in BB unten und der Schütze oben auf (0|0) wäre.
Dann bestimme ich den in BB unteren Punkt, an dem sich der Kreis mit dem Radius der Schussgeschwindigkeit und die Verbindungslinie zwischen dem Schützen und Zielpunkt schneiden.
Die Schussrichtung geht dann von der Schützenposition plus seiner momentanen Geschwindigkeit bis zum eben bestimmten Punkt; dieser Vektor hat übrigens die Länge der Schussgeschwindigkeit.

Achtung:
Bei mir zeigt der Winkel 0 nach oben und geht dann im Uhrzeigersinn weiter!

mfG
mpmxyz

Edit: Man konnte vorher beim Code das Ziel dem Schützen ganz schnell entgegenschicken und es wurde die Lösung nicht angegeben. Angeblich sei das ganze dann laut der alten Funktion unmöglich.
Dieser Fehler ist jetzt behoben.
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

proggerkind

Betreff: Danke

BeitragMi, Jun 24, 2009 18:58
Antworten mit Zitat
Benutzer-Profile anzeigen
ok hab's jetzt implementiert, funktioniert soweit.
Danke für Eure Bemühungen! Very Happy

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group