Au lieu de l'avant-propos
Dans mon récent article
Lazarus - écrivant un composant pour l'animation de sprite, j'ai décrit le processus de création d'un simple composant
TImageFragment qui vous permet d'afficher un fragment donné d'une image.
Poursuivant le sujet sélectionné, dans cet article, je veux montrer à quel point il est facile de faire de l'animation de sprites dans l'environnement de développement
Lazarus (
site officiel ) en utilisant ce composant.
Avec cette approche, des images d'animation individuelles dans différentes projections sont placées sur la même image, et le composant pour afficher l'image-objet n'affiche qu'un seul fragment sélectionné de cette image en utilisant les propriétés
OffsetX et
OffsetY (décalage du coin supérieur gauche du fragment d'image horizontalement et verticalement).
Beaucoup de ces images toutes faites peuvent être trouvées sur le Web - par exemple,
ici sur ce site .
Sélectionnez (et préparez) l'image
Pour mon exemple, j'ai choisi cette image:

- très expressivement cet oiseau Phoenix bat des ailes.
Comme vous pouvez le voir, chaque ligne contient 4 images pour chacune des 4 projections. En changeant uniquement
OffsetX , vous pouvez faire
battre l'aile de l'oiseau, et pour changer la projection, il suffit de changer
OffsetY . Cette séparation des images par des lignes simplifie considérablement la programmation de l'animation.
La taille de cette image est de 384x384 et la taille de chaque image est de 96x96. Malheureusement, l'utilisation directe de cette image nous a dérangé avec des artefacts: certaines images de l'image sont placées de sorte que leurs bords tombent sur des images adjacentes, et pendant l'animation, des traits jaunes clignotent sur les bords de l'image-objet.
Pour corriger ces défauts, j'ai utilisé l'éditeur graphique multiplateforme gratuit
GIMP (
site officiel ). Tout ce qui devait être fait était de supprimer les pixels saillants des images aux endroits où ils tombaient sur le cadre adjacent.
Le fichier corrigé ressemble à ceci:

- À l'œil nu, les différences sont invisibles, mais la deuxième option fonctionne sans artefacts.
Créer un nouveau projet
1. Créez un nouveau projet de type «Application».
Par défaut, l'EDI crée un projet appelé «project1», qui crée immédiatement un module de programme appelé «unit1», qui décrit une classe appelée «« TForm1 »et déclare une instance avec le nom« Form1 ».
En général, lors de la création de nouveaux objets, l'EDI leur attribue des noms similaires, composés du nom du type d'objet et du numéro de série. Je considère que c'est un bon style de renommer tous ces objets, en leur donnant des noms significatifs qui reflètent le rôle ou le but de l'objet.
Ainsi, notre projet ne sera pas appelé «project1», mais «Phoenix» - par le nom du sprite sélectionné.
2. Enregistrez notre nouveau projet.
Il est conseillé de sauvegarder chaque projet dans un répertoire séparé avec un nom qui correspond au nom du projet. Pendant le processus de sauvegarde, nous spécifions le répertoire à sauvegarder (si nécessaire, nous le créons juste là), puis le nom du fichier projet et le nom du fichier du module programme. J'ai créé le dossier «Phoenix» et y ai enregistré le fichier de projet («Phoenix.lpi» au lieu du «project1.lpi» proposé) et le fichier de module de programme («UnitMain.pas» au lieu du «unit1.pas» proposé).
Nuance de casse de caractèreLa version Lazarus pour Windows conduit le nom de fichier du module de programme en minuscules: "unitmain.pas", mais le nom de programme du module conserve la casse d'origine des caractères: "unit UnitMain;". Cela ne se produit pas avec le fichier de projet; le nom du fichier conserve la casse d'origine des caractères.
3. Renommez le formulaire et changez son titre.
Le formulaire nouvellement créé, appelé «Form1» (propriété
Name ), est une instance de la classe «TForm1» et contient le titre «Form1» (propriété
Caption ). Modifiez la propriété
Name du formulaire en «FormMain» et le nom de la classe changera en «TFormMain».
Remplacez la propriété
Caption par «Phoenix» afin que le titre du projet s'affiche dans le titre de la fenêtre.
4. En conséquence, j'ai obtenu le texte suivant du module unitmain.pas:
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. Compilez, exécutez le projet (touche <F9>):

Mettez le sprite sur le formulaire
En supposant que vous avez déjà installé le composant
TImageFragment décrit dans mon précédent article
Lazarus - nous écrivons un composant pour l'animation de sprite , sélectionnez l'onglet «Jeu» sur la palette de composants et ajoutons le composant «TImageFragment» au formulaire.
À l'aide de la propriété
Picture , chargez une image (une version fixe de l'oiseau Phoenix) dans le composant. De plus, nous modifions également les propriétés suivantes du nouvel objet:
- définissez les propriétés Height et Width sur 96
- définir les propriétés Left et Top sur 0 (pratique pour faire correspondre mes captures d'écran)
- La propriété de nom est changée de l'incommode "ImageFragment1" à un "Sprite" simple et compréhensible
Si tout est fait correctement, le composant affichera la première image de l'image:

Le texte du module
UnitMain subira des modifications mineures:
- le module
ImageFragment est ajouté à la section
utilisations uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ImageFragment;
- un nouvel objet apparaîtra dans la déclaration de classe
TFormMain = class(TForm) Sprite: TImageFragment; private public end;
Ajouter une animation - volets d'aile
1. Ajoutez un nouveau composant de la classe
TTimer au
formulaire .
Ce composant est situé sur l'onglet «Système» de la palette de composants. Vous pouvez le placer à n'importe quel endroit pratique du formulaire, car il ne s'affiche pas dans une application en cours d'exécution.
2. Renommez l'objet ajouté.
Le nouvel objet prend automatiquement le nom «Timer1», mais nous le renommons «TimerLive». Il est souvent commode de donner aux objets de tels noms, composés de deux parties: la première reflète la classe de l'objet et la seconde reflète son objectif.
3. Modifiez la propriété
Intervalle de 1000 à 100.
Laissez les images de cette animation se remplacer toutes les 100 millisecondes, c'est-à-dire 10 fois par seconde. À l'avenir, cette propriété peut être modifiée pour ralentir ou accélérer l'envergure - à la discrétion du programmeur.
4. Ajoutez un gestionnaire d'événements OnTimer.
La façon la plus simple de le faire est de double-cliquer sur l'icône d'un nouvel objet
TimerLive . À la suite de cette action, l'EDI lui-même ajoutera une nouvelle procédure à la déclaration de classe de formulaire, un lien vers cette procédure vers les propriétés de l'objet et le corps de la nouvelle procédure sera ajouté à la section d'
implémentation (et le curseur sera placé à l'intérieur de cette nouvelle procédure, entre les
mots-clés de début et de
fin ).
5. Ajoutez une ligne de code à la nouvelle procédure.
Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384;
À la suite de ces actions, la déclaration de classe devrait ressembler à ceci:
TFormMain = class(TForm) Sprite: TImageFragment; TimerLive: TTimer; procedure TimerLiveTimer(Sender: TObject); private public end;
Et la nouvelle procédure - le
gestionnaire d' événements
OnTimer devrait ressembler à ceci:
procedure TFormMain.TimerLiveTimer(Sender: TObject); begin Sprite.OffsetX := (Sprite.OffsetX + 96) mod 384; end;
Après avoir compilé et exécuté l'application, vous pouvez regarder l'oiseau Phoenix battre des ailes.
Cela se produit car le gestionnaire d'événements du minuteur change toutes les 100 millisecondes de manière cyclique le décalage du fragment affiché et la trame sélectionnée est décalée horizontalement, affichant séquentiellement 4 trames de la ligne supérieure de l'image chargée. L'opération de
mod - obtenir le reste de la division - empêche le décalage d'aller au-delà de la taille de l'image, et par conséquent, la 4ème image est à nouveau suivie par la 1ère.
Ajoutez un mouvement de sprite autour de la fenêtre
1. Ajoutez le module
Math à la section
uses uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, ImageFragment, Math;
2. Ajoutez une nouvelle variable et constante à la déclaration de classe.
Pour enregistrer le vecteur de déplacement du sprite autour de la fenêtre, ajoutez une variable de type
TPoint private FVector: TPoint;
Au même endroit, on déclare une constante pour définir le module de vitesse
const Speed = 10;
3. Ajoutez un autre composant de la classe
TTimer au
formulaire .
Je vous rappelle: ce composant est dans l'onglet «Système» de la palette des composants.
Le nouvel objet obtient de nouveau automatiquement le nom «Timer1», et nous le renommons - cette fois en «TimerMove». Le second temporisateur a pour but de contrôler le mouvement du sprite. Je n'ai pas lié les deux processus (animation et mouvement) à la même minuterie afin que chacun des temporisateurs puisse être réglé séparément - par exemple, pour ralentir la fréquence des oscillations des ailes sans ralentir le mouvement, etc.
4. Modifiez la propriété
Intervalle de 1000 à 100.
Laissez cette minuterie se déclencher également toutes les 100 millisecondes, c'est-à-dire 10 fois par seconde. À l'avenir, cette propriété peut également être modifiée pour ralentir ou accélérer la fréquence de rendu du fait que le sprite se déplace.
5. Ajoutez un
gestionnaire d' événements
OnTimer .
Pour changer, cette fois, je propose de le faire en double-cliquant en face de l'événement
OnTimer sur l'onglet "Evénements" du nouvel objet
TimerMove . Comme la dernière fois, à la suite de cette action, l'EDI lui-même ajoutera une nouvelle procédure à la déclaration de classe de formulaire, un lien vers cette procédure vers les propriétés de l'objet et le corps de la nouvelle procédure sera ajouté à la section d'
implémentation (et le curseur sera placé à l'intérieur de cette nouvelle procédure, entre la clé les mots
commencent et se
terminent ).
6. Ajoutez deux lignes de code à la nouvelle procédure.
Sprite.Left := Max(0, Min(Width - Sprite.Width, Sprite.Left + FVector.x)); Sprite.Top := Max(0, Min(Height - Sprite.Height, Sprite.Top + FVector.y));
L'utilisation des fonctions Max () et Min () empêche le sprite de quitter le formulaire (la fenêtre principale de l'application).
C'est pour utiliser ces fonctions que nous avons connecté le module
Math à la section
uses .
7. Ajoutez un
gestionnaire d' événements
OnKeyPress .
Sélectionnez le formulaire (cliquez sur le rectangle gris de la disposition de la fenêtre en dehors de tous les composants ajoutés) et sur l'onglet Événements, nous trouvons l'événement
OnKeyPress . En double-cliquant sur la valeur vide du gestionnaire d'événements, nous créons et attribuons une nouvelle procédure - le gestionnaire d'événements.
8. Ajoutez quelques lignes de code à la nouvelle procédure.
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);
À la suite de ces actions, la déclaration de classe devrait ressembler à ceci:
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;
Et les nouvelles procédures - les gestionnaires d'événements
OnTimer et
OnKeyPress devraient ressembler à ceci:
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;
Après avoir compilé et exécuté l'application, vous pouvez déplacer l'oiseau Phoenix sur l'écran à l'aide des touches «a», «w», «s», «d» et l'arrêter avec la barre d'espace.
Nous utilisons différentes projections du sprite
Ajoutez le code suivant à la fin de la procédure
TFormMain.FormKeyPress 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;
La modification de la propriété
OffsetY en fonction du vecteur de déplacement entraîne la rotation de l'image dans le sens du mouvement.
Tout le texte du module UnitMain 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.
Au lieu d'une postface
Cet exemple simple ne revendique pas des cotes élevées de vitesse ou de convivialité. Si quelqu'un, comme dans l'
article précédent , veut dire dans les commentaires que l'animation doit être mal faite - bienvenue, écrivez votre article. Et le sujet de cet article est de savoir comment créer une animation sur plusieurs lignes de code, sans utiliser de bibliothèques spéciales, pratiquement "à genoux". Cette méthode a été testée dans la pratique, elle fonctionne vraiment, donc avant de critiquer et de «moins», veuillez relire en quoi consiste cet article et pourquoi.