Sanfte Animation eines Panels von links nach rechts

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
dominicgarcia
Beiträge: 1
Registriert: Do 17. Okt 2024, 12:40

Sanfte Animation eines Panels von links nach rechts

Beitrag von dominicgarcia »

Hallo,

ich möchte das sich z.B. ein Panel waagerecht vom linken Bildschirmrand zum rechten
Bildschirmrand hin- und herbewegt.
Das bekomme ich ohne Probleme hin- das Panel soll aber weich abbremsen und beschleunigen...
Es geht mir um das generelle Konzept. Wie programmiert man so etwas.

Bin für jeden Hinweis dankbar.

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Warf »

Wie im Physikunterricht:
Geschwindigkeit = Beschleunigung*Zeit
Position = Geschwindigkeit*Zeit=Bescheunligung*Zeit*Zeit

Du suchst dir also aus mit welcher maximalgeschwindigkeit das Panel sich bewegen soll, z.B. 100 pixel pro sekunde, und eine Beschleunigung, z.B. 20pixel pro sekunde pro sekunde. Dann berechnest du wie lang der beschleunigungs und bremszeit ist, 100/20=5 sekunden. Dann berechest du wie lang der Bremsweg ist, 20*5^2 = 500 pixel.

D.h. du fängst an zu beschleunigen mit 20 pixeln pro sekunde bis du 100 pixel pro sekunde erreichst, dabei ist dein Panel bereits schon 500 pixel geandert. Sobald du 500 pixel vor dem Ende bist bremst du ab mit -20 pixel pro sekunde pro Sekunde.

Viel einfacher ists wenn dir die Maximalgeschwindigkeit egal ist, denn dann kannst du einfach flat ab der hälfte abbremsen, weil die Beschleunigungszeit natürlich immer Equivalent zur Bremszeit ist.

Beispiel (bewegt Button1 abwechseld von links nach rechts und von rechts nach links):

Code: Alles auswählen

procedure TForm1.Timer1Timer(Sender:TObject);
const
  MaxSpeed = 100;
  Acceleration = 20;
  Breakpoint = Acceleration*(MaxSpeed/Acceleration)*(MaxSpeed/Acceleration);
const
  CurrentSpeed: Double = 0;
  LastTime: QWord = 0;
var
  TimeDiff:Double;
begin
  if LastTime = 0 then
  begin
    LastTime:=GetTickCount64;
    Exit;
  end;
  TimeDiff:=(GetTickCount64-LastTime)/1000;
  LastTime:=GetTickCount64;
  if (Button1.Left+Button1.Width/2<ClientWidth/2) and (
       (CurrentSpeed<>MaxSpeed) or
       (Button1.Left+Button1.Width/2<ClientWidth-BreakPoint)
     ) and (
       (CurrentSpeed<>-MaxSpeed) or
       (Button1.Left+Button1.Width/2>BreakPoint)
     ) then
    CurrentSpeed:=Min(CurrentSpeed+Acceleration*TimeDiff, MaxSpeed)
  else
    CurrentSpeed:=Max(CurrentSpeed-Acceleration*TimeDiff, -MaxSpeed);
  Form1.Caption:=CurrentSpeed.ToString;
  Button1.Left:=Round(Button1.Left + CurrentSpeed);
end;
Zuletzt geändert von Warf am Do 17. Okt 2024, 22:32, insgesamt 1-mal geändert.

Mathias
Beiträge: 6910
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Mathias »

Ich mache sowas in dieser Art.

Code: Alles auswählen

procedure TForm1.Timer1Timer(Sender: TObject);
const
  c:Single=0;
begin
  Button1.Left:=round((sin(c)+1)*100);
  c+=0.1;
end; 
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

charlytango
Beiträge: 1061
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von charlytango »

ahem -- hab da fachlich nix dazu zu sagen, bloss eine Frage:

