Autor Beitrag
F34r0fTh3D4rk
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Mo 15.05.06 19:17 
ok mein 10.000 ball topic

der ball verliert nach und nach an höhe, als hätte er reibung, ich kann mir beim besten willen nicht erklären warum (der code ist recht kompliziert gehalten, ich wollte überprüfen, wer schuld ist, mensch oder maschine ;) )

hier der source: unmuted-music.de/ball.zip


so langsam versteh ich die welt nicht mehr ;)

mfg
Fabian W.
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1766

Win 7
D7 PE
BeitragVerfasst: Mo 15.05.06 19:30 
Ich hab den Code nur überflogen, aber wenn der Ball den Rand verlässt rufst du doch Ball.StepBackward; auf, und dabei setzt du wenn ichs richtig gesehen habe die vektoren immer ein stückweit zurück position.x := position.x - velocity.x * timestep;Diese Änderung der Vektoren wirk sich nunmal auf die Geschwindigkeit aus.


mfg

//EDit kompletter quatsch was ich da plappere, das sind ja garkeine Vektoren... sry, ich schaus mir später an, aber im Moment bin ich vom ZK-lernen verwirrt... :oops:
Tilo
ontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1098
Erhaltene Danke: 13

Win7 geg. WInXP oder sogar Win98
Rad2007
BeitragVerfasst: Di 16.05.06 06:51 
Hallo user profile iconF34r0fTh3D4rk
Das Problem war das Du den Weg zwar zeitrelativ gemacht hast, aber nicht die Gravitation.

Ändere mal die Proceduren StepForward und StepBackward so ab:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TBall.StepForward;
var
  timestep: double;
begin
//Zeitschritt berechnen;
  timestep := TBTimer.compute;
//Gravitation der vetikalen Geschwindigkeit hinzufügen
  velocity.y := velocity.y + g * timestep;
//Die neuen Positionen berechnen (timestep für timebased movement)
  position.x := position.x + velocity.x * timestep;
  position.y := position.y + velocity.y * timestep;
end;

procedure TBall.StepBackward;
var
  timestep: double;
begin
  timestep := TBTimer.compute;
  velocity.y := velocity.y - g * timestep;
  position.x := position.x - velocity.x * timestep;
  position.y := position.y - velocity.y * timestep;
end;



//zusatz:
Bringt leider nur den Effekt das der Ball langsamer fällt ung der "Energieverlust" geringer ist.

//Edit.
Ein weiterer Fehler ist das es sich hier um eine beschleunigte Bewegung handelt.
daraus ergibt sich die Formel:
ausblenden Quelltext
1:
ds=a*a/2					

Muss jetzt Schluss machen.
Vielleicht habe ich heute nachmittag mehr Zeit.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 16.05.06 07:24 
Wieso nimmt die Geschwindigkeit bei 'StepBackward' ab? Nimm das weg und es klappt. Deine Geschwindigkeitsabnahme ist doch im StepForward drin (bei negativer Velocity).

Die Geschwindigkeit ändert sich aber auch, wie Tilo schon meint, zeitabhängig. ich habe es mit g*timestep*10 versucht und das sah ganz nett aus.

Besser wäre es noch, die Reflexion noch genauer zu gestalten, also nicht das der Ball unten halb verschwindet, sondern bis maximal (Y=Height-Radius) geht.

_________________
Na denn, dann. Bis dann, denn.
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 12:57 
Hi F34r0fTh3D4rk

Grundsätzlich gleiches Problem wie HIER www.delphi-forum.de/...mp;highlight=gravity

Du berechnest die Simulation in dedizierten Zeitabschnitten. Dabei wirst du den exakten Zeitpunkt der Kollision nicht erwischen. Durch deine Schleifenbedingnung "Ball.position.y + Ball.radius <= IMG_Draw.Height;" brichst du ab, wenn der nächste Durchlauf über die Bande gehen würde.
Ergo verlierst du bei jeder Kollision ein Höhenpotential zwischen 0 - Radius. Ergo wird dein Ball immer niedriger hüpfen.

