Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
FORUMS DELPHI F.A.Q DELPHI TUTORIELS DELPHI LIVRES COMPOSANTS SOURCES DEFI TELECHARGEZ DELPHI TV


Aide sur delphi X

Par Bodman

---LE COMPOSANT DELPHI X---


DelphiX

Voilà une suite de composants dont on parle assez dans le monde de la programmation et c'est donc pour cela que je m'y suis mis.
Cette suite sert avant tout à faire des jeux mais personne ne vous y oblige, on peut aussi créer d'autre type de programme comme des animations graphiques ou bien autre chose.
Ces composants sont assez simples d'utilisation ils ne réclament pas un grand niveau delphi même s'il faut avoir une connaissance du système de classe qui est assez utilisé.
Nous allons donc supposer que vous savez manier cette technique, mais si ce n'est pas le cas voilà
une brève explication.

Attention ce composant ne fonctionne qu'avec les versions 3,4 et 5 de delphi. Pour faire fonctionnez ce composant sur des version plus recentes voici un liens.

Le but de ce tutorial sera de faire un jeu. Vous le verrez naître à partir de rien si ce n'est une des plus belle suite de composant delphi (pour moi bien sur).

0.L'installation

Vous pouvez télécharger delphiX
ici.
Pour l'installer, il vous suffit d’exécuter dans le répertoire..\Bin\.. le fichier qui correspond à votre version de delphi.
Et voilà c'est fait !!


1. la préparation

Nous allons déjà placer nos composants delphiX et les décrire 1 à 1, je vous conseille de placer vos composants en lisant ce dictaciel.


Notre fiche va devoir contrôler des composants delphi X, va devoir passer en plein écran, et d'autre action graphique qu'elle n'aurait pas l'habitude de faire. Pour que ceci se fasse plus facilement nous allons devoir changer le type de notre form, allez au début de votre unité et sous la rubrique type vous avez ceci :

type
TForm1 = class(TForm)

changer-le en :

type
TForm1 = class(T
DXForm)//La class DXFORM et similaire à la class form si ce n'est quel enlève des problèmes entre les composants delphiX et la fiche, elle requière aussi l'unité DXclass que vous devrez ajouté dans le groupe uses.

Ceci n'est pas obligatoire mais recommandé.

Maintenant nous allons pouvoir poser nos composants :

-DXdraw : le seul composant visuel de la suite, c'est la que passera tout ce que vous afficherez à l'aide des autres composants delphiX.
-DXimagelist : c'est une bibliothèque où vous mettrez toutes les images que vous utiliserez.
-DXtimer : c'est un sosie de notre timer habituel sauf qu'il est spécialement dédié à notre suite delphiX. Il contient plusieurs option en plus et par exemple une option lag count qui permet d’éviter les retards si votre affichage et ralenti pour une raison inconnue car Il est tout de même beaucoup plus rapide(100 fois +) que notre timer d'origine.
-DXsprite : c'est lui qui générera tous les sprites de votre programme, les fera bouger, les détruira.
-DXinput : indique les touches utilisées.

Bon nous allons nous arrêter là et nous décrierons les autres plus tard car ce ne sont pas les seuls, vous l'avez remarqué et en plus j'ai beaucoup de chose à vous faire faire avec ceux la.

Nous allons voir la préparation de tous ces composants pour que votre programme soit près à fonctionner :

DXdraw
dans l'inspecteur d'objet changer ceci :
align = alclient
notre DXdraw aura la même taille que notre fiche (c'est le seul composant visuel que nous ayons ).
Option -- fullscreen = true
pour afficher en plein écran
il faudra aussi enlever les bordures de notre fiche pour quelles n'apparaissent pas en plein écran (
borderstyle = bsnone).
Pour cacher la souris et la remplacer plus tard par une image nous allons utiliser :
dxdraw1.cursor := crnone;//Signifie que le curseur sera invisible
que nous ajoutons dans l’événement create de notre fiche.
Pour ne pas avoir un flash de l’écran à l'ouverture modifier l'autoinitialize en false et dans votre
form1create ajoutez :
Dxdraw1.initialize;//procedure qui prépare l’écran

