Autor Beitrag
beastofchaos
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: Mo 27.12.10 00:52 
Hallo Leute,
Ich eröffne das Thema zur einer wichtigen Kleinigkeit... Worum es geht, erklär ich euh gerne:

Hier noch einmal mein Vorbildprogramm: de.playforia.com/spielen/minigolf/

Bei diesem Minigolfprogramm zeichnet das Programm fast in einer millionstel Sekunde die Linie uwischen Kugel und Maus und ist immer genau bei dem Cursor. Bei meinem Minigolfprogramm ( das mit MouseMove arbeitet ) ist das Programm zu langsam, um selbst bei bewegendem Cursor, die Linie exakt zu zeichnen :/ Weiß jemand Rat?

MfG Thomas


Zuletzt bearbeitet von beastofchaos am Di 28.12.10 17:35, insgesamt 1-mal bearbeitet
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Mo 27.12.10 01:36 
Die Darstellung Deiner Golflandschaft würde ich in einem einem Image hinter der Paintbox vorhalten. Das Zeichnen der Linie, bzw. die Animation des Schlages in der Paintbox darstellen. Folgendes läuft bei mir ohne Hänger, Timer und flackern auf einen 1.3 GHZ Rechner mit Onboardgrafik.
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:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    Timer1: TTimer;
    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure PaintBox1Paint(Sender: TObject);
  private
  FX,FY:Integer;
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  FX := X;
  FY := Y;
  Paintbox1.Invalidate;
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  Paintbox1.Canvas.Pen.Style := psSolid;
  Paintbox1.Canvas.Brush.Color := clWhite;
  Paintbox1.Canvas.Ellipse(90,90,110,110);
  Paintbox1.Canvas.MoveTo(100,100);
  Paintbox1.Canvas.Pen.Style := psdash;
  Paintbox1.Canvas.LineTo(FX,FY);
  Paintbox1.Canvas.Pen.Style := psSolid;
  Paintbox1.Canvas.Rectangle(FX - 5, FY - 5, FX + 5, FY + 5);
end;

end.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
beastofchaos Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: Mo 27.12.10 01:57 
Ich hab das ja jetzt auch alles hinbekommen und bin sehr stolz, aber mein Problem JETZT ist, dass, wenn du die Maus richtig schnell bewegst, die Linie nicht rechtzeitig zeichnet bzw. minimal zu langsam ist. Ich hab auch einen schnellen Computer, aber es geht hier eher darum ,dass die Procedure MouseMove nciht schnell genug arbeitet.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Mo 27.12.10 02:30 
Du hast eine EXE drangehängt, um hier etwas zu optimieren hilft das nichts.
Ich vermute Du malst über einen Timer, falls nicht malst Du gegf. einfach mehr als nötig ist. MouseMove ist mit Sicherheit nicht zu langsam. Mein Couchrechner ist nicht schnell sondern richtig langsam und ich ich habe mit angehängtem Beispiel die von Dir genannten Probleme nicht.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 27.12.10 06:47 
Meine Vermutung: Du zeichnest vielleicht in OnPaint noch einmal komplett alles in die Hintergrundbitmap und kopierst die auf die PaintBox. Dann ist es natürlich langsam.

Oder du prüfst in OnMouseMove nicht, ob die Koordinaten sich überhaupt geändert haben seit dem letzten Zeichnen. Dann zeichnest du manchmal extrem oft neu, so dass es Performanceprobleme gibt.

Aber wie user profile iconbummi schon sagte:
Wenn du nicht das Projekt mit Quelltext, sondern nur die Exe anhängst, können wir auch nicht direkt dort optimieren.
beastofchaos Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: Mo 27.12.10 11:09 
Gut, hier habt ihr das ganze Programm. Hab mal meine Funktion vom schießen gelöscht, da ich ja hier erst mal nur das schaffen will. Also nicht über den Button "Schießen" (+einen zweiten Timter) wundern.
Und übrigens führt er doch MouseMove aus, WENN sich die Koordinaten der Maus ändern. Tatsächlich funktioniert es bei mir so, dass er in der Bitmap alles mit Rectangle übermalt und dann die neue Linie zeichnet. Und dann nur noch am Ende "Paintbox1.Repaint" ausführen. Hab halben Tag daran gearbeitet und keine andere geeignete Lösung gefunden.