Lösung: Berechne die Kollision dediziert und exakt.

MfG Simon
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 16.05.06 12:58 
das problem ist ja, dass wenn der ball über die kante hinausgeht jan hängen bleiben kann, ich kann natürlich auch die richtung abfragen, aber auf die dauer bringt das glaube ich auch nichts, ich glaube der fehler liegt wirklich bei der beschleunigung

// dort ist das gleiche problem, aber wie die dedizierte lösung funktioniert steht da nicht
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 13:13 
Ich bin davon ausgegangen, das du das schon drin hast.
-> "velocity.y := velocity.y + g * timestep;"

den der Fehler ist ja klar!

wenn du mit Geschwindigkeiten rechnest, solltest du auch Geschwindigkeiten addieren/subtrahieren. :wink:

m/s = m/s + m/s² ? Nö oder? m/s = m/s + m/s² * s ist deutlich besser.

Das ändert aber nichts an dem inhärenten Fehler in der Simulationsberechnung (siehe Oben).

MfG
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 16.05.06 13:19 
wie mache ich das denn am besten, von mir aus fang ich nochmal neu an, das soll ja möglichst accurate (mir fällt das deutsche wort grad net ein) sein, denn es soll ja nicht bei einem ball bleiben und reibung lass ich erstmal außen vor. die masse sollte da aber noch rein
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 13:52 
Auf die Schnelle

Position:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure TMainForm.T_DrawTimer(Sender: TObject);
begin
  if Ball.position.y + Ball.radius > IMG_Draw.Height then
  begin
    repeat
      Ball.StepBackward;
    until
      Ball.position.y + Ball.radius <= IMG_Draw.Height;
    //Ball.velocity.y := - Ball.velocity.y;  
    -> Ansatt einfach die Geschwindigkeit zu invertieren sollte hier gnau berechnet werden wann die Kollision sattfindet, welche Geschwindigkeit der Ball dabei hat, Welche Geschwindigkeit und Position der Ball zum Eventzeitpunkt hat
  end;
  if Ball.position.y + Ball.radius = IMG_Draw.Height then
    Ball.velocity.y := - Ball.velocity.y;
  Ball.StepForward;
  IMG_Draw.canvas.Rectangle(0, 0, IMG_Draw.Width, IMG_Draw.Height);
  DrawBall;
end;


Vorgehen:
Was habe ich?
Zeit t1 - Letzte Berechnung
Position X1 - Letzte Berechnung
Position b - Boden
Zeit t2 - Jetzige Berechnung

Irgentwo zwischen t1 und t2 knallt der Ball auf den Boden.

Berechnung von Irgentwo:

Bei t1 hat der Ball noch die Höhe s = x1-b. Das ist der Weg den der Ball noch zurücklegen wird.
Mit der Formal
s = a/2 * t² + v0 * t + s0 | v0 Geschwindigkeit bei t1; s0 = x1
kannst du t berechnen.
Damit kannst du exakt die Geschwindig bei der Kollision berechnen. Diese invertieren. Und abschliesend StepForward mit der Zeit t2-t berechnen.

Viel Spass bei der Umsetzung. :-)

PS: Die Position für v = 0 sollte analog berechnet werden.


Zuletzt bearbeitet von Simon Joker am Di 16.05.06 13:56, insgesamt 1-mal bearbeitet
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 16.05.06 13:55 
also liegt der fehler bei der kollision ?
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 13:59 
Ja und bei dem was Tilo moniert hat. Wobei das mit Geschwindigkeit + Beschleunigung der bösere Fehler ist, weil das nicht nur eine Rundungsungenauigkeit ist sonder ein echter mathematischer Fehler, der von einem Physiklehrer mit "Fünf. Setzen!" kommentiert würde. :twisted:
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 16.05.06 14:15 
vielleicht bringt ihr mir ein wenig licht in die sache, das wäre einfacher ^^ etwas zu einem bestimmten zeitpunkt berechnen usw ist ja kein ding, aber die zeit ist ja unbekannt, das ganze wird ja simuliert Oo
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 15:02 
Ich hatte schon angedeutet. :-)

