![]() |
Geschwindigkeit bei bewegten Objekten
Hi,
Ich habe jetzt schon des öfteren kleine Spiele programmiert, aber ich hatte jedesmal Probleme wenn es darum ging verschiedene Geschwindigkeiten darzustellen. Jetzt habe ich wieder das Problem. Ich habe ein relativ simples Programm: Es gibt einen Ball, und diesem kann man mit einer bestimmten Kraft in eine beliebige Richtung "werfen". Mithilfe von Vektoren kann ich den Einfluss der Gravitation und des Windes beobachten. Soweit ist das kein Problem. Aber jetzt geht es darum einen Geschwindigkeits Faktor einzubauen. Hier hab ich jetzt einfach die Länge (oder den Betrag) des Vektors genommen, und ihn auf die Anzahl der Pixel übertragen, die sich der Ball in diesem Timer durchlauf bewegt. Funktionieren tut das ohne Frage, nur es gibt 2 Nachteile: 1. Es sieht doof aus ^^. Der Ball macht einfach zu große Sprünge (10-30 Pixel) 2. Kollisionsabfrage wird schwierig, da der Ball nicht genau auf Objekte trifft, sondern quasi direkt in sie hinein, da die Sprünge eben so groß sind. Eine andere Möglichkeit wäre, die Zeit zwisachen den Timer Aufrufen dynamisch an die Geschwindigkeit anzupassen. Aber hier gibt es dann schnell eine untere Grenze, und es ist stark von der Belastung des PC`s abhängig wie schnell sich der Ball bewegt. Hat vielleicht jemand eine Idee wie man soetwas elegant lösen könnte? Vielen Dank im vorraus ;) |
Re: Geschwindigkeit bei bewegten Objekten
Wo mit bewegst du denn das Objekt? Über einen einfachen Timer?
Ich denke du solltest einfach das Timer-Intervall erhöhen, so dass kleinere Bewegungen pro Intervall ausreichen. Ich habe für sowas immer das OnIdle benutzt; es wird so oft wie es dem Rechner möglich ist ausgeführt. Dann kannst du die Koordinaten des Objektes in kleinen Schritten vergrößern oder verkleinern und das ganze sollte flüßig laufen. Also statt OnTimer (oder was auch immer du verwendet hast):
Delphi-Quellcode:
in das OnCreate und dann den zu wiederholenden Code in eine Methode mit Namen 'procedure1'.
Application.OnIdle := procedure1;
Auf DelphiGL.com gibt es einen Bomberman Tutorial, dort steht etwas über 'Timebased Movement', dass du dir mal durchlesen solltest. Der Nachteil vom OnIdle ist nämlich, dass es von der Rechenleistung abhängt, wie oft es ausgeführt wird und das Programm dann auf schnellen Rechner möglicherweise zu schnell ausgeführt wird. Dort ist beschrieben, wie du das umgehen kannst. |
Re: Geschwindigkeit bei bewegten Objekten
Hi!
Ich würde das timer-Intervall nicht ändern, sondern immer bei 13 ms lassen (ca. 75 Hz). Dann kann man große Sprünge auch nicht wahrnehmen, wenn es sie denn geben sollte. Zur Kollisionsabfrage: Deine OnTimer-Procedure sieht wahrscheinlich ungefähr so aus:
Delphi-Quellcode:
wobei der Vektor dann die die Geschwindigkeit ist. Dabei fliegt der Ball aber, wie bereits von dir erwähnt evtl. direkt ins Objekt hinein. Mach's doch stattdessen so:
Ball.Left := Ball.Left + Vektor;
Kollisionsabfrage;
Delphi-Quellcode:
Dann fliegt der Ball nämlich nur so lange, bis es eine Kollision gibt.
For i := 1 to Vektor do begin
Ball.Left := Ball Left + 1; Kollisionsabfrage; If Kollision then Break; end; |
Re: Geschwindigkeit bei bewegten Objekten
danke euch beiden. Dieses Time Based Movement habe ich mir mal angeschaut. Scheint vielversprechend. Auch das OnIdle Event kannte ich noch nicht. Danke :)
Zur Kollisionsabfrage: gute Idee. Ich denke mal so wirds klappen, danke :) |
Re: Geschwindigkeit bei bewegten Objekten
Hallo Antigo
Welchen Typ haben deine Vektorenelemtene? Ganzzahl? Dann war das die falsche Wahl. Wenn du Gleitkommazahlen fuer die Vektoren nimmst, dann sollte es eigentlich keine Schwierigkeiten bezueglich Genauigkeiten geben. Was die Kollisionserkennung betrifft: Ich wuerde in folgender Reihenfolge vorgehen:
greetz Mike |
Re: Geschwindigkeit bei bewegten Objekten
Ähm meine Vektorelemente sind in der Tat Integer. Und es funktioniert auch nicht so wie es soll, da er durch Rundungen so wie es aussieht einfach immer einen Pixel vorgeht. Jedenfalls ist es so, das der Ball sich anders verhält wenn ich das Timer Interval ändere, und genau das sollte beim Timebased Movement ja nicht der Fall sein.
Optimal wäre es wohl wenn ich die komplette Flugbahn des Balles schon kennen würde und dann beim Timer durchlauf nur gucken müsste in welchem Zeitindex ich mich befinde und die dazugehörige Position raussuchen würde. Dann würde das Timer Intervall wirklich keinen EInfluss mehr haben, und es sollte auch nicht mehr ruckeln, aber ich weiss nicht wie ich das bewerkstelligen sollte... Zurück zum vektor :D inwiefern würden Gleitkommazahlen da helfen? Zur Kollisionsabfrage: DIe Möglichkeit, wäre quasi andersrum. Ist vielleicht ressourcenschonender, weil man nicht immer in Einzelschritten vorgeht. Naja mal sehen, erstmal muss der Ball vernünftig fliegen ;) Vielen dank schonmal :) |
Re: Geschwindigkeit bei bewegten Objekten
Zitat:
![]() Zitat:
Bei der Verwendung von Floats wuerde es nach 1 Sekunde an der richtigen Stelle befinden, naemlich 5 Pixel weiter ;) greetz Mike |
Re: Geschwindigkeit bei bewegten Objekten
Zitat:
Zitat:
danke nochmal |
Re: Geschwindigkeit bei bewegten Objekten
ok es kann gar nicht funktionieren mit diesem Time Based Movement :/
Ich habe es so geregelt, dass bei jedem mal, wenn der Ball bewegt wird, seine Flugbahn direkt mit der Gravitation und dem Wind verrechnet wird:
Delphi-Quellcode:
Jetzt ist es natürlich so, dass die Flugbahn anders verläuft, wenn der Vektor des Balles öfters mit den beiden anderen verrechnet wird. Deshalb ist es immer noch so das der Ball bei Timer Intervall 1 anders fliegt als bei Timer Intervall 50 :(
var
Gravitation,Wind:TVektor; Ball: TBall; ... ... procedure TForm1.Timer1Timer(Sender: TObject); ... Ball.vektor.addieren(Gravitation); Ball.vektor.addieren(wind); ... //Time Based Movement time:=gettickcount()-timestamp; ball.bewegen((5*ball.vektor.gibLaenge/10)*time/1000); Vielleicht hat ja jemand einen Ansatz wie man das lösen kann. Ich hab schon an sowas gedacht:
Delphi-Quellcode:
Also das nur bei jedem vollen Pixel die Flugbahn verändert wird, aber das haut auch nicht hin. Denn bei Timer Intervall 50 können ja auch mehrere Pixel gegangen worden sein, und trotzdem nur eine einzige Flugbahn anpasung vorgenommen worden sein.
if ball.x mod 1 = 0 then begin
Ball.vektor.addieren(Gravitation); Ball.vektor.addieren(wind); end; Ich hoffe da blickt jetzt noch jemand durch ;) |
Re: Geschwindigkeit bei bewegten Objekten
Zitat:
Code:
sondern es muss auch der Wind noch miteinbezogen werden:
v0 * t * cos(b)
Code:
wobei vw der Vektor des Windes ist und c ein Faktor, mit dem die Kraft des Windes an dem Objekt wirkt. (Siehe dazu
xy(t) = v0 * t * cos(b) + vw * t * c
= t * (v0 * cos(b) + vw * c) ![]() Zitat:
Zitat:
Code:
So sieht das aus im Vergleich, wenn du einmal Position und Pixel als Integer speicherst, und einmal, wenn du Position als floats und Pixel als integers speicherst.
Schritt Position/Pixel (float) Position/Pixel (int)
1 0 / 0 0 / 0 (+0.25) 2 0.25 / 0 0 / 0 (+0.25) 3 0.50 / 0 0 / 0 (+0.25) .... 6 1.25 / 1 0 / 0 (+0.25) 7 1.50 / 1 0 / 0 (+0.25) .... 9 2.00 / 2 0 / 0 (+0.25) 10 2.25 / 2 0 / 0 (+0.25) ect. Zitat:
Delphi-Quellcode:
dt ist die wichtige Variable. Diese gibt dir in Millisekunden an, wieviel Zeit seit dem letzten Tick vergangen ist. Wie du sie anwendest: hier mal ein kleines Beispiel:
var
LastTick: Integer; //... procedure TForm1.OnTimer(Sender: TObject); var CurrentTick, dt: Integer; begin CurrentTick := GetTickCount(); dt := CurrentTick - LastTick; //dt = Delta T, die Zeitdifferenz zwischen dem letzten Tick und dem derzeitigen //hier dann dein Verarbeitungscode LastTick := CurrentTick; end;
Delphi-Quellcode:
Damit sollte das Timebased Movement korrekt implementiert sein.
procedure PhysicTick(dt: real); //dt, aber in Sekunden! (angenehmer fuer physische Berechnungen)
var Speed, Position: TVektor; //Geschwindigkeits- und Positionsvektoren begin Position := Position + (Speed * dt); end; procedure OnTimer(...) begin //hier dann dein Verarbeitungscode PhysicTick(dt / 1000); //division durch tausend, um von Millisekunden auf Sekunden umzurechnen. end; Code is allerdings im Kopf entstanden, also koennten kleinere Fehlerchen dabeisein ;) greetz Mike |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:30 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz