Hallo.
Ich versuche mit GDI+ die Bewegung eines Objektes zu realisieren. Dazu lasse ich, wie in diesem Thread geschildert, ein Objekt von einem Punkt zum anderen wandern. Zuerst wollte ich das so lösen, dass die Bilder nach einer vorgegebenen Zeit aktualisiert werden. Dazu habe ich anfangs mit 30 Aktualisierungen pro Sekunde gearbeitet (30 Bilder/Sekunde = 30 FPS).
Allerdings ist ein merkwürdiger Fehler aufgetreten: Das Objekt "springt" plötzlich, obwohl es sich geradeaus bewegen soll. Als ich die feste FPS-Rate auf 100 erhöht habe, trat dieser "Sprung" früher auf, als ich sie gesenkt habe, trat er früher oder gar nicht auf.
Auf dem Bildschirm wird zudem eine Zeitanzeige angezeigt, die auf die erste Nachkommastelle genau immer die Zeit seit Programmstart anzeigen soll. (Auf erste Nachkommastelle genau heißt also, dass sie zumindest alle 1/10 Sekunden aktualisiert werden soll). Aber schon bei 10 FPS tritt dieser Fehler auf.
Mein Verdacht ist also, dass durch die festgegebene Frequenz das Programm mit den vielen Berechnungen pro Sekunde nicht ganz fertig wird, und so die Berechnungen verfälscht werden (die Zeit fließt in die Berechnung mit ein). Ist dieser Verdacht berechtigt? Wenn ja, müsste ich es anders realisieren. Aber wie halte ich dann die Uhrzeit aktuell?
Danke im Voraus,
euer verzweifelter Jack
-> Informatik-Infotainment <-
Hallo Jack_AI,
also wenn ich eine Feste Framerate haben möchte mache ich es beispielsweise so:* Du weisst dass Du angenommen 25 Frames pro Sekunde haben möchtest. D.h. Du musst alle 40 ms einen Frame darstellen.
Obiges ist nur sehr vereinfacht dargestellt aber ich glaube es zeigt den Weg wo es hingehen soll.
Falls Du in einen Backbuffer zeichnest musst Du natürlich auch noch die Zeit miteinkalkulieren die benötigt wird um den veränderten Ausschnitt auf den Schirm zu zaubern (Invalidate)
Grüsse,
Egon
egrath's Blog: http://egonrath.eg.funpic.de/wordpress
Das ist gar nicht mein Problem.
Ich stelle meine Frage noch einmal anders:
Was passiert denn, wenn das Programm für die Berechnungen länger braucht, als den Bruchteil einer Sekunde, den ich dem Programm zur Verfügung stelle? Ich sage dem Programm ja, "Hey, Programm! Berechne das Ganze in 40ms noch mal neu!" - "Und wenn ich das in der Zeit nicht schaffe, mein Gebieter?" - "Dann... dann..." Ja, was dann?
-> Informatik-Infotainment <-
Hrm,
ich würde das ganze erst einmal in einen Probeprojekt abhandeln indem ich erstmal keinerlei Berechnungen anstelle sondern nur ein Grafisches- Objekt gerade bewegen lasse indem x erhöhst. Anschließen würde ich die Formel nach für nach implementieren bis die Stelle gefunden hast in der mehr Zeit als 40ms verbrauchst.
Normal sollte die Berechnung von deinen vorangegangenen Thread nicht wirklich belastent sein. So das ich eher andere Fehlerquellen vermute - nur dazu brauche ich die Zeichenroutine von dir + Aufruf als Code zum sichten.
Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(
Normal sollte die Berechnung von deinen vorangegangenen Thread nicht wirklich belastent sein. So das ich eher andere Fehlerquellen vermute - nur dazu brauche ich die Zeichenroutine von dir + Aufruf als Code zum sichten.
Ich weiß nicht, ob dir das wirklich helfen wird. Ich poste das hier einfach mal. Hoffnung habe ich nicht wirklich.
Konstruktor:
public Form1()
{
InitializeComponent();
...
// EventHandler
pn_Flaeche.Paint += new PaintEventHandler(pn_Flaeche_Paint);
// Timer
RefreshTimer = new Timer();
RefreshTimer.Interval = Convert.ToInt32((1 / (double)ClassGlobal.FPS) * 1000); // FPS = 30
RefreshTimer.Tick += new EventHandler(RefreshTimer_Tick);
}
// Timer-Ticks
void RefreshTimer_Tick(object sender, EventArgs e)
{
ClassGlobal.Time++;
pn_Flaeche.Invalidate();
}
Zeichen-Routine:
void pn_Flaeche_Paint(object sender, PaintEventArgs e)
{
if (ClassGlobal.ProgramStarted)
{
if (Objektliste.Count > 0)
{
foreach (ClassObject Objekt in Objektliste)
{
// Hinweis: Problem tritt schon bei nur einem Objekt auf
Objekt.DoYourJob(e.Graphics); // Objekt wird gezeichnet und Bewegung wird berechnet
}
}
// Zeit anzeigen
e.Graphics.DrawString(Math.Round(ClassGlobal.SITime(), 1).ToString(), new Font("Times New Roman", 12, FontStyle.Regular),
Brushes.Black, new PointF(ClassGlobal.Bildbreite - 50, ClassGlobal.Bildhoehe - 30));
}
}
Was mir aufgefallen ist: Wenn sich das Objekt nur auf der X- oder Y-Achse bewegt, tritt dieser Effekt nicht. Für "schräge" Bewegungen werden mehr Berechnungen gebraucht. Daher vermute ich, dass entweder die komplexeren Rechungen einen Fehler enthalten (was ich eigentlich ausschließe), oder diese Berechnungen zu viel Zeit brauchen.
-> Informatik-Infotainment <-
Hallo,
abgesehen davon dass ich die gesamte Zeichenroutine anders gestalten würde sehe ich kein gravierendes Problem in deinem Code (würde in einen Puffer zeichnen und für jeden Frame nur die Veränderten Ausschnitte zeichnen)
Um einmal auszuschliessen dass deine Berechnungsroutinen zu lange brauchen: Lasse bei jeder Berechnung eine StopWatch mitlaufen und schreib das ganze in ein File. Wenn Du einen Profiler hast dann benutz den mal.
Wenn das nicht das Problem sein sollte würde ich so vorgehen:
(Obiges Beispiel sollte mit einem Backbuffer durchgeführt werden)
Grüsse,
Egon
egrath's Blog: http://egonrath.eg.funpic.de/wordpress
Hrm, okay ich denke an der stelle verlierst du keine Performance.
if (Objektliste.Count > 0) kannst dir spaaren da die foreach Schleife das schon übernimmt. Denk dran, je weniger Abfragen und Aufrufe desto mehr Performance bekommst du rein - Aber das ist nicht der Zeitkiller. Kannst du bitte vom Grafischen Object die Funktion DoYourJob() noch reinmachen - evtl ist dort ein Aufruf der zu viel Zeit kostet.
Ansonsten, egrath hat nicht unrecht aber eigentlich sollte das nicht nötig sein - zumindest nicht wenn mehrer tausende von Objecten darstellst.
Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(
OK, ich habe festgestellt, dass das Problem an der Logik lag. Es hat mit dem Zeichnen an sich nichts zu tun.
Allerdings habe ich gerade ein andere Problem bemerkt:
Ich habe ja meine Endlosschleife, in der alle paar Millisekunden das Bild neu gezeichnet wird. Allerdings wird das Bild auch neu gezeichnet, wenn das Bild durch andere Umstände (z.B. wenn ich ein anderes Fenster darüber ziehe) neu gezeichnet werden muss. Dadurch werden wird die Darstellung beschleunigt. Wie kann ich das verhindern?
-> Informatik-Infotainment <-
Hallo,
indem Du periodisch nur in einen BackBuffer zeichnest und in der OnPaint nur mehr diesen auf den Screen kopierst.
Grüsse,
Egon
egrath's Blog: http://egonrath.eg.funpic.de/wordpress