Das ist die Formel die du braucht um den Zeitpunkt der Kollision zuberechnen.

s = a/2 * t² + v0 * t + s0

s -> verbleibende Höhe des Balls nach letzter Berechnung
a -> Erdbeschleunigung oder was auch immer
t -> Zeit die benötigt wird um die verbleibende Höhe zufallen DAS SUCHST DU!
v0 -> Geschwindigkeit nach letzer Berechnung
s0 -> Position nach letzer Berechnung

1. Gleichung lösen (Lösung Quatratische Gleichung - siehe Tafelwerk)
2. Zeitpunk der Kollision tk ergibts sich aus t1 + t mit t1 = Zeit letzter Berechnung
3. mit tk kannst du die Geschwindigkeit bei Kollision Vk berechnen
4. Vk invertieren
5. Position für Zeit der neuen Berechnung berechnen

Auslösen mußt due die Berechnung, wenn der Ball mit der nächsten Berechnung sicher über die Begrenzung (Boden) kommt. Das wäre bei dir die Abbruchbedingung deiner Repeat-Schleife.

MfG
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 16.05.06 15:06 
ich versteh im moment nicht mal mehr die beschleunigung, also das hier:
ausblenden Delphi-Quelltext
1:
  v := v + g {* tf};					


ist falsch, wie muss es dann heißen ?
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 15:22 
V(t) = a * t ist die verkürtzte Schreibweise! Nur gültig wenn V0 = 0 also beginnend bei Stillstand

Korrekt ist

V(t) = V0 + a * t

wobei halt V0 die Anfangsgeschwindigkeit ist.
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Di 16.05.06 17:40 
und das t wäre dann delta t oder wie ? wozu brauch ich das, denn in der simulation wird t ja nicht benötigt.