DXsprite
pour fonctionner ce composant à besoin d'une chose très importante le nom du composant DXdraw, indiquer le lui avec la propriété dxdraw.

DXtimer
la vitesse : là mettez ce que vous voulez mais 33 me semble bien car de toutes manières il est dur d'avoir un rafraîchissement de l'image supérieur à celui-ci.
Votre DXtimer va servir à reinitialiser votre écran et vos sprites ainsi que les touches donc dans sa propriété timer ajoutez :

DXdraw1.Surface.Fill(0); // Supprime tout ce qui composait l’écran.
dxspriteengine1.Move(lagcount);
//execute la procedure onmove de chaque sprite.
dxspriteengine1.dead;
/Détruit les sprites d’on la fonction dead à été activé.
dxspriteengine1.Draw;
//Dessine les sprites
dxdraw1.Surface.Canvas.Release;
//remet à jours le canvas
dxinput1.Update;
//remet à jours les touche tapés car ce composant ne le fais pas seul.
dxdraw1.Flip;
//Remet à jours l’écran


DXimagelist
bibliothèque d'image, vous pourrez y mettre toutes les images que vous voulez .
Vous pourrez rendre ces images en partie invisibles en précisant la couleur des parties invisibles.
Et précisez dxdraw1 dans la propriété dxdraw.
Pour les images, installez plutôt ce fichier
image.dxg qui contient les images utilisées par ce tutorial.(En double cliquant sur le composant et sélectionnant ce fichier vous les aurez).

DXinput
Rien a signaler si ce n'est que si vous voulez vous servir de touches spécifiques ajoutez les en double cliquant sur le composant.



Bon si vous exécutez votre programme à ce moment là vous aurez un écran vide et pour fermer alt + F4 sera la seule solution donc nous allons ajouter une possibilité de fermer avec la touche echap.

Dans le dxinput mettez button1 en echap (double cliquez sur le composant pour le faire) et dans votre timer ajouter:

if isbutton1 in dxinput1.States then
//dxinput.state comporte la liste des touches qui ont été pressées depuis la dernière mise à jours de celle-ci(avec dxinput.update) close; //fermeture de l'application si echap est pressée.

Et voilà c'est tout .

2.Le jeu


Oui nous allons passer au jeu en lui-même .

Alors quel jeu va t’ont faire ?
Euh je sais pas moi?
tiens on va animer des petits animaux, bonne idée, non je déconne!
Ah je sais ! Disons un jeu ou l'on tire sur des bêtes qui sortent de terre.
C'est mieux ça? Bon alors elles ne sortent par de terre elles voleront.
De toutes manières vous n'avez pas le choix c'est moi qui décide et en plus ce n'est qu'un exemple pour qu'à la fin vous puissiez faire votre propre jeu.

3.les sprites

Bien donc commençons.
Les sprites c'est quoi exactement ?
Pour moi, des image animées ou non qui se déplacent ou non et qui réagissent ensemble ou non. Par exemple c'est la fumée de la cheminée dans ZELDA, les combattants dans STREET FIGHTER et aussi la balle et les barres dans PONG.

Donc dans notre jeu quels seront les sprites ?
Et bien il y aura un viseur avec lequel on tirera, un sprite de bête le même pour toutes et il y aura aussi notre fond qui sera un backroundsprite(il sera afficher en mosaïque).
Tout notre jeu sera composé de sprites.
Alors voilà pour créer un sprite il y à plusieurs méthodes, on peut le créer sans rien déclarer mais nous ne pourrons rien en faire, il sera à l’écran et c'est tout aucune collision aucun mouvement,
rien. On peut aussi le déclarer là deux autres possibilités entre en compte.
On peut le créer sans garder de référence, mais utiliser une variable pointeur permet d'accéder facilement à ses propriétés.
Dans les deux cas il pourra bouger et réagir aux collisions.

