Raumschiff an Position stoppen nur mittels Beschleunigung

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

 

Kruemelator

Betreff: Raumschiff an Position stoppen nur mittels Beschleunigung

BeitragMo, Okt 21, 2013 23:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Ein Raumschiff bewegt sich mit Schubdüsen, die können das Raumschiff in eine bestimmte Richtung beschleunigen. Dieses Raumschiff soll sich jetzt schnellst möglich an einen angegeben Position bewegen und dort zu Ruhe kommen.
Das müsste so gehen dass das Raumschiff solange beschleunigt bis zu einer Stelle kommt ab der es abbremsen muss um nicht über das Ziel hinaus zu fliegen. Um es einfach zu halten erstmal mit nur in einer Dimension.
Wie ermittel ich nur den Beschleunigungswert für den jeweiligen Schleifendurchgang?

Hier mal mit Beispielwerten:
BlitzBasic: [AUSKLAPPEN]
position = 0
schubplus = 0.003
schubminus = -0.001
ziel = 10
mov = 0
;schleife
mov = mov + ?????
position = position + mov

DAK

BeitragMo, Okt 21, 2013 23:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich bin gerade sehr müde, kann also völliger Blödsinn sein:

Verhältnis von Beschleunigung zu Abbremsentschleunigung: 3:1
Das heißt, das erste Viertel des Weges beschleunigst du, das letzte Viertel bremst du ab.

Habs mal ausprobiert, mit Long-Variablen und dafür großen Ganzzahlen (zwecks bester Genauigkeit) kommt diese Abschätzung bei mir bis auf 0.0008599% genau hin, also quasi so gut, wie man es kriegt.

Bei deinen Werten und Float-Variablen ist das ganze wenigstens noch 0.85% genau.
Gewinner der 6. und der 68. BlitzCodeCompo
 

Kruemelator

BeitragMo, Okt 21, 2013 23:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Mit festen Werten würde ich das auch hinbekommen, mein Problem liegt daran dass sich alles außer dem Schub ändern kann. Z.B. kann das Raumschiff schon mit einer Geschwindigkeit starten, außerdem ändert sich die der Wert von Position jeden Schleifendurchgang und ich kann lediglich den Abstand zum Ziel ermitteln.

Xeres

Moderator

BeitragMo, Okt 21, 2013 23:26
Antworten mit Zitat
Benutzer-Profile anzeigen
Ist ja auch logisch. Wenn man einen Körper beschleunigt hat, muss man ihn um genau den selben Betrag wieder abbremsen.
Wenn man von einer Maximalgeschwindigkeit ausgeht, kann man die nötige Zeit (=Schleifendurchgänge) über die Formel für gleichmäßig beschleunigte Bewegungen ausrechnen: v = a * t => t = v/a
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)

DAK

BeitragMo, Okt 21, 2013 23:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Ok, du kannst ja von dem hier ausgehen:

Code: [AUSKLAPPEN]
beschleunigung = b
geschwindigkeit = startgeschwindigkeit + t * b
entfernungzumziel = startentfernung  +  startgeschwindigkeit * t  +  t²/2 * b


Wenn du die Geschwindigkeit auf 0 setzt und nach t umformst, dann kriegst du raus, wie viel Zeit/Zyklen du brauchst um das Schiff zu stoppen.
Wenn du die Entfernung zum Ziel auf 0 setzt, und dann mittels der quadratischen Lösungsformel umformst, dann solltest du bekommen, wie weit vor dem Zeil du abbremsen musst. Sobald du auf diese Entfernung runtergekommen bist, musst du dann hald abbremsen.

Wie gesagt, sehr müde, kann auch voll falsch sein.
Gewinner der 6. und der 68. BlitzCodeCompo

Midimaster

BeitragDi, Okt 22, 2013 9:34
Antworten mit Zitat
Benutzer-Profile anzeigen
ich würde es über eine Simulation machen. Das würde in einem Raumschiffspiel auch Spaß bringen.

Zunächst einmal eine Begriffsklärung. Ein Raumschiff, das Du beschleunigst hält NIE wieder an! Also ist die Frage falsch, wie man beschleunigt um zu einer bestimmten Position zu kommen.

"Abbremsen" geht auch nicht. Nur "Beschleunigen" in eine andere Richtung,. z.B. Gegenrichtung. Bei fester Schubkraft beeinflusst nur ein Faktor den Zielpunkt: die aktuelle Geschwindigkeit.