mit nem timer mit 50 ticks, habe ich ja eine 20stel sekunde, das muss ich dann noch einbeziehen oder ? vielleicht kann mir jemand ein musterbeispiel zeigen, sonst check ich das wohl nie ^^ (man schaue sich meine ganzen anderen topics dazu an, ich mach seit nem jahr fast nichts anderes und jedes mal verzweifle ich daran :( )
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Di 16.05.06 20:13 
Ja t ist dt, oder in deinem Beispiel timestep. Das ist so schon Ok. Du Berechnest ja die Veränderungen seit der letzten Berechnung, und dafür mußt du die Zeit verwenden, die seit dem vergangen ist.

Zitat:

... wozu brauch ich das, denn in der simulation wird t ja nicht benötigt. ...

Das ist Unsinn. Du verwendest sie ja schon und sie geht in jeder deiner Berechnungen ein. Du gibst sie nur nicht aus.

1.
Du hast einen elementaren Fehler begangen, denn hat Tilo im 3. oder 4. Post korrigiert. Das war einfach ne falsche Formel.

2.
Der zweite Fehler steckt sozusagen im System und tritt bei allen Simulationenen auf die einzelne Zustände berechnen. Für zeitliche Verläufe ist das noch am einfachsten zu verstehen.

Nehmen wir als Beispiel eine einfache lineare Bewegung. Sie lässt sich mit der Formel

s = V * t

beschreiben.
Berechnet oder mißt man jetzt jede Sekunde s hat man in 10 Sekunden 10 wunderschöne einzelne Werte. Stellt man sie dar ergibt sich eine bildschöner linearer Verlauf, anhand dessen wir uns nun erlauben Aussagen über den Zustand zwischen den Messpunkte zumachen. Und das ist genau das Problem, denn es ist ist FALSCH!! Diese so zuversichtlich geäußerte Voraussage trifft nur zu, wenn V konstant ist. Wenn diese Bedingung durch irgendetwas nicht erfüllt wird ist die Simulation nicht zutreffend.
Nehmen wir ein einfaches Beispiel. Du fährst mit dem Auto zur Arbeit und misst die Zeit beim Start und bei der Ankunft. Das Ergebniss ist eine Geschwindigkeit, die deine Fahr korrekt beschreibt. ABER sie sagt nichts über den Verlauf der Fahrt aus, ob du an Ampeln gestanden hast ect. wird nicht erfasst.
Durch Erhöhung der Messpunkte kann die Genauigkeit verbessert werden, aber grundsätzlich bleibt das Problem bestehen.

Keine gequantelte Messung/Berechnung kann einen stetigen Verlauf korrekt beschreiben, sondern sie bleibt immer einen Näherung.

So nun zu deinem Beispiel "Fallbeschleunigung". Die Formeln sind klar

V = V0 + a * t
s = a/2*t² + V0 * t + s0

Die Berechnungen erfolgen zu beliebigen Zeitpunkten und ergeben eigentlich einen schönen Verlauf.
Pseudo Code:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
a := -9.81;
repeat
  T[x] := GetTime;
  //Mit vollständiger Zeit und  V0 = 0 und s0 = 0
  V[x] := a * T[x];
  s[x] := a / SQR(T[x]); 
  //oder mit Delta t
  V[x] := V[x-1] + a * (T[x] - T[x-1]);
  s[x] := a / SQR(T[x] - T[x-1]) + V[x-1] * (T[x] - T[x-1]) + s[x-1];
  //Hier auf Kollision prüfen
  if s[x] < BodenHoehe then begin
  
  end;  
  inc(x);
until CancelParam;


Die Störung im System ist nun die Kollision mit dem Boden. Diese wird irgendwann zwischen T[x-1] und T[x] stattfinden. Für eine Korrektur muß dieser Zeitpunkt (nennen wir ihn T[k]) genau berechnet werden. Also sozusagen eine Zwischenberechnung eingeschoben werden, die die Zustände zwischen unseren normalen Messpunkten bestimmt, damit wir darüber eine Aussage treffen können.
Wie das geht habe ich oben schon beschrieben.

MfG Simon

Edit: Korrektur der Formel


Zuletzt bearbeitet von Simon Joker am Mi 17.05.06 13:30, insgesamt 1-mal bearbeitet
Tilo
ontopic starontopic starontopic starontopic starofftopic starofftopic starofftopic starofftopic star
Beiträge: 1098
Erhaltene Danke: 13

Win7 geg. WInXP oder sogar Win98
Rad2007
BeitragVerfasst: Mi 17.05.06 10:19 
Hallo,
Ich habe mal den Code etwas umgestellt und auf das wesentliche reduziert:
Damit man es physikalisch richtig betrachten kann:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TMainForm.DrawBall;
begin
//Ball aufs Image zeichnen
  IMG_Draw.canvas.Ellipse(IMG_Draw.width div 2-round(Ball.radius),
                          IMG_Draw.Height-round(Ball.position.y - Ball.radius),
                          IMG_Draw.width div 2+round(Ball.radius),
                          IMG_Draw.Height-round(Ball.position.y + Ball.radius));

end;


desweiteren das hier:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TMainForm.T_DrawTimer(Sender: TObject);
begin
  Ball.NextStep;
  IMG_Draw.canvas.Rectangle(0, 0, IMG_Draw.Width, IMG_Draw.Height);
  DrawBall;
end;


Und die NextStepProcedure:
ausblenden volle Höhe Delphi-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:
procedure TBall.NextStep;
var
timestep: double;
timek,times:double;
newVY:double;
newY:double;
va:double;
begin
//Zeitschritt berechnen;
 timestep:=1;
 //X-Koordinate wird nicht benötigt

 //Y-Koordinate
 newY:=position.y+velocity.y*timestep-g*timestep*timestep/2;
 if newY<=radius then
 begin//Kollision
  //timek, Zeit bis Kollision
  timek:=-(velocity.y/g)-sqrt((velocity.y*velocity.y)/(g*g)-2*position.y/g);
  //Aufschlagsgeschwindigkeit
  va:=velocity.y-g*timek;
  //times Aufstiegszeit
  times:=timestep-timek;
  //neue Position
  position.y:=radius-va*times-g*times*times/2;
  //neue Geschwindigkeit;
  velocity.y:=-va-g*times;
 end
 else
 begin//keine Kollision
  position.y:=newY;
  velocity.y:=velocity.y-g*timestep;
 end;
end;


TimeStep habe ich auf 1 Sekunde gesetzt damit man das Problem erkennt:
in der markierten Zeile kommt als erste Zeit ein Wert von timek=1,2763256101 raus.
Der Fehler liegt also in der BErechnung der Kollisionszeit. Ich finde den Fehler aber nicht. Soweit ich es sehe ist die Formel physikalisch korrekt.
Simon Joker
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 236
Erhaltene Danke: 1



BeitragVerfasst: Mi 17.05.06 13:29 
Hi Tilo

Du hast einen Fehler bei der Normierung gemacht. s ist nicht gleich Null, wenn man nur mit den Koordinaten des Balles rechnet, sondern s = radius.
Damit ergibt sich das hier:

ausblenden volle Höhe Delphi-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:
procedure TBall.NextStep;
var
timestep: double;
timek,times:double;
newVY:double;
newY:double;
va:double;
p, q : single;
begin
//Zeitschritt berechnen;
 timestep := 0.2;
 //X-Koordinate wird nicht benötigt
 //Y-Koordinate
 newY:= position.y + velocity.y*timestep + g/2*timestep*timestep;
 if newY <= radius then
 begin//Kollision
  //timek, Zeit bis Kollision
  p := velocity.y/g;
  q := 2*(position.y-radius)/g;
  timek := -p + sqrt( p*p - q);
  //Aufschlagsgeschwindigkeit
  va:= velocity.y + g*timek;
  //times Aufstiegszeit
  times := timestep-timek;
  //Geschwindigkeit invertieren
  velocity.y := -va ;
  //neue Position
  position.y := radius;
  position.y := position.y + velocity.y*times + g/2*times*times;
  //neue Geschwindigkeit;
  velocity.y := velocity.y + g*times;
 end
 else
 begin//keine Kollision
  position.y := newY;
  velocity.y := velocity.y + g*timestep;
 end;
end;


Man beachte: Wenn V in die Höhe positiv ist, ist die Fallbeschleunigung negativ, also g = -9.81; Meine Korrektur erfordert die negative Fallbeschleunigung.

MfG Simon
F34r0fTh3D4rk Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 5285
Erhaltene Danke: 28

Win Vista (32), Win 7 (64)
Eclipse, SciTE, Lazarus
BeitragVerfasst: Mi 17.05.06 17:22 
ich glaube jetzt habe ichs verstanden:

/\t ist der die Zeit zwischen v0 und v1 bzw s0 und s1.
da immer in sekunden gerechnet wird, kann ich dort also mein timerinterval / 1000
nehmen, dann habe ich ja die interpolation der zeit.
und dieses /\ brauch ich auch, wenn ich die zeit der kollision berechnen will, bzw das ist dann ja ein neues.

ich werde das gleich mal alles ausprobieren ;)
ich kann ne menge über schwingungen und wellen erzählen, aber mechanik ist zu lange her, da hatten wir in mathematik noch nicht einmal vektorrechnung ;)

die timek zeile mag er nicht, ungültige gleichkomma operation Oo
ausblenden Delphi-Quelltext
1:
timek := -(-p + sqrt(-(p * p - q)));					

geht auch net, es liegt an der negativen zahl unter der wurzel, so gehts:
ausblenden Delphi-Quelltext
1:
timek := -(-p + sqrt(abs(p * p - q)));					


irgendwas stimmt da aber noch nicht, die geschwindigkeit ist ja nach unten hin positiv und die kollision erfolgt ja bei image1.height - radius oder position.y + radius >= image1.height, aber dann klappt das net so wirklich