Notre fond sera créé puis plus jamais nous n'y toucherons donc il sera créé sans avoir été déclarer.
Les ennemis seront créés puis eux non plus ne seront plus jamais utilisés mais ils se déplaceront tout de même donc déclarons les sans leurs attribuer de variable.
Le viseur lui bouge et il faudra pouvoir y accéder lorsque la souris bougera donc déclarons le ainsi qu'une variable de son nom.


4.Le fond

Rien de plus simple pour le créer allons dans l’événement create de notre fiche et ajoutons ces quelques lignes:

with TBackgroundSprite.Create(DXSpriteEngine1.Engine) do
//nous créons un fond et comme une fois créé nous ne pourrons plus y accéder(puisque nous avons aucun pointeur ou variable pour connaître sa position) nous allons utiliser with pour préciser ses propriétés
begin
SetMapSize(1, 1);
//marque la taille du sprite, ici 1 image sur 1.
Image:=Form1.DXImageList1.Items.Find('fond');
//l'image du fond sera celle qui se trouve dans DXImageList1 et qui porte le nom fond
Width := Image.Width;
Height := Image.Height;
//la hauteur et la largeur du sprite seront egals à celles de l'image.
Z := 0;
{Z correspond à la couche sur laquelle est notre image si l'on fait un sprite sur la couche 1 il sera visible mais si ont fait un sprite sur la couche -1 il sera invisible.}
Tile := true
//notre image sera répétée sur tout l’écran.
end;

Voilà vous n'aurez plus rien à y faire le composant spriteengine s'occupe de l'afficher à l’écran si vous avez bien pensé à mettre spritengine.draw dans le timer(ce que nous avons fait au début).
Si vous exécutez vous verrez un joli fond.

Petite précision sur
setmapsize si nous avions mis tile := false alors nous n'aurions eu qu'un exemplaire de notre image et si avec ceci il avait eu setmapsize(2,2) ont aurai eu un rectangle de 2 image sur 2 que composera notre fond.


5.Le viseur

Donc notre viseur devra lui être déclaré car il à certaines propriétés qui devrons être déclarées sous forme de procédure. Alors dans type ajoutons :

Tviseur = class(TImageSprite);


Et dans
var une variable
viseur : Tviseur;
Ensuite pour le créer dans l’événement create de notre fiche de la même manière que notre fond nous allons ajouter :

viseur := Tviseur.Create(DXSpriteEngine1.Engine);
with viseur do
begin
Image:=Form1.DXImageList1.Items.Find('viseur');
//indique l'image
Width := Image.Width;
//reprend la largeur de l'image
Height := Image.Height;
// et sa hauteur ce qui fait correspondre la taille du sprite avec celle de l'image.
Z := 2;
end;

Vous l'avez vue notre
Z est 2 car il faut bien que le viseur soit supérieur au fond, sinon on ne le verrai pas.
Pour le reste pas de problème.

ensuite dans notre
dxdraw dans l’événement onmousemove ajoutons :
viseur.X:= X;
viseur.Y := Y;

et voilà.
Mais pourquoi avoir déclaré un classe intermédiaire nommée Tviseur ?
Quelle est cette procédure si importante?
Vous comprendrez plus tard.

6.Nos petites bêtes

Elle seront mouvantes et au départ elle ne seront pas à l’écran.
On les créera dons à l’extérieur ,hihi pas sur votre table de salon mais toujours dans le canvas de l'écran seulement comme c'est une table de dessin virtuelle on peut dessiner à coté chouette non?

Alors voilà nos
Tenemi(nos bêbête quoi).

Tenemi = class(TImageSprite)
public
sens : boolean;
//variable qui indiquera plus tard le sens de direction de nos bêtes
procedure Domove (movecount : integer); override;
//procédure propre au timagesprite donc utilisons override pour remplacer celle d'origine
end;

Alors vous en dites quoi elles ont un sens de direction et une procedure de déplacement qui sera exécuté à chaque
dxspriteengine1.Move(lagcount); donc tout les temps de millisecondes.

Bon comme nos ennemis seront créés régulièrement nous allons créer une procedure de création d’ennemi.


procedure tform1.creaenemi;//pensez à déclarer procedure creaenemi; dans notre tform
begin
//---------------------UN ENEMI-----------------
with Tenemi.Create(form1.DXSpriteEngine1.Engine) do
begin
Image:=Form1.DXImageList1.Items.Find('enemi');
//déclare l'image
Width := Image.Width;
Height := Image.Height;
sens := random(2) = 1 ;
//choisi aléatoirement le sens de notre sprite
if sens then X:=screen.width+image.width
// choisi sa position en fonction du sens pour être sur qu'il soit cacher au debut
else
X := -(image.width);
//en dehors de l’écran
Y:=random(screen.height);
//positionnement aléatoire
Z:=2;
pixelcheck := true;
//cette variable spécifie si les collision doivent être prisent à l'image près (donc s'il y a des transparences elle seront ignoré ) ou si cela doit être au pixel près.
end;
//--------------------------FIN--------------------
end;


Ensuite il faut s'occuper du déplacement de nos ennemis.

procedure Tenemi.Domove (movecount : integer);
begin
inherited Domove(movecount);

{les sprites peuvent être animé avec les propriétés anim et Pattern.
dans la source de delphix on remarque que le changement d'image (l'animation) se fait dans le domove de timagesprite
Mais pour que cette action d'animation ce fasse il faut appeller la fonction de l’ancêtre de notre Tenemi, Timagesprite.
Car pour ceux qui ne le savent pas inherited appelle les routines de l'ancetre.
Ici on pourrait juste mettre inherited; car cela appelle la procedure du même nom}
//ici il n'y aura pas d'animation de sprite je vous expliquerais plus loin pourquoi.