Meines Wissens kann man eine Konstante nicht inkrementieren.
Liege ich da falsch?

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1639
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von fliegermichl »

charlytango hat geschrieben: Do 17. Okt 2024, 23:24 ahem -- hab da fachlich nix dazu zu sagen, bloss eine Frage:

Meines Wissens kann man eine Konstante nicht inkrementieren.
Liege ich da falsch?
Das ist keine echte Konstante. Nur eine initialisierte Variable.

Code: Alles auswählen

const c = 0.1;
Die ist unveränderlich.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1639
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von fliegermichl »

Mathias hat geschrieben: Do 17. Okt 2024, 21:28 Ich mache sowas in dieser Art.

Code: Alles auswählen

procedure TForm1.Timer1Timer(Sender: TObject);
const
  c:Single=0;
begin
  Button1.Left:=round((sin(c)+1)*100);
  c+=0.1;
end; 
Wenn man statt der Konstanten 100

Code: Alles auswählen

    Button1.Left:=round((sin(c)+1)*((width-Button1.Width) shr 1));
schreibt, wandert der Button auch schön von ganz links nach ganz rechts und wieder zurück.

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 587
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 4.1 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Niesi »

fliegermichl hat geschrieben: Fr 18. Okt 2024, 08:34
charlytango hat geschrieben: Do 17. Okt 2024, 23:24 ahem -- hab da fachlich nix dazu zu sagen, bloss eine Frage:

Meines Wissens kann man eine Konstante nicht inkrementieren.
Liege ich da falsch?
Das ist keine echte Konstante. Nur eine initialisierte Variable.

Code: Alles auswählen

const c = 0.1;
Die ist unveränderlich.


Niklaus Wirth drehte sich im Grab um - eine Konstante, die eine initialisierte Variable ist. :roll:

Sein Motto war immer: Programmieren muss einfach sein ...
:!: :!: :!:

https://www.golem.de/news/nachruf-infor ... 80806.html

https://de.wikipedia.org/wiki/Wirthsches_Gesetz
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Warf »

Eine typisierte Konstante ist in der Standard Einstellung eine "Writable Const". Das heißt es ist keine Konstante sondern eine Variable mit statischer Lebenszeit. In anderen Sprachen nennt sich das "static variable".

Im Grunde was es bedeutet, es ist eine Variable die nur für die Funktion zugänglich ist, aber über Funktionsaufrufe hinweg bestelt. Also eine globale Variable mit lokaler Sichtbarkeit. Beispiel:

Code: Alles auswählen

function NextIndex: Integer;
const
  Counter: Integer=0;
begin
  Result:=Counter;
  Inc(Counter);
end;
Diese funktion gibt in jedem Aufruf den wert des Vorrigen Aufrufs + 1 zurück.

Sowas kann sehr nützlich sein in einigen Fällen. in meinem Beispiel oben hab ich es einfach benutzt damit ich alles in einer Schönen funktion hab, was es einfacher macht das ganze hier im Forum zu teilen.

Für diesen Fall ist das natürlich aber eher Suboptimal, denn die Variablen sind auch über verschiedene Instanzen der selben Klasse geteilt, d.h. wenn man mehr als eine Instanz dieser Form hat, würden die sich gegenseitig zwischen funken. Daher sollte für eine Umsetzung das als Feld in die Klasse gebracht werden.

Gibt aber dennoch mehr als genug Fälle in denen das eine super Lösung ist, und da das Hauptproblem von Globalen Variablen der Globale Scope ist, ist es normalerweise Ratsam wenn man eine Globale Variable nur innerhalb einer Funktion (und ggf einigen Helferfunktionen) braucht, diese als Writeable Const lokal zu definieren.

Das die Syntax absolut Grauenvoll ist mit dem "const" keyword stimm ich voll und ganz zu. Dennoch ein sehr nützliches Konzept

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Warf »

Mathias hat geschrieben: Do 17. Okt 2024, 21:28 Ich mache sowas in dieser Art.

