|
|||||
|
|||||
Dans tous les jeux "Professionnels"
qui utilisent des Sprites il existe un moteur (programme spécialement
conçu pour réaliser des déplacements d'images en
tenant compte de l'image de fond, de la vitesse de déplacement
, des collisions, des animations... et de bien d'autres effets). Nous
n'allons pas prendre en compte tous ses paramètres et nous concentrer
sur le Déplacement...
|
. |
Essai 1: Déplacement vers la droite, géré dans une boucle. |
Paintbox1 = contient l'image de fond (Tpaintbox) |
Image1 = contient l'image à déplacer (Timage) |
Image2 = contient l'image de fond (Timage) |
Paintbox1.canvas.draw(0,0,image2.picture.bitmap); // copier l'image de fond dans le paintbox |
for i:=1 to 50 do |
begin |
Paintbox1.canvas.draw(100+i,200,image1.picture.bitmap); //mon image est un BMP |
end; |
Notez que si votre image est un Bmp utilisez Image.Picture.Bitmap , si c'est un Jpeg utilisez Image.Picture.Graphic |
.C'est simple mais le dessin déplacé efface l'image de fond et laisse une trace derrière lui |
. |
Question : Pourquoi réaliser le déplacement dans un Paintbox ?? |
Je déconseille d'utiliser le canvas d'une form pour effectuer des déplacements d'images... pourquoi ?? autant prendre de bonnes habitudes dès le départ, voici quelques arguments (mais rien ne vous y oblige ;): |
- Si en cours de développement on préfère présenter l'animation ailleurs, il suffit de déplacer le Paintbox. Si on affiche directement sur le Canvas de la Form il faut modifier toutes les coordonnées...gallère, temps perdu, risque d'erreurs... et j'en passe. |
- Dans de nombreux jeu, le plateau de jeu ne couvre pas toute la Form et une partie est réservée à l'affichage d'informations (score, nombre de vies, Boutons de commandes...). Il devient alors indispensable de gérer l'effacement de notre Image lorsqu'elle sort du plateau de jeu, et si possible de façon progressive... hein ??? ben oui plus elle sort et moins on en voit...ha!! En d'autres termes se prendre la tête. L'interêt d'utiliser un Paintbox c'est que ce probléme se résoud de lui même !!! Comment mais tout simplement parce qu'on fait afficher sur le Canvas du Paintbox qui n'est pas le même que celui de la Form... donc si votre Image commence à sortir du Paintbox elle sera automatiquement coupée ... cool !!! j'ai plus à gérer visuellement la sortie du plateau de jeu... |
. |
Question : Pourquoi ne pas utiliser un Timage au lieu d'un Tpaintbox ?? |
Personnellement je préfère utiliser un Tpaintbox ce qui me permet de savoir de suite sur quoi je travaille: une image à déplacer (Timage) ou sur le plateau de jeu (TPaintbox)...oui c'est vrais il est très simple de renommer les composants...bref c'est Mon choix à vous de faire le votre. |
. |
Essai 2: Déplacement vers la droite, géré dans une boucle sans effacer le fond. |
Paintbox1.canvas.draw(0,0,image2.picture.bitmap); // copier l'image de fond dans le paintbox |
for i:=1 to 50 do |
begin |
Paintbox1.canvas.draw(0,0,image2.picture.bitmap); // copier l'image de fond dans le paintbox |
Paintbox1.canvas.draw(100+i,200,image1.picture.bitmap); //mon image est un BMP |
end; |
Noter que la première opération que je réalise est de placer le fond, puis de placer mon image. Si dans cet exemple ce n'est pas évident il faut avoir cette habitude.(placer le fond puis tous les éléments qui se trouvent dessus) |
C'est déjà beaucoup mieux... mais comment dire ? le déplacement se fait bien mais il y a des décalages qui se produisent parfois dans l'image à déplacer ,ce qui donne l'impression que l'affichage n'est pas stable. C'est tout simplement le balayage de l'écran qui n'est pas syncro avec l'affichage de votre image (il faudrait ajouter dans la boucle d'affichage un test pour attendre que le faiseau d'électrons finisse de balayer l'écran pour faire un nouvel affichage). |
Enfin utiliser un outil qui vous permet de voir la charge de votre processeur (dans le gestionaire des tâches ou le programme CPU Plus que j'ai réalisé) pour voir ce qui se passe lorsque votre programme tourne... Votre processeur est fortement utilisé (surtout si vous travaillez avec de grosses images). Inutile de dire qu'un jeu posséde des dizaines d'images et qu'il devient alors impossible d'utiliser cette technique sans faire ramer votre jeu voire à le rendre injouable. |
.. |
Question : Est il utile de faire ré-afficher toute l'image de fond alors que l'image qui bouge est plus petite ??? |
Non, bien sûr, mais comment faire...???. |
. |
Essai 3 : Enlever les effets d'affichage indésirables. |
Tout d'abord la commande COPYRECT(rect1,image2,rect2) qui permet de copier un morceau d'image. |
rect1,rect2 :Trect; |
il faut renseigner rect1.top, rect1.left, rect1.bottom, rect1.right pour présiser où va s'afficher rect2.top,rect2.left,rect2.bottom, rect2.right de l'image Image2. En fait rect1 = rect2 puisque ces 2 images ont la même taille et ont la même position (comme nous allons le voir plus loin...) |
Nous allons transférer le morceau d'image de fond qui correspond à notre dessin pour l'afficher dessus et donc l'effacer (ce qui nous évitera de réafficher toute l'image..gros gain de temps et de puissance machine!!!), il ne restera plus qu'à réafficher notre image.... |
Oui mais... ce système marche bien avec 2 images (un fond + une image) mais il reste un clignotement parasite s'il y a plusieurs images à déplacer en même temps, et qu'elles se superposent. Cela est dû aux séries d'effacements + affichages qui se superposent. |
Plutôt que d'afficher avec la commande Copyrect le fond directement dans notre Paintbox nous allons utiliser un bitmap de manoeuvre appelé Fond_de_Travail pour y effectuer tous nos déplacements de manière cachée. Quand tout sera prêt, nous afficherons en une seule dans la paintbox le contenu du Fond de travail. C'est le principe de DelphiX, DirectX.... |
var |
Fond_de_Travail:Tbitmap; |
... |
// dans l'initiallisation de la form |
Fond_de_travail:=Tbitmap.create; |
Fond_de_travail.Assign(image2.Picture.Bitmap); // Graphic si c'est un jpeg |
... |
// dans notre boucle d'affichage |
For i:=1 to 50 do |
Begin |
Fond_de_travail.Assign(image2.Picture.Bitmap); //copie de l'image de fond dans celle de travail |
Fond_de_travail.canvas.draw(0,0,image2.picture.bitmap); // rien ne s'affiche à l'écran |
Paintbox1.canvas.draw(0,0,Fond_de_travail); // basuler sur le réel |
end; |
... |
// avant de quitter |
Fond_de_travail.free // libérer la mémoire |
C'est déjà beaucoup mieux, l'image qui se déplace est très stable et glisse sans effets indésirables....mais si on regarde du côté du processeur on s'apperçoit que si nous avons gagné en qualité d'affichage, nous n'avons pas amélioré la charge machine. Certains d'entre vous se dirons "mais il a oublié d'utiliser la commande copyrect !!!" .. et bien, oui ! pour bien comprendre il faut procéder étape par étape. Voici donc le même programme optimisé avec la commande copyrect. |
. |
Essai 4 : Enfin nous y voilà... le Copyrect |
var |
x:integer; // coordonnées X de notre image |
y:integer; // coordonnées Y de notre image |
Fond_de_Travail:Tbitmap; |
image1:TBitmap; // notre image de fond |
image2:TBitmap; // image à déplacer |
... |
// dans l'initiallisation de la form |
Fond_de_travail:=Tbitmap.create; |
Fond_de_travail.Assign(image2.Picture.Bitmap); // Graphic si c'est un jpeg |
x:=0; y:=50; // initialisation de la position de l'image |
... |
// dans notre boucle d'affichage |
For i:=1 to 50 do |
Begin |
rect1.left:=x+i; // décalement de l'image de 1 pixel vers la droite |
rect1.top:=y; |
rect1.bottom:=rect1.top+image1.height; // ajouter la hauteur de l'image |
rect1.right:=rect1.left+image1.width; // ajouter la hauteur de notre image |
Fond_de_travail.canvas.copyrect(rect1,image1.canvas,rect1); // copie du morceau du fond qui nous interesse |
// c'est ici qu'il faudra ajouter les copyrect des autres images à déplacer dans fond_de_travail |
// avant de basuler dans le réel |
Fond_de_travail.canvas.draw(x,y,image2.picture.bitmap); //mettre notre image |
Paintbox1.canvas.draw(0,0,Fond_de_travail); // basculer sur le réel dans le paintbox |
end; |
... |
// avant de quitter |
Fond_de_travail.free // libérer la mémoire |
. |
Alors, verdict ??? et bien notre image bouge bien sans clignotement et la charge du processeur à considerablement baissée, ce qui va nous permettre de faire d'autres choses (gestion des collisions,...) . |
. |
Améliorations possibles : |
Elles sont très nombreuses. Le but de ce tutoriel étant de mettre en évidence le mécanisme de recouvrement mis en place dans un déplacement... |
Dans un jeu les déplacements sont gérés
dans un Timer pour permettre à d'autres tâches de s'exécuter
en même temps. Il peut aussi être judicieux de créer
une Classe dérivée de notre Tbitmap et à laquelle
on ajouter les paramétres de coordonnées, de vitesse...
et tout ce qui peut être utile à notre Sprite...
En résumé:
3) En fin de travail (formdestroy) n'oubliez pas de désallouer les 2 grands bitmaps par Fond_de_travail .free, image1.free et toute autre bitmap alloué dynamiquement par Tbitmap.create. |
. |
La super astuce |
Votre jeu utilise cette technique
mais les déplacements sont lent...essayez d'accélérer
le Timer en indiquant la valeur la plus petite possible. La valeur
implicite est de 1000 milisecondes = 1 seconde. Si votre Timer
est positionné à 1 miliseconde (le minimum) et que c'est
toujours lent , c'est qu'en fait le timer ne descend pas en dessous de 50
ms. C'est le plus souvent insuffisant pour une animation fluide.
Les solutions: procedure
TForm1.Timer1Timer(Sender: TObject); |
Cette méthode à ses limites... elle est légèrement moins performante que DelphiX ou DirectX qui utilisent des fonctions optimisées et spécialisées, mais elle fonctionne dans une fenêtre windows parfaitement standard.il faut savoir choisir ses outils en fonction de ses besoins....Bon jeu et sutout n'oubliez pas de m'envoyer vos oeuvres ;-) |
. |
Voici 2 exemples de jeux que j'ai réalisé avec cette technique. Ils donnent une bonne idées de ce qu'on peu faire... |
- Ballon (752 Ko) |
- Pongo (1.7 Mo) |