if sens then X:= X-3 else X := X+3;
//déplacement du sprite en fonction du sens choisi
if (X =screen.Width) or (X <= 0) then sens := not sens;
// si le sprite est arriver en dehors de l’écran il change de sens
end;
Bien maintenant comment vont être créés nos ennemi?

Nous allons créer une variable reste :integer.
Elle indiquera le nombre d’ennemi à créer . Au début dans l’événement create de notre fiche donnons lui la valeur 5. puis dans notre Ttimer ajoutons ceci.
if (reste 0) then
begin
dec(reste);
form1.creaenemi;
end;
Lancez l'application et vous aurez droit à un superbe jeu.

7.?

ah aH AH je vous ai eu il ne marche pas le jeu mais pourquoi à votre avis .
Oh je vais vous le dire car vous avez bien du trouver (en + si cela ce trouve vous avez corrigé le problème).
Bien sur vous n'avez jamais dit quand il faut détruire les ennemis.
Donc nous allons regarder quand cela serai utile.
Et bien le mieux c'est le viseur car c'est lorsque l'on clique qu'on vérifiera le problème et si chaque bête devait le faire ce serait trop long.

Donc ajoutons à notre viseur une option de vérification des collisions.

avant :

Tviseur = class(TImageSprite);

et maintenant :

Tviseur = class(TImageSprite)
public
procedure DoCollision (Sprite : TSprite; var Done : boolean); override;
//verifie la collision entre notre viseur et nos ennemis
end;

Et voilà pourquoi une classe Tviseur.
c'est mieux mais que faut t'il faire en cas de collision et bien continuons.



