Entwickler-Ecke

Multimedia / Grafik - Kreis bewegen und abprallen lassen


wayne123 - Do 27.01.11 17:11
Titel: Kreis bewegen und abprallen lassen
Also ich möchte möglichst einfach/billig einen Kreis erzeugen lassen, der sich in eine Richtung bewegt und an allen Seiten abprallt. Das ganze hab ich dann mit einer großen for-Schleife und if-then Strukturen in die for-Schleife probiert. Jetzt häng ich aber schon bei dem ersten if-then, denn wenn der Kreis unten abprallt, tut er dies auch richtig, es wird aber ein zweiter Kreis erschaffen, der weiter nach unten geht. Achja ich weiß, dass das mir refresh nicht wirklich was bringt, aber vllt. kann mir ja trotzdem jemand helfen. Das mit dem random kann man ja hoffentlich nachher noch einfügen, oder?


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:
50:
51:
52:
53:
54:
unit UnitKreis2;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var v,x,y,z,i,j,k,l: integer;
begin
v:= 200;
x:= 200;
y:= 300;
z:= 300;
j:= 1;
k:=1;
l:=1;
for i:= 1 to 1000 do
begin
if z+j >= Clientheight then
begin
refresh;
l:=l+1;
Canvas.Ellipse(v+k,x+j-2*l,y+k,z+j-2*l);
end
else
refresh;
Canvas.Ellipse(v+k,x+j,y+k,z+j);
j:=j+1;
k:=k+1;
end;


end;

end.


Regan - Do 27.01.11 17:25

Statt Refresh einfach Application.ProcessMessages(); einwerfen.

user profile iconwayne123 hat folgendes geschrieben Zum zitierten Posting springen:
sich in eine Richtung bewegt und an allen Seiten abprallt

Möchtest du einen Kreis malen, der einfach innerhalb der Form herumspringt? Dann müsstest du auch die alten Kreise löschen.


guinnes - Do 27.01.11 17:26

Wenn man den Quelltext formatieren würde, würde man sehen, dass da möglicherweise ein Begin..end-BBlock fehlt


Regan - Do 27.01.11 17:29

Kleine Ergänzung zu user profile iconguinnes: Es gibt auch einen Delphi-Styleguide [http://www.delphi-treff.de/object-pascal/delphi-styleguide/] ;)


wayne123 - Do 27.01.11 17:33

Ich wollte möglichst wenig neues nehmen und eig. nur mit Canvas.Ellipse und for-Schleife und if-then arbeiten, aber wie funktioniert denn Application.ProccessMessages()? Ich hab jetzt mal mit sleep nachgeguckt, wie genau diese beiden Kreise verlaufen und hab gemerkt, dass der abprallende Kreis und der weiterlaufende Kreis sich abwechselnd einen nach vorne bewegen, nur wieso, weiß ich nicht.


Regan - Do 27.01.11 17:38

user profile iconwayne123 hat folgendes geschrieben Zum zitierten Posting springen:
wie funktioniert denn Application.ProccessMessages()?

Du ersetzt einfach nur dieses Refresh(); durch Application.ProccessMessages() und dann sollte das Programm auch ordnungsgemäß neuzeichnen. Application.ProccessMessages(); lässt das Programm Nachrichten verarbeiten (z. B. eine Zeichnung oder den Klick auf den Schließenbutton). Es friert nicht ein.

user profile iconwayne123 hat folgendes geschrieben Zum zitierten Posting springen:
nur wieso, weiß ich nicht.

user profile iconguinnes hat folgendes geschrieben Zum zitierten Posting springen:
Wenn man den Quelltext formatieren würde, würde man sehen, dass da möglicherweise ein Begin..end-BBlock fehlt

Und konkret:

user profile iconwayne123 hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
{...}
if z+j >= Clientheight then
  begin
    Application.ProccessMessages();
    l:=l+1;
    Canvas.Ellipse(v+k,x+j-2*l,y+k,z+j-2*l);
  end
else
  Application.ProccessMessages();

Canvas.Ellipse(v+k,x+j,y+k,z+j);
j:=j+1;
k:=k+1;
end;

{...}

Ändern in:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
{...}
if z+j >= Clientheight then
  begin
    Application.ProccessMessages();
    l:=l+1;
    Canvas.Ellipse(v+k,x+j-2*l,y+k,z+j-2*l);
  end
else
  begin
    Application.ProccessMessages();
    Canvas.Ellipse(v+k,x+j,y+k,z+j);
    j:=j+1;
    k:=k+1;
  end;

end;

{...}


wayne123 - Do 27.01.11 17:45

Ohh, stimmt, jetzt ist nur noch ein Kreis da, der sich dafür gerade nach oben bewegt, aber das werd ich mir erstmal noch angucken. Nur dass Application.ProcessMessages() funktioniert nicht, denn dann sind auf einmal alle Kreise da, die insg. gezeichnet werden, was dann so ne Art Rohr ergibt.


Regan - Do 27.01.11 18:14

user profile iconwayne123 hat folgendes geschrieben Zum zitierten Posting springen:
denn dann sind auf einmal alle Kreise da, die insg. gezeichnet werden, was dann so ne Art Rohr ergibt.

user profile iconRegan hat folgendes geschrieben Zum zitierten Posting springen:
Dann müsstest du auch die alten Kreise löschen.

Du müsstest die ganze Canvas-Fläche wieder mit einer Farbe füllen und so die alten Kreise überschreiben. Mit sleep(100); kannst du die Ausführung des Programmes um 100 Millisekunden anhalten, womit du dann einen schönen flüssigen Effekt erreichst ;)