Jeder Düsenstoß bringt als eine Zu- oder Abnahme der Geschwindigkeit. Nun muss man ja so lange einen Düsenstoß in die Gegenrichtung simulieren, bis die Geschwindigkeit wieder 0 ist. Das resultierende Ergebnis wäre dann die dabei zurückgelegte Strecke (Weg#). Das zieht der Navigator nun von der Ziel-Position ab, so kann er herausfinden, wo der richtige Zeit/Ort für das Starten der Aktion ist.

Im Raumschiff hat der Navigator also nur eine einzige Chance das Raumschiff an einer bestimmten Position zum stoppen zu bringen: Er muss zum richtigen Zeit/Ort die Aktion starten. Zeitpunkt und Distanz korrelieren dabei.


BlitzBasic: [AUSKLAPPEN]
Global Schub#=0.003

Function Bremsweg#(Speed#)
Local Weg#=0
Repeat
Speed=Speed - Schub
Weg=Weg+Speed
Until Speed<0
Return Weg
End Function



Eine "Automatik" würde nun das Ergebnis der Funktion Bremsweg#() mit der noch zurückzulegenden Distanz (Ziel#-Pos#) zum Ziel vergleichen und bei Bedarf ( wenn Bremsweg()< Distanz ) die Düsen kurz ausschalten oder vielleicht sogar die Bremsleistung einer zweiten Düse verwenden.

BlitzBasic: [AUSKLAPPEN]
 Global Speed#=10, AktPos#=100, Ziel#=520, Schub#=0.003
Repeat
AktPos=AktPos+Speed
Speed= Automatik (AktPos, Ziel, Speed)
Until...


Function Automatik (Pos#, Ziel#, Speed#)
Local Brems# = Bremsweg(Speed)
If Brems >(Ziel-Pos)*1.01
Speed=Speed -2*Schub
ElseIf Brems >(Ziel-Pos)
Speed=Speed - Schub
EndIf
Return Speed
Return
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe

DAK

BeitragDi, Okt 22, 2013 10:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Ähm.. Midimaster: Deine Lösung ist im Ansatz recht nett, aber ich verstehe nicht, warum du (selbst zum Zwecke einer Simulation) den Bremsweg mit der Schleife rechnen würdest. Das frisst nur unnötig Rechenleistung für etwas, was der Nutzer nie sieht. Stell dir vor, du hast da 100 Raumschiffe, die lange Strecken zurücklegen, und wo Bremsweg() pro Raumschiff mehrere 100 Mal pro Frame aufgerufen werden muss (z.B. 5 Sec Bremszeit bei 60 FPS -> 300 Schleifendurchläufe). Dann hast du hier glatte 30000 Schleifendurchläufe. Lässt sich viel einfacher über die Formel, die ich davor gepostet hab, direkt ausrechnen:

Code: [AUSKLAPPEN]
geschwindigkeit = startgeschwindigkeit + t * b
Nullsetzen und Umformen:
Code: [AUSKLAPPEN]
0 = startgeschwindigkeit + t * b
t *b = -startgeschwindigkeit
t = -startgeschwindigkeit/b

-> t Frames Bremszeit
Code: [AUSKLAPPEN]
entfernungzumziel = startentfernung  +  startgeschwindigkeit * t  +  t²/2 * b

t und b einsetzen: wenn entfernungzumziel = 0 (oder annähernd =0) anfangen zum Bremsen.

Habe ich nicht getestet, sollte aber so funktionieren.

b ist dabei die Bremsbeschleunigung.


Edit: Hier noch mal in Blitz ausprogrammiert:
BlitzBasic: [AUSKLAPPEN]
Global pos#=0.0
Global speed#=-0.00
Global length#=1000
Global acc#=0.003
Global dec#=-0.001

While (accTest())
Delay 10
Wend
WaitKey

Function accTest()
If (Abs(speed)<.001 And Abs(pos-length)<0.5)
Return False
EndIf
Local bremszeit = -speed/dec
Local bremsweg = speed*bremszeit + bremszeit*bremszeit*dec/2
Local bremswegtoleranz = speed*speed*1000
If (bremsweg<=length-pos-bremswegtoleranz) Then
speed = speed+acc
Else
speed = speed+dec
EndIf
pos = pos+speed
Print("Pos: "+pos+" Speed: "+speed)
Return True
End Function


Die Bremswegtoleranz ist notwendig, um Rechengenauigkeitsfehler auszugleichen, da einerseits Floats verwendet werden (die ja ohnehin nicht sehr genau sind) und andererseits ein eigentlich kontinuierlicher Prozess (Flug) in sequenzielle Happen zerlegt wird, und somit auch nicht alles genau abläuft. Mit der eingestellten Toleranz hat es für mich gut geklappt, spiel hald damit rum.

Wenn die Toleranz zu groß ist, dann stoppt das Raumschiff vor dem Ziel, wenn sie zu klein ist, dann pendelt das Schiff um das Ziel herum, statt darauf stehen zu bleiben.

Mit der eingestellten Toleranz schafft er es auf Wegen von 1 bis 100'000 ganz gut. (Bei 1 war er recht ungenau, ist auf 1.3 stehen geblieben. 1'000'000 hat er nur deswegen nicht mehr geschafft, weil die Floats nicht mehr genau genug waren, um bei dieser Distanz irgendwas sinnvolles zu machen)
Gewinner der 6. und der 68. BlitzCodeCompo

Midimaster

BeitragDi, Okt 22, 2013 20:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Deine Bremsberechnung hinkt... Wenn du ACC-und DEC-Aktionen im Wechselspiel erlaubst, wird jedes Raumschiff richtig anhalten, auch wenn die Formel nicht funktioniert. Weil ja bei einer "Fehl-Entwickung" einfach dagegengefeuert wird.

Wie wird Deine Restweg-Berechnung aussehen, wenn sie isoliert den korrekten Restweg ausrechnen muss?

Funktioniert Deine Formel auch, wenn Sie nur "bremsen" darf?

Also jetzt hab ich mal eine Testumgebung geschrieben, in der die Bremsformeln zeigen sollen, was Sie können:

BlitzBasic: [AUSKLAPPEN]
Graphics 800,600
SetBuffer BackBuffer()
FPS=CreateTimer(60)
SeedRnd MilliSecs()
Global X#, Ziel#, Speed#, Schub#

X=Rnd(10,50)
Ziel=Rnd(750,790)
Speed=Rnd(1 , 3.5)
Schub= 0.005

t$="Bremsweg gesamt = " + Bremsweg_MIDI#(Speed)

Repeat
Cls
Text 100,300,t
Rect X-2,100-2,5,5
Rect Ziel,0,1,600
X= X+ Speed
Automatik X, Ziel
Flip 0
WaitTimer FPS
Until KeyHit(1)



Function Automatik (Pos#, Ziel#)
Local Brems#
Brems = Bremsweg_MIDI(Speed)
;Brems = Bremsweg_DAK(Speed)
If Brems >(Ziel-Pos)*1.01
DebugLog "viel zu nah"

Speed=Speed - 2*Schub
ElseIf Brems >(Ziel-Pos)
DebugLog "zu nah"
Speed = Speed - Schub
EndIf
If Speed<0.01
Speed=0
EndIf
End Function


Function Bremsweg_MIDI#(TestSpeed#)
Local Weg#=0
Repeat
TestSpeed=TestSpeed - Schub
Weg=Weg+TestSpeed
Until TestSpeed<0
Return Weg
End Function


Start und Ziel und auch Speed werden durch Zufall ausgewählt. Bei einer Speed von unter 3.5 lässt sich das Raumschiff garantiert stoppen.
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
 

Kruemelator

BeitragDi, Okt 22, 2013 22:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Ideen mit der Entfernung zum Ziel und dem Bremsweg haben mich gut vorran gebracht.
In meinem Ansatz werden die benötigeten Bremsschritte und die Schritte zum ereichen des Ziels verglichen.

Es ist aber noch nicht zufriedenstellend, viele Raumschiffe bleiben am Zielpunkt stehen, manche fliegen aber wieder zurück.
Außerdem wechselt das Raumschiff häufig von Schub zu Gegenschub sobald es nah ans Ziel kommt.

Abgesehen davon sieht es schon so aus wie man es sich vorstellt.

Edit: Problem gefunden für das zurückfliegen(im Code korrigiert), dennoch wird immer noch von Schub zu Gegenschub gewechselt.

BlitzBasic: [AUSKLAPPEN]
Graphics 800,600,32,2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

Global raumschiffzahl = 19
Dim raumschiff#(raumschiffzahl,4)
;0 pos
;1 ziel
;2 speed
;3 schub
;4 gegenschub

For i=0 To raumschiffzahl
raumschiff#(i,0) = Rnd(0,100)
raumschiff#(i,1) = Rnd(600,800)
raumschiff#(i,2) = Rnd(0,1)
raumschiff#(i,3) = Rnd(0,0.03)
raumschiff#(i,4) = Rnd(0,0.03)
Next

timer = CreateTimer(60)
While Not KeyHit(1)
WaitTimer(timer)
Cls

For i=0 To raumschiffzahl
beschleunigung(i)
raumschiff#(i,0) = raumschiff#(i,0) + raumschiff#(i,2)
Next


;Malen
Color 255,255,255
For i=0 To raumschiffzahl
pos# = raumschiff#(i,0)
ziel# = raumschiff#(i,1)
Line ziel,100+i*20-5,ziel,100+i*20+5
Rect pos-1,100+i*20-1,3,3,1
Next


Text 10,10,speed
Flip 0
Wend
End

Function beschleunigung(i)
pos# = raumschiff#(i,0)
ziel# = raumschiff#(i,1)
speed# = raumschiff#(i,2)
schub# = raumschiff#(i,3)
gegenschub# = raumschiff#(i,4)

a# = 0;Beschleunigung
abstand# = ziel - pos
bremsschritte = Ceil(speed/gegenschub)
schrittezumziel = abstand/speed;angenommen speed wird nicht mehr geaendert
If bremsschritte >= schrittezumziel Then;Schub
a = -gegenschub
Else;Gegenschub
If abstand > 0.001 Then
a = schub
EndIf
EndIf
If Sgn(speed) <> Sgn(speed#+a) Then;begrenzt schub auf das noetige um speed auf 0 zu bekommen
a = -raumschiff#(i,2)
EndIf
;Speed aendern
raumschiff#(i,2) = raumschiff#(i,2) + a
End Function


Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group