Anstelle des Vorworts
In meinem kürzlich erschienenen 
Lazarus- Artikel 
- Schreiben einer Komponente für Sprite-Animationen - habe ich den Prozess zum Erstellen einer einfachen 
TImageFragment- Komponente beschrieben, mit der Sie ein bestimmtes Fragment eines Bildes anzeigen können.
In diesem Artikel möchte ich das ausgewählte Thema fortsetzen und zeigen, wie einfach es ist, mithilfe dieser Komponente Animationen von Sprites in der 
Lazarus- Entwicklungsumgebung ( 
offizielle Website ) zu erstellen.
Bei diesem Ansatz werden einzelne Animationsrahmen in verschiedenen Projektionen auf demselben Bild platziert, und die Komponente zum Anzeigen des Sprites zeigt nur ein ausgewähltes Fragment dieses Bildes unter Verwendung der Eigenschaften 
OffsetX und 
OffsetY (Versatz der oberen linken Ecke des 
Bildfragments horizontal und vertikal).
Viele dieser vorgefertigten Bilder finden Sie im Web - zum Beispiel 
hier auf dieser Website . 
Wählen Sie das Bild aus (und bereiten Sie es vor)
Für mein Beispiel habe ich dieses Bild ausgewählt:

- sehr ausdrucksstark schlägt dieser Phönixvogel mit den Flügeln.
Wie Sie sehen können, enthält jede Zeile 4 Frames für jede der 4 Projektionen. Wenn Sie nur 
OffsetX ändern , können Sie den Vogel mit den Flügeln 
schlagen lassen. Um die Projektion zu ändern, reicht es aus, nur 
OffsetY zu ändern. Diese Trennung von Frames durch Linien vereinfacht die Programmierung von Animationen erheblich.
Die Größe dieses Bildes beträgt 384 x 384 und die Größe jedes Rahmens beträgt 96 x 96. Leider hat uns die direkte Verwendung dieses Bildes mit Artefakten verärgert: Einige Frames des Bildes sind so platziert, dass ihre Kanten auf benachbarte Frames fallen, und während der Animation blinken gelbe Striche an den Rändern des Sprites.
Um diese Mängel zu beheben, habe ich den kostenlosen plattformübergreifenden grafischen Editor 
GIMP ( 
offizielle Seite ) verwendet. Alles, was getan werden musste, war, die hervorstehenden Pixel der Bilder an den Stellen zu entfernen, an denen sie auf den angrenzenden Rahmen fielen.
Die korrigierte Datei sieht folgendermaßen aus:

- Mit bloßem Auge sind die Unterschiede unsichtbar, aber die zweite Option funktioniert ohne Artefakte.
Erstellen Sie ein neues Projekt
1. Erstellen Sie ein neues Projekt vom Typ „Anwendung“.
Standardmäßig erstellt die IDE ein Projekt mit dem Namen "project1", das sofort ein Programmmodul mit dem Namen "unit1" erstellt, eine Klasse mit dem Namen "TForm1" beschreibt und eine Instanz mit dem Namen "Form1" deklariert.
Im Allgemeinen weist die IDE beim Erstellen neuer Objekte ihnen ähnliche Namen zu, die aus dem Namen des Objekttyps und der Seriennummer bestehen. Ich halte es für einen guten Stil, alle diese Objekte umzubenennen und ihnen aussagekräftige Namen zu geben, die die Rolle oder den Zweck des Objekts widerspiegeln.
Unser Projekt heißt also nicht "Projekt1", sondern "Phoenix" - entsprechend dem Namen des ausgewählten Sprites.
2. Speichern Sie unser neues Projekt.
Es ist ratsam, jedes Projekt in einem separaten Verzeichnis mit einem Namen zu speichern, der dem Namen des Projekts entspricht. Beim Speichern geben wir das zu speichernde Verzeichnis an (ggf. erstellen wir es genau dort), dann den Namen der Projektdatei und den Dateinamen des Programmmoduls. Ich habe den Ordner „Phoenix“ erstellt und dort die Projektdatei („Phoenix.lpi“ anstelle der vorgeschlagenen „project1.lpi“) und die Programmmoduldatei („UnitMain.pas“ anstelle der vorgeschlagenen „unit1.pas“) gespeichert.
Charakterfall NuanceDie Lazarus-Version für Windows führt den Dateinamen des Programmmoduls in Kleinbuchstaben: "unitmain.pas", aber der Programmname des Moduls behält die ursprüngliche Groß- und Kleinschreibung der Zeichen bei: "unit UnitMain;". Dies ist bei der Projektdatei nicht der Fall, da der Dateiname den ursprünglichen Fall von Zeichen beibehält.
 3. Benennen Sie das Formular um und ändern Sie den Titel.