procedure Tviseur.Docollision(Sprite : TSprite; var Done : boolean);
begin
inherited Docollision(sprite,done);
if (sprite is tenemi) then
begin
tenemi(sprite).dead;
//on détruit l’ennemi
inc(reste)
//reste indique le nombre d’ennemi à créer

end;

end;

Puis dans l’événement onclick de notre dxdraw on ajoute :

viseur.Collision;

et voilà c'est bon là vous pourrez jouer à votre petit jeu.

8.C'est triste un jeu de ce genre

Bah oui c'est triste, pas de score, d'explosion, d'animation ,de sons. Alors je vais donc vous passer en revue quelques améliorations.

LE SENS

Il nous faudrait deux images d’ennemi car s'il vient de la droite ou de la gauche il n'a pas la même tête donc ajoutons une image enemi2(dans notre dximagelist) et dans notre
enemy.domove on fait ceci :

AVANT

procedure Tenemi.Domove (movecount : integer);
begin
inherited Domove(movecount);
if sens then X:= X-3 else X := X+3;
if X >=screen.Width then sens := true;
if X <= 0 then sens := false;
end;

APRES

procedure Tenemi.Domove (movecount : integer);
begin
inherited Domove(movecount);
if sens then X:= X-3 else X := X+3;
if X =screen.Width then
begin
sens := true;
Image:=Form1.DXImageList1.Items.Find('enemi');
//en changeant de sens on change l'image
end;
if X <= 0 then
begin
sens := false;
Image:=Form1.DXImageList1.Items.Find('enemi2');
end;
end;

c'est tout.



LE SON

Pourquoi pas !!

A chaque clique de souris faire retentir un bruit (coup de feu ....)

ajoutons un
DXWaveList (base de donné de son) et un DXSound (lecteur).

Le dxwavelist est similaire à un dximagelist sauf que c'est une banque de donnés qui comporte des sons et non pas des images.
Le dxsound lui se compare plus à un dxdraw.
Dans notre
DXWaveList on met dxsound1 dans la propriété dxsound et ont met notre son que l'on nommé bang ici (en doucliquant sur le composant et sélectionnant ce fichier vous l'aurez tout près).

Ensuite il vous reste juste à ajouter cette ligne dans votre
l'évenement onclick de notre dxdraw1 :

form1.DXWaveList1.Items.find('bang').Play(false);

La propriété qui accompagne la procedure
play signifie qu'il faut attendre la fin du sons pour continuer les autres routines.

LES EXPLOSIONS

Ben oui ce n'est pas drôle, la bête elle disparaît sans rien alors on va la faire exploser (enfin un truc dans ce genre hihi!).
alors créons une nouvelle classe :

TBoom = class(TImageSprite)
public
procedure Domove (movecount : integer); override;
end;


Notre
Tboom sera une animation de quelques images donc pour le créer on ajoutera une procedure boom(LX, LY :integer) (les variables LX et LY correspondent à la position de notre explosion celle de la bête ).

On décrit cette procedure:

procedure Tform1.Boom(LX,LY:integer);
begin
with Tboom.Create(form1.DXSpriteEngine1.Engine) do
begin
X:=LX;
Y:=LY;
Z:=2;
// même hauteur que les bêtes.
Image:=Form1.DXImageList1.Items.Find('boom');
Width := Image.Width;
Height := Image.Height;
AnimCount:=Image.PatternCount;
//nombre d'image dans l'animation
AnimLooped := false;
//animation en boucle
AnimPos := 0;
//image de départ pour l'animation
AnimSpeed := 1/10;
//vitesse d'animation
end;
end;

Alors on va décrire un peu le truc.
On a créé un sprite
Tboom avec l'image boom anim count correspond au nombre d'image animlooped indique si oui ou non ce sprite par en boucle.
Animpos l'image sélectionné. Animspeed la vitesse d'animation.
Patterncount correspond au nombre d'image dans notre image boom (car elle est divisé en plusieurs images), pour décrire ces images modifiez la propriété pattern dans votre image(cela correspond au dimension d'une image).
notre sprite sera créé à chaque destruction d'une bête donc ajoutons dans la collision de notre sprite viseur cette petite ligne :

