Panel soll sich automatisch in verschiedene Richtungen bewegen

    Panel soll sich automatisch in verschiedene Richtungen bewegen

    Hallo,
    ich möchte in Delphi folgendes realisieren:
    Ich habe ein Panel, welches sich automatisch in eine zufällige Richtung bewegen soll. Diese Richtung soll sich nach einer zufälligen Zeit ändern.
    Das Ganze soll solange wiederholt werden, bis es den Rand des Fensters erreicht.

    Mir fehlen einfach die Ansatzpunkte für die Bewegungen, sprich zufällige Richtung, sowie zufällige Zeit. ?(

    Vielen Dank im Voraus! :)
    Dir fehlen nur Ansatzpunkte?
    Dann gebe ich dir ein paar:
    - Randomize / Random für Zufallszahlen
    - Die Eigenschaften Top und Left für die Positionierung des Panels
    - Die Eigenschaften Width und Height in Verbindung mit Top und Left, um zu prüfen, ob der Rand erreicht ist
    - Abhängig davon, musst du auch noch die entsprechenden Eigenschaften des Parent des Panels berücksichtigen
    - Die TTimer-Komponente die zur zufälligen Zeit ausgelöst wird
    Zur Richtung: Welche Richtungen sind möglich? Spontan würde man jetzt sagen: Rechts, links, oben und unten. In Wirklichkeit sind aber mindestens 360 Richtungen möglich, denn einen Kreis kann man in 360 Gradeinheiten aufteilen. Auch eine Linie kann man vom Ausgangspunkt gesehen in 360 verschiedene Richtungen zeichnen. Das nennt man Winkel: Ein Winkel ist in der Geometrie ein Teil der Ebene, der von zwei in der Ebene liegenden Strahlen (Halbgeraden) mit gemeinsamem Anfangspunkt begrenzt wird. Wobei hier als erster Strahl die eine Linie vom Ausgangspunkt mit dem Winkel 0 hinzugedacht werden muß. Fazit: Du mußt dich mit Winkelberechnung und der Umsetzung in Pascal befassen.

    Zur Geschwindigkeit: Der Betrag der Geschwindigkeit gibt an, welche Wegstrecke ein Körper innerhalb einer bestimmten Zeitspanne zurücklegt. Das bedeutet bei einem Winkel von z.B. 90 Grad (Bewegung nach links) und einer Geschwindigkeit von 1 Pixel pro Sekunde, daß du jede Sekunde den X-Wert der Position um 1 verringerst. Bei einem Winkel von 45 Grad (Bewegung nach links oben) und einer Geschwindigkeit von 2 Pixeln pro Minute mußt du den X-Wert sowie den Y-Wert der Position jede Sekunde um den Wert 2 verringern.

    Zu Zufallswerten: Zufallswerte generiert man in Delphi mit der Funktion Random.

    Ich habe jetzt absichtlich "übersichtliche" Winkelgrößen gewählt, um das Beispiel anschaulich zu gestalten. Für Winkel von z.B. 22 Grad mußt du natürlich entsprechende Winkel-Algorithmen entwickeln oder bei Google erfragen.
    Die Richtungen sind Nach oben, unten, links, rechts.
    Random und das Panel verrücken ist alles kein Problem. Aber ich weiß nicht, wie ich das in Verbindung mit den Timern einsetze und die Richtung automatisch und zufällige einstelle. Gibt es sowas wie ein "case-random-of" ? :D

    Quellcode

    1. procedure TFHauptformular.PanelLaufen;
    2. var i:integer;
    3. begin
    4. DoubleBuffered := True;
    5. for i := 1 to random(220) do
    6. begin
    7. Panel.Top := Panel.Top - 1;
    8. sleep(10);
    9. Repaint;
    10. end;
    11. end;


    Mir kam eben die Idee:
    Ich könnte doch mit Random eine Zahl 1-4 generieren und diese dann einer Richtung zuordnen. Bspw. bei 1 nach links, bei 2 nach oben etc.
    So würde ich eine zufällige Richtung hinbekommen. Das teste ich erst mal.

    Edit: Funktioniert :) Jetzt nur noch die Timer einbinden. Zwischendurch eine andere Frage: Der Nutzer gibt die Anzahl Panels ein, welche erstellt werden sollen. Wie spreche ich denn die einzelnen Panels an?
    So lasse ich sie erstellen:

    Quellcode

    1. ​ for i := 1 to AnzahlPanel do
    2. Panel := TPanel.Create(FHauptformular);


    Wenn ich nun Panel.NachLinks ausführe, wird nur das erste erstelle Panel nach Links bewegt.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „CuberDave“ ()

    Eine Reihe von Panels verwaltest du am besten in einer TObjectList. Um die Panels zu unterscheiden, verwendest du wie im ObjektInspector auch das Property Name. Du kannst zur Vereinfachung einfach den Index in der Objektliste als Name verwenden.
    Einfacher finde ich, die Geschwindigkeiten in X und Y direkt anzugeben. Kannst du mit Random machen. Wenn ein Objekt an die "Wand" stößt, dann dreht sich die entsprechende Geschwindigkeit um. Das Beispiel bezieht sich auf einen Ball. VX und VY sind die Geschwindigkeiten, X und Y die Position des Objekts (Bei dir Left und Top). Bei einem Rechteck sind statt R Width und Height anzusetzen. Der Timer ruft die Move (der Liste) auf.

    Delphi-Code

    1. procedure TBall.Move;
    2. begin
    3. FX := FX + FVX;
    4. FY := FY + FVY;
    5. if FX >= FAreaWidth - FR then
    6. begin
    7. FX := FAreaWidth - FR;
    8. FVX := -FVX
    9. end;
    10. if FX <= FR then
    11. begin
    12. FX := FR;
    13. FVX := -FVX
    14. end;
    15. if FY >= FAreaHeight - FR then
    16. begin
    17. FY := FAreaHeight - FR;
    18. FVY := -FVY
    19. end;
    20. if FY <= FR then
    21. begin
    22. FY := FR;
    23. FVY := -FVY
    24. end;
    25. end;


    Kriegst du das hin, das auf deine Panels zu übertragen?
    Einen Satz verstehen, heißt, wissen was der Fall ist, wenn er wahr ist. (Ludwig Wittgenstein)

    Perlsau schrieb:

    Eine Reihe von Panels verwaltest du am besten in einer TObjectList. Um die Panels zu unterscheiden, verwendest du wie im ObjektInspector auch das Property Name. Du kannst zur Vereinfachung einfach den Index in der Objektliste als Name verwenden.


    TObjectList, alles klar. Damit werde ich mich mal befassen.Danke!

    Bjoerk schrieb:

    [...]

    Kriegst du das hin, das auf deine Panels zu übertragen?


    Mal schauen wie weit ich mit meinen aktuellen Algorithmus komme. Finde deine Bezeichnungen etwas verwirrend, ehrlich gesagt.

    So, jetzt komme ich nicht weiter. Alle Panels (im Folgenden Code "Ameisen") bewegen sich in die gleiche Richtung und um die gleiche Distanz.

    Hier mal die Syntax für die procedure "NachLinks":

    Quellcode

    1. ​procedure TFHauptformular.NachLinks;
    2. var i,j: integer;
    3. hilf: TAmeise;
    4. begin
    5. for i := 1 to random(220) + 30 do
    6. begin
    7. for j := 1 to AnzahlAmeisen do
    8. begin
    9. hilf := (ObjectList.Items[j-1]) As TAmeise;
    10. hilf.Left := hilf.Left - 1;
    11. sleep(10);
    12. Repaint;
    13. end;
    14. end;
    15. end;


    So lasse ich die zufällige Richtung erzeugen:

    Quellcode

    1. ​ Richtung := random(4) + 1;
    2. case Richtung of
    3. 1: NachLinks;
    4. 2: NachRechts;
    5. 3: NachOben;
    6. 4: NachUnten;
    7. end;

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „CuberDave“ ()

    Was findest du verwirrend? Die Richtung gibt man über einfach das Vorzeichen der Geschwindigkeit an. Guckst du:

    Delphi-Code

    1. unit AmeisenUnit;
    2. interface
    3. uses
    4. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    5. Dialogs, ExtCtrls, Contnrs;
    6. type
    7. TAmeise = class(TPanel)
    8. private
    9. FVx, FVy: integer;
    10. public
    11. property Vx: integer read FVx write FVx;
    12. property Vy: integer read FVy write FVy;
    13. procedure Move(AreaWidth, AreaHeight: integer);
    14. end;
    15. TAmeisen = class(TObjectList)
    16. private
    17. function GetItems(Index: integer): TAmeise;
    18. public
    19. procedure Move(Width, Height: integer);
    20. property Items[Index: integer]: TAmeise read GetItems; default;
    21. end;
    22. TAmeisenForm = class(TForm)
    23. MoveTimer: TTimer;
    24. procedure MoveTimerTimer(Sender: TObject);
    25. procedure FormCreate(Sender: TObject);
    26. procedure FormDestroy(Sender: TObject);
    27. procedure AmeiseClick(Sender: TObject);
    28. private
    29. FAmeisen: TAmeisen;
    30. end;
    31. var
    32. AmeisenForm: TAmeisenForm;
    33. implementation
    34. {$R *.dfm}
    35. { TAmeise }
    36. procedure TAmeise.Move(AreaWidth, AreaHeight: integer);
    37. begin
    38. Left := Left + FVx;
    39. Top := Top + FVy;
    40. if Left <= 0 then
    41. begin
    42. Left := 0;
    43. FVx := -FVx
    44. end;
    45. if Top <= 0 then
    46. begin
    47. Top := 0;
    48. FVy := -FVy
    49. end;
    50. if Left >= AreaWidth - Width then
    51. begin
    52. Left := AreaWidth - Width;
    53. FVx := -FVx
    54. end;
    55. if Top >= AreaHeight - Height then
    56. begin
    57. Top := AreaHeight - Height;
    58. FVy := -FVy
    59. end;
    60. end;
    61. { TAmeisen }
    62. function TAmeisen.GetItems(Index: integer): TAmeise;
    63. begin
    64. Result := TAmeise(inherited Items[Index]);
    65. end;
    66. procedure TAmeisen.Move(Width, Height: integer);
    67. var
    68. I: integer;
    69. begin
    70. for I := 0 to Count - 1 do
    71. Items[I].Move(Width, Height);
    72. end;
    73. { TAmeisenForm }
    74. procedure TAmeisenForm.FormCreate(Sender: TObject);
    75. var
    76. I, Index: integer;
    77. begin
    78. DoubleBuffered := true;
    79. Randomize;
    80. FAmeisen := TAmeisen.Create;
    81. for I := 1 to 10 do
    82. begin
    83. Index := FAmeisen.Add(TAmeise.Create(Self));
    84. FAmeisen[Index].Name := 'Ameise' + IntToStr(I);
    85. FAmeisen[Index].Caption := IntToStr(I);
    86. FAmeisen[Index].Parent := Self;
    87. FAmeisen[Index].Left := Random(Width div 2);
    88. FAmeisen[Index].Top := Random(Height div 2);
    89. FAmeisen[Index].Width := 40;
    90. FAmeisen[Index].Height := 40;
    91. FAmeisen[Index].ParentBackground := false;
    92. FAmeisen[Index].OnClick := AmeiseClick;
    93. if Odd(I) then
    94. begin
    95. FAmeisen[Index].Color := clBlue;
    96. FAmeisen[Index].Vx := Random(10) + 1; // > 0 -> Nach Rechts;
    97. FAmeisen[Index].Vy := Random(10) + 1; // > 0 -> Nach Unten;
    98. end
    99. else
    100. begin
    101. FAmeisen[Index].Color := clRed;
    102. FAmeisen[Index].Vx := -(Random(10) + 1); // < 0 -> Nach Links;
    103. FAmeisen[Index].Vy := -(Random(10) + 1); // < 0 -> Nach Oben;
    104. end;
    105. end;
    106. MoveTimer.Interval := 50;
    107. end;
    108. procedure TAmeisenForm.FormDestroy(Sender: TObject);
    109. begin
    110. FAmeisen.Free;
    111. end;
    112. procedure TAmeisenForm.MoveTimerTimer(Sender: TObject);
    113. begin
    114. MoveTimer.Enabled := false;
    115. try
    116. FAmeisen.Move(ClientWidth, ClientHeight);
    117. finally
    118. MoveTimer.Enabled := true;
    119. end;
    120. end;
    121. procedure TAmeisenForm.AmeiseClick(Sender: TObject);
    122. var
    123. Ameise: TAmeise;
    124. begin
    125. Ameise := TAmeise(Sender);
    126. ShowMessage(Ameise.Name);
    127. end;
    128. end.
    Einen Satz verstehen, heißt, wissen was der Fall ist, wenn er wahr ist. (Ludwig Wittgenstein)