Das neu erstellte Formular mit dem Namen "Form1" ( 
Name- Eigenschaft) ist eine Instanz der Klasse "TForm1" und enthält den Titel "Form1" ( 
Caption- Eigenschaft). Ändern Sie die 
Name- Eigenschaft des Formulars in "FormMain", und der Klassenname ändert sich in "TFormMain".
Ändern Sie die 
Caption- Eigenschaft in "Phoenix", sodass der Projekttitel im Fenstertitel angezeigt wird.
4. Als Ergebnis habe ich den folgenden Text des Moduls unitmain.pas erhalten:
unit UnitMain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs; type TFormMain = class(TForm) private public end; var FormMain: TFormMain; implementation {$R *.lfm} end. 
5. Kompilieren Sie das Projekt, führen Sie es aus (Taste <F9>):

Setzen Sie das Sprite auf das Formular
Angenommen, Sie haben bereits die 
TImageFragment- Komponente 
installiert , die in meinem vorherigen 
Lazarus- Artikel beschrieben wurde. 
Wir schreiben eine Komponente für die Sprite-Animation , wählen die Registerkarte "Spiel" in der Komponentenpalette aus und fügen dem Formular die Komponente "TImageFragment" hinzu.
Laden Sie mit der 
Picture- Eigenschaft ein Bild (eine feste Version des Phoenix-Vogels) in die Komponente. Darüber hinaus ändern wir auch die folgenden Eigenschaften des neuen Objekts:
- Setzen Sie die Eigenschaften Höhe und Breite auf 96
- Setzen Sie die Eigenschaften Links und Oben auf 0 (praktisch für den Abgleich mit meinen Screenshots).
- Die Namenseigenschaft wird von "ImageFragment1" in ein einfaches und verständliches "Sprite" geändert.
Wenn alles richtig gemacht wurde, zeigt die Komponente den ersten Frame des Bildes:

Der Text des 
UnitMain- Moduls wird geringfügig geändert:
- Das 
ImageFragment- Modul wird dem 
Verwendungsabschnitt hinzugefügt
 uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ImageFragment; 
- In der Klassendeklaration wird ein neues Objekt angezeigt
  TFormMain = class(TForm) Sprite: TImageFragment; private public end; 
Animation hinzufügen - Flügelklappen
1. Fügen Sie dem 
Formular eine neue Komponente der 
TTimer- Klasse hinzu.
Diese Komponente befindet sich auf der Registerkarte „System“ der Komponentenpalette. Sie können es an einer beliebigen Stelle im Formular platzieren, da es in einer laufenden Anwendung nicht angezeigt wird.
2. Benennen Sie das hinzugefügte Objekt um.
Das neue Objekt erhält automatisch den Namen "Timer1", aber wir benennen es in "TimerLive" um. Es ist oft zweckmäßig, Objekten solche Namen zu geben, die aus zwei Teilen bestehen: Der erste spiegelt die Klasse des Objekts wider und der zweite spiegelt seinen Zweck wider.
3. Ändern Sie die 
Interval- Eigenschaft von 1000 in 100.
Lassen Sie die Frames dieser Animation alle 100 Millisekunden, dh 10 Mal pro Sekunde, einander ersetzen. In Zukunft kann diese Eigenschaft geändert werden, um die Spannweite zu verlangsamen oder zu beschleunigen - nach Ermessen des Programmierers.
4. Fügen Sie einen OnTimer-Ereignishandler hinzu.
Der einfachste Weg, dies zu tun, besteht darin, auf das Symbol des neuen 
TimerLive- Objekts zu 
doppelklicken . Als Ergebnis dieser Aktion fügt die IDE selbst der Formularklassendeklaration eine neue Prozedur hinzu, eine Verknüpfung zu dieser Prozedur mit den Objekteigenschaften, und der Hauptteil der neuen Prozedur wird dem 
Implementierungsabschnitt hinzugefügt (und der Cursor wird innerhalb dieser neuen Prozedur zwischen den 
Schlüsselwörtern begin und 
end platziert ).
5. Fügen Sie der neuen Prozedur eine Codezeile hinzu.
  Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; 