Form1.boom(sprite.X,sprite.Y);

Bien sur il faut ajouter une procedure domove pour lui indiquer quand il doit se détruire.
donc voilà notre domove :

procedure Tboom.Domove (movecount : integer);
begin
inherited Domove(movecount);
if animpos = animcount-1 then dead;
end;

Ceci fait en sorte que si la position de l'animation est égal à celle de la dernière image du sprite.


LE SCORE

Et oui il faut un score pour savoir où on en est.
Donc commençons par déclarer une variable
Score : integer;

ensuite dans l’événement create de notre fiche on met
score := 0 et à chaque collision de viseur inc(score).
Mais on à notre score Maintenant il faut l'afficher donc dans l’événement timer du
timer avant de dessiner notre écran donc en après avoir déplacé les sprites (au cas ou un d'autre eux soit mort) et dessiné ceux-ci on met cette ligne qui écrit notre score en haut à gauche de l’écran.

t := inttostr(score);
dxdraw1.Surface.Canvas.TextOut(1,1,'SCORE : '+t);

Bien sur déclarez t en tant que
string.
Vous pouvez bien sur changer la taille ou la police ect (couleur & co...).
Par exemple :
dxdraw1.Surface.Canvas.Font.Color := clblue;
dxdraw1.Surface.Canvas.Font.Height := 40 ;

ce qui donne un truc dans ce genre :

SCORE : 0

9.Mais pourquoi ils ne sont pas animés nos enemis

Et bien cela aurai été avec plaisir mais malheureusement un bug dans delphiX nous en empêche.
Je vais donc vous donnez ce que j'ai trouvé au sujet de ce bug .
Lorsque que l'image n'est pas sur sa position 0 de l'animation et que vous avez choisi pixelcheck (ce qui est fait le plus souvent ) et bien la collision est toujours fausse.
Enfin je ne vais pas vous ennuyer avec cela amusez vous bien avec votre nouveau joujou euh..pardon composant :-).


10.Petit recapitulatif


Oui, un petit bilan s'impose pour que tout soit bien en ordre.

Pour pouvoir commencer il faut mettre les composants.
ensuite il faut préparer la fiche (dxform,borderstyle....) et dans notre timer mettre les actions de reactualisation des sprites et de l’écran(enfin le dxdraw).
pour afficher des sprites il faut les créer.
Pour cela on peut les créer avec ou sans référence et avec ou sans classe.
dans delphiX il y a plusieurs types de sprite mais le plus utilisé est Timagesprite.
chaque Timagesprite à entre autre un propriété
domove et une propriété docolision, Ces propriétés sont importantes car se sont elles qui rendront nos sprites mouvants et réactifs aux autres sprites donc retenez bien ces deux propriétés .
Et pour finir on peut toujours utiliser directement le dxdraw et écrire dessus(avec le canvas) comme nous l'avons fait mais nous pouvons aussi dessiner avec des procédures du dximagelist, draw (dessine) drawadd(dessine avec des effets de transparence(alpha blending)) et quelques autre que vous decouvrirez en regardant les exemples fournies avec delphiX vous y découvrirez par exemple un joli shoot'em up (Samples\Sprite\Shoot) ou un exemple dans lequel toutes les maniéres de dessiner une image (en vague en alpha en agrandissement ect...) sont présentes.


C'est fini il ne vous reste plus qu'à télécharger les exemples de ce tutorial si vous en avez besoin et si vous avez des problèmes des critiques ou autre chose voici mon mail, bodman@wanadoo.fr.

Par bodman
Mon site: PC SEED

Responsables bénévoles de la rubrique Delphi : NoisetteProd et Pedro - Contacter par EMail :
Vos questions techniques : forum d'entraide Delphi - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.