MfG Thomas

edit: Leider hab ich noch das Problem, dass, wenn das nur bei "PaintBox1MouseMove" gemacht ist und ich die Maus auf einem Button habe, erstellt er keine Linie. Deswegen muss ich den Quelltext bei jeder MouseMove-prozedur von jeder Komponente reinkopieren.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Button2MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);


Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt
Moderiert von user profile iconNarses: Inline- in normalen Anhang gewandelt und Binaries aus dem Archiv gelöscht.


Zuletzt bearbeitet von beastofchaos am Di 28.12.10 17:35, insgesamt 1-mal bearbeitet
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Mo 27.12.10 12:51 
Da Du es sicher selbst lösen willst von mir nur ein paar hinweise....
ausblenden Delphi-Quelltext
1:
2:
  bmp:=TBitMap.Create;
  bmp := TBitmap.Create;

ist sicher nur eine Kopierfehler....
Eine der ersten Regeln lautet DRY (don't repeat yourself), wenn Du es so lösen willst wie Du es getan hast, dann weise allen Elementen die OnMOuseMove benötigen dieselbe Methode zu, im Moment hast Du den identischen Codeblock 4 mal in Deinem Quelltext.
Die meiste Rechenzeit verbraucht bei Dir
ausblenden Delphi-Quelltext
1:
2:
3:
4:
bmp.Canvas.Rectangle(0,0,Form1.Width-17,Form1.Height-37);
// und
  BitBlt(PaintBox1.Canvas.Handle, 00, bmp.Width, bmp.Height, bmp.Canvas.Handle,
    00, SrcCopy);


Ich würde:
1.) die Buttons außerhalb des Spielfelds plazieren
2.) ein Hintergundimage für den Golfkurs verwenden.
3.) eine Paintbox drüberlegen in der Ball und Linie im OnPaint direkt gezeichnet werden.
4.) Das OnPaintverhalten würde ich für 2 Situationen unterschiedlich zuweisen.
a.) das woran Du gerade arbeitest, das Festlegen der Abschlgsrichtung (per OnMouseMove)
b.) das noch kommende animieren des Abschlags per Timer. (Das Timerintervall von 1 kanst Du zwar einstellen, mehr als rund 15 - 20 wirst Du aber auch auf den schnellsten Systemen nicht bekommen).
Das Malen direkt in der Paintbox von Ball und Linie lässt die ganze unnötige Füllroutine wegfallen, aufgerufen wird die Paintbox dann im MouseMove/Timer per Invalidate (kein Repaint) damit wird immer nur das gemalt was Du gerade gemalt haben möchtest.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS

Für diesen Beitrag haben gedankt: beastofchaos
beastofchaos Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: Mo 27.12.10 14:10 
Habe den Kopierfehler auch schon entdeckt und korrigiert :)

Und mit der Rectangleanweisung: Ich dachte mir shcon, wenn ich im Hintergrund Rasen etc malen will, kann ich nicht jedes mal, alles mit einem weißen rechteck übermalen, aber wie soll ich sonst die alte Position von der Kugel oder Linie löschen und etwas neues zeichnen. oder kensnt du inzwischen einen Befehl, in dem die bitmap/ Paintbox geleert wird und funktioniert... :/ Vll wilst du mir ja als Beispiel im hitnergrund ein Smiley malen und dein per Paintbox eine Kugel von links nach rechts bewegen. Denn, wenn ich alles übermale, sieht man folglich auch den Hintergrund nicht mehr ( -> deswegen hab ich z.B. meinen Balken im Vordergrund).

Hab jetzt schon 2 Stunden an dem Problem gesessen, dass er eine Linie, die länger als 200 Pixel ist, nur 200 Pixel lang malt. Ziemlich aufwendig, da man Trigonometrie gut können muss dafür :p
Versuche auch grad in meinem Programm erst mal ordnung zu schaffen. Immer wieder definiere ich auch die Pen.Color neu... :/