Als Ergebnis dieser Aktionen sollte die Klassendeklaration ungefähr so aussehen:
  TFormMain = class(TForm) Sprite: TImageFragment; TimerLive: TTimer; procedure TimerLiveTimer(Sender: TObject); private public end; 
Und die neue Prozedur - der 
OnTimer- Ereignishandler sollte 
ungefähr so aussehen:
 procedure TFormMain.TimerLiveTimer(Sender: TObject); begin Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; end; 
Nach dem Kompilieren und Ausführen der Anwendung können Sie beobachten, wie der Phoenix-Vogel mit den Flügeln schlägt.
Dies liegt daran, dass der Timer-Ereignishandler alle 100 Millisekunden zyklisch den Versatz des angezeigten Fragments ändert und der ausgewählte Frame horizontal verschoben wird und nacheinander 4 Frames der obersten Zeile des geladenen Bildes anzeigt. Die 
Mod- Operation - den Rest der Teilung erhalten - verhindert, dass der Versatz über die Bildgröße hinausgeht, und infolgedessen folgt auf den 4. Frame erneut der 1. Frame.
Fügen Sie eine Sprite-Bewegung um das Fenster hinzu
1. Fügen Sie das 
Mathematikmodul zum 
Verwendungsabschnitt hinzu uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math; 
2. Fügen Sie der Klassendeklaration eine neue Variable und Konstante hinzu.
Fügen Sie eine Variable vom Typ 
TPoint hinzu, um den Vektor zum Verschieben des Sprites im Fenster zu 
speichern  private FVector: TPoint; 
An derselben Stelle deklarieren wir eine Konstante zur Definition des Geschwindigkeitsmoduls
  const Speed = 10; 
3. Fügen Sie dem 
Formular eine weitere Komponente der 
TTimer- Klasse hinzu.
Ich erinnere Sie daran: Diese Komponente befindet sich auf der Registerkarte „System“ der Komponentenpalette.
Das neue Objekt erhält automatisch wieder den Namen "Timer1" und wir benennen ihn um - diesmal in "TimerMove". Der Zweck des zweiten Timers besteht darin, die Bewegung des Sprites zu steuern. Ich habe nicht beide Prozesse (Animation und Bewegung) an denselben Timer gebunden, sodass jeder Timer separat eingestellt werden konnte - zum Beispiel, um die Häufigkeit von Flügelschwüngen zu verlangsamen, ohne die Bewegung zu verlangsamen, und so weiter.
4. Ändern Sie die 
Interval- Eigenschaft von 1000 in 100.
Lassen Sie diesen Timer auch alle 100 Millisekunden, dh 10 Mal pro Sekunde, auslösen. In Zukunft kann diese Eigenschaft auch geändert werden, um die Häufigkeit des Renderns der Bewegung des Sprites zu verlangsamen oder zu beschleunigen.
5. Fügen Sie einen 
OnTimer- Ereignishandler hinzu.
Zur Abwechslung schlage ich diesmal vor, dies durch Doppelklicken gegenüber dem 
OnTimer- Ereignis auf der Registerkarte "Ereignisse" des neuen 
TimerMove- Objekts zu 
tun . Als letztes Ergebnis dieser Aktion fügt die IDE selbst der Formularklassendeklaration eine neue Prozedur hinzu, eine Verknüpfung zu dieser Prozedur mit den Objekteigenschaften, und der Hauptteil der neuen Prozedur wird dem 
Implementierungsabschnitt hinzugefügt (und der Cursor wird innerhalb dieser neuen Prozedur zwischen den Schlüsseln platziert Wörter 
beginnen und 
enden ).
6. Fügen Sie der neuen Prozedur zwei Codezeilen hinzu.
  Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y)); 
Die Verwendung der Funktionen Max () und Min () verhindert, dass das Sprite das Formular (das Hauptanwendungsfenster) verlässt.
Für die Verwendung dieser Funktionen haben wir das 
Math- Modul mit dem 
Verwendungsabschnitt verbunden .
7. Fügen Sie einen 
OnKeyPress- Ereignishandler hinzu.
Wählen Sie das Formular aus (klicken Sie auf das graue Rechteck des Fensterlayouts außerhalb aller hinzugefügten Komponenten) und auf der Registerkarte Ereignisse finden Sie das 
OnKeyPress- Ereignis. Durch Doppelklick auf den leeren Wert des Ereignishandlers erstellen wir eine neue Prozedur und weisen sie zu - den Ereignishandler.
8. Fügen Sie der neuen Prozedur einige Codezeilen hinzu.
  if Key = 'a' then FVector := TPoint.Create(-Speed, 0) else if Key = 'd' then FVector := TPoint.Create(Speed, 0) else if Key = 'w' then FVector := TPoint.Create(0, -Speed) else if Key = 's' then FVector := TPoint.Create(0, Speed) else if Key = ' ' then FVector := TPoint.Create(0, 0); 