wayne123 - Do 27.01.11 19:26

Das sleep nur einmal, oder einmal in der Schleife und einmal in if-then? Em, wie genau geht der Befehl fürs überzeichnen? und hier auch wieder die Frage, zweimal oder einmal?


bummi - Do 27.01.11 19:40

Ich hab Dir mal ein kleines Beispiel angehängt


wayne123 - Do 27.01.11 20:18

Da kommt bei mir ein Fehler, weil glaub ich die .res Datei fehlt. Geht das dann nur mit dieser Box oder kann man das auch ohne Box fast genauso machen?


bummi - Do 27.01.11 22:06

den Res-Fehler kannst Du ignorieren, Du kannst auf jedem Canvas malen, die Paintbox macht es Dir am einfachsten ohne eigene Komponenten oder Erweiterung bestehenden Komponenten zu arbeiten.
Eine Implementierung im OnPaint eines Forms geht ebenso einfach, im Timer dann halt z.B. Form1.Invaidate aufrufen und selbstredend das Canvas des Forms verwenden.


kwhk - Sa 29.01.11 14:24

Ich habe das Beispiele etwas überarbeitet
- der Kreis ist eine Ellipse
- das Programm läuft endlos, bis im Fenster die Maustaste gedrückt wird
- Ich benutze Delphi7, da muss Application.ProcessMessages und nicht Application.ProcessMessages() geschrieben werden. Die Klammern sind bei C++ anzugeben. Es ist eine Procedure und keine Function.



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:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
    procedure FormClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

  Beenden : Boolean = False; // Bei Mausklick = TRUE

implementation

{$R *.dfm}

Procedure TForm1.BitBtn1Click(Sender: TObject);
  Var x,y,b,h,i,j,xa,ya: integer;
  Begin
    i := 1; j := 1;     // dx und dy
    x := 100; y := 200// Start-Position
    b := 200; h := 150// Breite Höhe
    xa := x;  ya := y;  // Alt-Position

    Canvas.Pen.Style := pssolid;
    Canvas.Pen.Width := 2;
    Canvas.Brush.Style := bssolid;
    Canvas.Brush.Color := Form1.Color;

    While True do // Endlosschleife, bis Mausklick im Fenster
      Begin
        Canvas.Pen.Color := Form1.Color;     // Lösch-Farbe
        Canvas.Ellipse(xa, ya, xa+b, ya+h);  // ALT löschen

        Canvas.Pen.Color := clBlack;     // Schwarz
        Canvas.Ellipse(x, y, x+b, y+h);  // NEU zeichnen

        xa := x; ya := y;    // Position ALT merken
        x := x+i; y := y+j;  // Position NEU berechnen
        Sleep(10);           // etwas warten 10 ms
        if ((x < 1and (i < 0)) then i := 1;   // Linker Rand erreicht ?
        if ((y < 1and (j < 0)) then j := 1;   // Oberer Rand erreicht ?
        if (x+b+1) > ClientWidth then i := -1;  // Rechter Rand erreicht ?
        if (y+h+1) > ClientHeight then j := -1// Unterer Rand erreicht ?
        Application.ProcessMessages;
        if Beenden then Halt(1); // Programm beenden bei Mausclick
      End;
  End;

procedure TForm1.FormClick(Sender: TObject);
begin
  Beenden := True;  // Mausklick im Fenster => PGM-Ende
end;

End.


Probiere es einfach mal aus ...