1) Ich werd mir einfach ein Spielrand mit mehreren Images basteln müssen :/ Aber dann geht es natürlich leicht ;)
3)direkt mit nPaint ist sicher kürzer und zeitsparender, danke für den Tipp
4)Wie gebe ich ihm den zwei verschiedene Situation vor? Soll ich für Beispiel a und b eine Boobleanvariable benutzen und so überprüfen, welche der beiden Aktion gerade aktiv ist ( und dann in Onpaint noch if Schleife )?

Ich dachte Repaint malt das auch immer ganz neu. Oder ist der Unterschied, dass Repaint immer über das alte malt und dass Invalidate das alte löscht und dann erst etwas neues zeichnet?


PS: Was ist eigentlich das Problem/der Nachteil, wenn man eine Bitmap verwendet, statt es direkt im nPaint zu malen?
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Mo 27.12.10 20:30 
Ich hatte gemeint Du könntest für Deinen Hintergrund ein Image laden welches Deinen aktuellen GolfCourse beinhaltet. Auf der Paintbox malst Du direkt im OnPaint welches Du per Invalidate aufrufst nur die sachen die sich ändern, der Ball und die Linie, dies reduziert den Rechen und Speicherfüllaufwand auf ein Minimum.
Wenn Du Invalidate aufrufst wird in die leere Paintbox nur gemalt was Du gerade möchtest, z.B. der Ball und ide Linie.
Die großen Probleme warten eh noch auf Dich, wenn Du den Winkel der Ablenkung berechnen mußt in Abhängigkeit von der Neigung der getroffenen Fläche, die Geschwindigkeit entsprechend dem Reibungskoeffizienten reduzieren musst etc.
Ich habe schon ein paar Ideen, aber warten wir bis es soweit ist.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 27.12.10 21:15 
user profile iconbummi hat folgendes geschrieben Zum zitierten Posting springen:
Ich hatte gemeint Du könntest für Deinen Hintergrund ein Image laden welches Deinen aktuellen GolfCourse beinhaltet. Auf der Paintbox malst Du direkt im OnPaint welches Du per Invalidate aufrufst nur die sachen die sich ändern, der Ball und die Linie, dies reduziert den Rechen und Speicherfüllaufwand auf ein Minimum.
Nein, es erhöht ihn eher. Das TImage wird nämlich dann extra von Windows verwaltet und ggf. viel zu oft neu gezeichnet...
Denn was meinst du wohl wie Windows das schafft, dass das Bild aus dem Hintergrund wieder da ist? Es löst ein Neuzeichnen aus, weil das eine Control unter dem anderen liegt.

Deshalb macht es schon Sinn sich da selbst drum zu kümmern, wenn man mehrere Elemente hat. Man muss das dann natürlich selbst so organisieren, dass man nicht unnötig neuzeichnet. Das heißt sich die alte Position merken und nur die aus dem Zwischenspeicher wiederherstellen, dann die neue Position zeichnen usw.

Auf diese Art und Weise kann man nahezu flimmerfreie Animationen hinbekommen. Und mit Delphi 2010/XE und Windows 7 mit Direct2D geht das noch viel viel besser und extrem flüssig.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Mo 27.12.10 21:36 
@jaenicke
nach meinen Erfahrungen frisst die Speicherkopiererei bei weitem mehr Rechenleistung als Windows ein Hintergrundimage selbst neu malen zu lassen, zumindest bei Anforderungen wie dem genannten Beispiel, das von Dir geschilderte Problem ist mir schon klar, kommt aber nach meinen Erfahrungen weniger zu tragen, als wenn ein OffScreenbitmap IMHO unnötig neu berechnet und gemalt wird.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19321
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 27.12.10 21:43 
user profile iconbummi hat folgendes geschrieben Zum zitierten Posting springen:
kommt aber nach meinen Erfahrungen weniger zu tragen, als wenn ein OffScreenbitmap IMHO unnötig neu berechnet und gemalt wird.
Genau das darf natürlich nicht passieren. Deshalb habe ich ja geschrieben: den Teil merken, der wiederhergestellt werden muss. ;-)