Als Ergebnis dieser Aktionen sollte die Klassendeklaration ungefähr so aussehen:
  TFormMain = class(TForm) Sprite: TImageFragment; TimerMove: TTimer; TimerLive: TTimer; procedure FormKeyPress(Sender: TObject; var Key: char); procedure TimerLiveTimer(Sender: TObject); procedure TimerMoveTimer(Sender: TObject); private FVector: TPoint; const Speed = 10; public end; 
Und die neuen Verfahren - 
OnTimer- und 
OnKeyPress- Ereignishandler sollten 
ungefähr so aussehen:
 procedure TFormMain.TimerMoveTimer(Sender: TObject); begin Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y)); end; procedure TFormMain.FormKeyPress(Sender: TObject; var Key: char); begin if Key = 'a' then FVector := TPoint.Create(-Speed, 0) else if Key = 'd' then FVector := TPoint.Create(Speed, 0) else if Key = 'w' then FVector := TPoint.Create(0, -Speed) else if Key = 's' then FVector := TPoint.Create(0, Speed) else if Key = ' ' then FVector := TPoint.Create(0, 0); end; 
Nach dem Kompilieren und Ausführen der Anwendung können Sie den Phoenix-Vogel mit den Tasten „a“, „w“, „s“, „d“ über den Bildschirm bewegen und mit der Leertaste anhalten.
Wir verwenden verschiedene Projektionen des Sprites
Fügen Sie den folgenden Code am Ende der Prozedur 
TFormMain.FormKeyPress hinzu  if FVector.x < 0 then Sprite.OffsetY := 96 else if FVector.x > 0 then Sprite.OffsetY := 192 else if FVector.y < 0 then Sprite.OffsetY := 288 else Sprite.OffsetY := 0; 
Durch Ändern der 
OffsetY- Eigenschaft in Abhängigkeit vom Verschiebungsvektor wird das Bild in Bewegungsrichtung gedreht.
Alle UnitMain-Modultext unit UnitMain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math; type  TFormMain = class(TForm) Sprite: TImageFragment; TimerMove: TTimer; TimerLive: TTimer; procedure FormKeyPress(Sender: TObject; var Key: char); procedure TimerLiveTimer(Sender: TObject); procedure TimerMoveTimer(Sender: TObject); private FVector: TPoint; const Speed = 10; public end; var FormMain: TFormMain; implementation {$R *.lfm}  procedure TFormMain.TimerLiveTimer(Sender: TObject); begin Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; end; procedure TFormMain.TimerMoveTimer(Sender: TObject); begin Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y)); end; procedure TFormMain.FormKeyPress(Sender: TObject; var Key: char); begin if Key = 'a' then FVector := TPoint.Create(-Speed, 0) else if Key = 'd' then FVector := TPoint.Create(Speed, 0) else if Key = 'w' then FVector := TPoint.Create(0, -Speed) else if Key = 's' then FVector := TPoint.Create(0, Speed) else if Key = ' ' then FVector := TPoint.Create(0, 0); if FVector.x < 0 then Sprite.OffsetY := 96 else if FVector.x > 0 then Sprite.OffsetY := 192 else if FVector.y < 0 then Sprite.OffsetY := 288 else Sprite.OffsetY := 0; end; end. 
 Anstelle eines Nachwortes
Dieses einfache Beispiel beansprucht keine hohen Bewertungen für Geschwindigkeit oder Benutzerfreundlichkeit. Wenn jemand, wie im 
vorherigen Artikel , in den Kommentaren mitteilen möchte, dass die Animation falsch ausgeführt werden muss - begrüßen Sie, schreiben Sie Ihren Artikel. In diesem Artikel geht es darum, wie Sie Animationen in mehreren Codezeilen erstellen können, ohne spezielle Bibliotheken zu verwenden, praktisch „auf dem Knie“. Diese Methode wurde in der Praxis getestet und funktioniert wirklich. Bevor Sie kritisieren und „minus“, lesen Sie bitte noch einmal, worum es in diesem Artikel geht und warum.