Code: Alles auswählen

procedure TForm1.Timer1Timer(Sender: TObject);
const
  c:Single=0;
begin
  Button1.Left:=round((sin(c)+1)*100);
  c+=0.1;
end; 
Ja das ist die andere Methode, man kann sich eine Funktion ausdenken die den Weg beschreibt, z.B. Sinus oder Parabolisch, und dann die Position auf dieser Kurve ausrechnen und auf die Horizontalachse abbilden.

Was man allerdings noch beachten sollte ist das je nach Auslastung Timer nicht uniform ticken, d.h. man sollte lieber die Zeitschritte nach der Tatsächlich vergangenen Zeit normalisieren:

Code: Alles auswählen

procedure TForm1.Timer1Timer(Sender: TObject);
const
  curveSpeed=10;
const
  c:Single=0;
  LastTime:QWord=0;
var
  TimeDelta:Double;
begin
  if LastTime=0 then
    TimeDelta:=0
  else
    TimeDelta:=(GetTickCount64-LastTime)/1000;
  LastTime:=GetTickCount64;
  Button1.Left:=round((sin(c)+1)*100);
  c+=CurveSpeed*TimeDelta;
end;

Mathias
Beiträge: 6910
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Mathias »

Das die Syntax absolut Grauenvoll ist mit dem "const" keyword stimm ich voll und ganz zu. Dennoch ein sehr nützliches Konzept
Dies ist in meinen Augen nicht sauber gelöst, eine Konstante dürfte wie der Name schon sagt, nicht änderbar sein.
So wäre es viel sauberer gelöst.

Code: Alles auswählen

var
  counter: integer = 0; static;
Wenigstens kann man mit {$J+} und {$J-} die Constante auf ReadOnly stellen.
Was man allerdings noch beachten sollte ist das je nach Auslastung Timer nicht uniform ticken, d.h. man sollte lieber die Zeitschritte nach der Tatsächlich vergangenen Zeit normalisieren:
Dies ist mir bewusst, dies sollte man bei jeder Animation machen, vor allem wen das ganze über die Framerate gesteuert ist.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2118
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Warf »

Das ist eine der Sachen die finde ich haben Modernere UI Frameworks wie WPF oder Firemonkey besser gelöst, das es dort schon predefinierte Animationsframeworks gibt mit denen man sowas recht trivial wird

Mathias
Beiträge: 6910
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von Mathias »

Warf hat geschrieben: Fr 18. Okt 2024, 17:29 Das ist eine der Sachen die finde ich haben Modernere UI Frameworks wie WPF oder Firemonkey besser gelöst, das es dort schon predefinierte Animationsframeworks gibt mit denen man sowas recht trivial wird
Mit HTML ist solches Zeugs auch möglich.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

PascalDragon
Beiträge: 954
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von PascalDragon »

In diesem Kontext sollte man wohl auch die sogenannten „Easing Funktionen” erwähnen, welche im Zusammenhang mit Animationen häufig genutzt werden, um zwischen zwei Werten (zum Beispiel Positionen) zu interpolieren. Die verlinkte Webseite hat auch die mathematischen Funktionen, welche in FPC reimplementiert werden können.
FPC Compiler Entwickler

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1639
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Sanfte Animation eines Panels von links nach rechts

Beitrag von fliegermichl »

PascalDragon hat geschrieben: So 20. Okt 2024, 11:32 In diesem Kontext sollte man wohl auch die sogenannten „Easing Funktionen” erwähnen, welche im Zusammenhang mit Animationen häufig genutzt werden, um zwischen zwei Werten (zum Beispiel Positionen) zu interpolieren. Die verlinkte Webseite hat auch die mathematischen Funktionen, welche in FPC reimplementiert werden können.
Ah ja, die hatte ich schonmal nach Pascal portiert. Muss ich mal raussuchen.

Antworten