Wenn es wirklich deutlich schneller sein soll, geht das nur indem man via DX oder OpenGL die Überlappungen von der Grafikkarte berechnen lässt. (Wie es Windows Vista und 7 mit allen Fenstern tun, weshalb da die Oberfläche fixer ist als bei XP. Naja, bei Vista durch den Flaschenhals DWM und fehlendes D2D nur theoretisch.)
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Mo 27.12.10 21:59 
@jaenicke
ich habe den Eindruck das Windows ab Vista aufwärts eben diese schon intern abzufackeln scheint und bei genanntem Beispiel selbst schon nur Bereich regeneriert bei dem Änderungen aufgetreten sind, kann aber auch sein dass der Eindruck täuscht.
OpneGL und DX sind zwar potente Beispiele würden aber IMHO die Lerneffekten die ein solches Projekt mitbringt durch die vorhandenen Engines eliminieren. Ich denke bei den Basics anzufangen ist besser als sie sich im nachhinein zuzulegen.
Aber wir gehen OT. ;-)

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
beastofchaos Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: Mo 27.12.10 22:18 
user profile iconbummi hat folgendes geschrieben Zum zitierten Posting springen:
Ich hatte gemeint Du könntest für Deinen Hintergrund ein Image laden welches Deinen aktuellen GolfCourse beinhaltet. Auf der Paintbox malst Du direkt im OnPaint welches Du per Invalidate aufrufst nur die sachen die sich ändern, der Ball und die Linie, dies reduziert den Rechen und Speicherfüllaufwand auf ein Minimum.
Wenn Du Invalidate aufrufst wird in die leere Paintbox nur gemalt was Du gerade möchtest, z.B. der Ball und ide Linie.
Die großen Probleme warten eh noch auf Dich, wenn Du den Winkel der Ablenkung berechnen mußt in Abhängigkeit von der Neigung der getroffenen Fläche, die Geschwindigkeit entsprechend dem Reibungskoeffizienten reduzieren musst etc.
Ich habe schon ein paar Ideen, aber warten wir bis es soweit ist.


Hab mir "theoretisch" im normalen Editor mal den Aufbau schon zusammengebastelt. Als erstes mal zum abschießen der Kugel (im Moment nur konstante Geschwindigkeit), weil mein Freund das schon programmiert hat mit dem Langsamerwerden der Kugel. Als zweites hab ich schon mit Editor geschrieben, wie ich Spiegelung bei Hindernisen ausführe. Dürfte aber am Anfang nur aus einer bestimmten Richtung funktioniert. Da werd ich sicher auch lang dran arbeiten, wenn ich soweit bin ;)

Hab jetzt verstanden, wie das funktioniert, wenn ich nicht bitmap benutze, danke. Werde es mal ausprobieren ;)
Ist es ein Problem, wenn ich jedes Hindernis jeweils einem Image zu weise. So muss ich nicht einzelne Koordinaten sondern .Left-Punkte angeben und möglicherweise verscheiben.
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Di 28.12.10 02:07 
Du wirst zu dem Thema hoffentlich noch reichlich Input erhalten. IMHO mußt Du für jedes Bitmap ein Array von Funktionen anlegen welches die Steigung im Bereich x1-x2 hinterlegt (für alle beteiligten Flächen), die senkrechte konstruieren und per Einfallswinkel=Ausfallswinkel die weiteren Koordinatenen berechnen. Ich würde hierfür ein Array of Record
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
TS:Millisecond;
P:TPoint;
Velocity:Double;
Speed:Double;
frictionn:Double;

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
beastofchaos Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 247
Erhaltene Danke: 4



BeitragVerfasst: Di 28.12.10 03:11 
Hab das hier verschoben auf den anderen Thread, da es jetzt nciht mehr so um DIESES Thema geht ;)

Moderiert von user profile iconNarses: Inline- in normalen Anhang gewandelt und binaries aus dem Archiv entfernt.