Déjà pourquoi une liste chainée ? Prenons un exemple simple. Vous êtes en train de programmer un shoot'em up. Vous avez votre vaisseau et vous devez gérer les tirs du joueur. Il faut savoir que vous ne pouvez pas savoir combien de fois le joueur va tirer au cours de la partie. De ce fait si vous demandez à Purebasic de vous afficher un sprite de tir alors qu'il n'y en a plus à l'écran, le jeu va planter.
Damned ! Incroyable ! et pourtant...Quelques programmeurs utiliseront des tableaux pour gérer les tirs du joueurs. C'est à dire qu'il vont initialiser un tableau qui comptabilisera le nombre de tir à l'écran.
Seulement comme je vous l'ai dit vous ne pouvez pas prévoir le nombre de tir à l'avance, le joueur peut tirer 500 fois comme 10 000 fois si c'est un mega bourrin. De ce fait il faudra prévoir un tableau énorme (genre 10 000 en taille) par exemple. Résultat des opérations, vous avez un énorme tableau et en plus, il prend énormement de place en ressources. Donc pas très optimisée comme solution...
C'est ici qu'interviennent les Listes Chaînées (ou Linked List). Comme son nom l'indique, on crée une liste qui sera dynamique. C'est à dire que, dans notre exemple, la liste sera aussi grande qu'il n'y a de tirs dans le jeu. D'autres part ces tirs seront détruits de manière dynamiques aussi. Donc, la liste va s'agrandir, pour devenir plus petite et tout cela sans que vous n'ayez presque rien à faire.
Donc en résumé, une liste chaînée, c'est une liste d'éléments (comme les tirs) qui est gérée de manière dynamique et suivant les évènements du jeu. L'avantages, c'est que les listes ne prennent pas autant de essources qu'un énorme tableau et la liste s'adapte selon les évènements.
A quoi peuvent elles servir sinon ? A gérer par ex une liste d'ennemis (Invaders) ou des étoiles etc...
Généralement, même si ce n'est pas obligatoire, on couple les listes chaînées avec les structures. Alors kesako ca encore lol.
Je ne sais pas si vous avez déjà entendu de la programmation orientée objet ? Bon déjà ce n'est pas tout à fait la même chose, mais les objets ont quelques points communs. Un objet que vous créé en programmation, aura ses propres propriétés (par ex la position en x, en y, la vitesse...). Quand vous créez une structure, vous créez en fait un "objet" (entre "" car ce n'est pas le terme exact), auquel vous attribuez des propriétés qui pourront être utilisées par la suite.
Laissons la liste chaînée de côté, nous allons essayé de comprendre les structures. Admettons que vous vouliez faire un carnet d'adresse. Vous allez avoir dedans, le nom, le prénom et le numéro de téléphone par ex. Si vous voulez stocker ses données dans un tableau, vous imaginez le nb de dimensions que devra avoir le tableau pour tout stocker ? Pourquoi ne pas faire alors une structure qui se présenterait comme ceci :
Structure Carnet
nom.s
prenom.s
numero.w
EndStructure
Ensuite vous avez votre "objet" Carnet avec toutes ses propriétés et vous pourrez stocker dans une unique case d'un tableau, une occurence de cette structure. Par exemple, la case 1 du tableau stockera en même temps le nom, prénom et numero de quelqu'un. Tout ca d'un coup. Pratique non ? Dans le cas contraire vous auriez à créer plus dimensions dans votre tableau en disant par ex que la première ligne c'est la nom, la
seconde les prénoms, un vrai foutoir quoi...Vive les structures.
Les structures fonctionnent de la même manière avec les listes chaînées. Bon assez de blabla passons à la pratique. Pour comprendre les structures et les listes je vous propose de créer un simple scrolling paralaxe d'étoiles, un fond étoilé animé en somme.
Un fond à deux niveaux pour simuler la profondeur de la galaxie. C'est plus joli et plus réaliste. Pour cela nous avons besoin de deux sprites : une étoile claire (blanche), et une étoile un peu plus foncée pour mettre au second niveau et simuler la profondeur. Je vous laisse les faires ca se fait en 5 mns avec un soft de dessin.
Nommez l'étoile clair : star.bmp et l'étoile foncée : star2.bmp
ou telechargez celles-ci
http://michel.dobro.fee.fr/Forum_PB/tut ... e/star.bmp
http://michel.dobro.fee.fr/Forum_PB/tut ... /star2.bmp
Ca y est ? vous avez vos deux petites images ? Magnifique, player one shoots again ! sinon c'est GameOver lol
Je le dis tout de suite je ne vais pas m'attarder sur les bases, donc je prend en considération que vous connaissez les bases (intialisation des sprites création de la fenêtre de jeu etc...)
Bien commencez par créer un nouveau projet avec PureBasic et mettez les lignes de code suivantes :
Code : Tout sélectionner
;Tutorial Listes Chaînées
;Initialisation des composants
InitSprite()
InitKeyboard()
InitMouse()
InitSound()
;Constantes
#Star = 1
#Star2 = 2
;Création de la fenêtre principale
SetRefreshRate(60)
MaFenetre = OpenScreen(800,600,32,"Test")
If MaFenetre = 0
MessageRequester("Erreur", "Impossible d'ouvrir une fenêtre DirectX", #PB_MessageRequester_Ok)
EndIf
Par contre j'ai créé deux constantes qui définiront nos sprites, à savoir : #Star et #Star2 qui identifieront les deux étoiles que vous avez dessinées précédemment.
Parfait continuons :
Code : Tout sélectionner
;Chargement des sprites
LoadSprite(#Star,"star.bmp")
TransparentSpriteColor(#Star,0)
Structure Etoile
posx.f
posy.f
vitesse.f
EndStructure
Global NewList Stars.Etoile()
LoadSprite(#Star2,"star2.bmp")
TransparentSpriteColor(#Star2,0)
Structure Etoile2
posx.f
posy.f
vitesse.f
EndStructure
Global NewList Stars2.Etoile2()
Pour chaque étoile nous avons créé une structure. Aaaaah voilà que cela devient intéressant. Ainsi une étoile aura une position en X (posx), une position en Y (posy) et une vitesse (vitesse). Vous remarquerez que à côté de chaque variable se trouve ".f" il s'agit en fait du type de variable, dans notre exemple des nombres flotants. Une étoile aura alors chacune de ces propriétés. Enfin pour chaque étoile nous créeons une liste avec l'instruction NewList (une liste chaînée donc). Prenons la première :
NewList Stars.Etoile()
Cette ligne signifie qu'on crée une liste du nom de Stars et utilisant la structure Etoile. Facile n'est ce pas ?
Nous avons effectué cette opération pour nos deux étoiles.
il serait temps maintenant de donner un mouvement à nos étoiles. Dans notre exemple, le scroll étoilé se fera à la verticale. Donc les étoiles vont évoluer suivant une position sur l'axe des Y (et donc verticale).
Apprenons directement à structurer nos programmes. Vu qu'il faut faire le mouvement pour les deux types d'étoiles, nous allons créer une procédure, qui sera appelé dans le programme principale. Ajoutez ces lignes de code :
Code : Tout sélectionner
Procedure DisplayEtoile()
ResetList(Stars())
While NextElement(Stars())
If Stars()\posy > 600
Stars()\posy = -5
EndIf
DisplayTransparentSprite(#Star, Stars()\posx, Stars()\posy)
Stars()\posy + Stars()\vitesse
Wend
ResetList(Stars2())
While NextElement(Stars2())
If Stars2()\posy > 600
Stars2()\posy = -5
EndIf
DisplayTransparentSprite(#Star2, Stars2()\posx, Stars2()\posy)
Stars2()\posy + Stars2()\vitesse
Wend
EndProcedure
Bon ca y est ? et on parle pas la bouche pleine ! Donc je reprends....Bon les deux au fond la bas !
Répetez ce que je viens dire ? Et voilà yen a 2 qui suivent ! Donc commençons l'explication de ces lignes.
Rappelez vous que notre première liste (de la première étoile), s'appelle Stars. L'instruction ResetList demande à Purebasic de prendre la liste par le début (bah oui hein vous regardez pas votre liste de courses à l'envers !).
Nous avons ensuite une boucle While Wend. Elle signifie "Pour chaque élément Stars faire..." ou même "Tant qu'il y a des éléments Stars faire". En clair tant qu'on a dans la liste des étoiles alors...C pas dur mais que fais t'on ? Très simple on dit que si la position de notre étoile en Y est supérieure à 600 alors on la replace à une coordonnée Y de -5 donc en clair si elle sort de l'écran paf on la remet hors de l'écran, en haut. Ensuite on affiche l'étoile avec la commande DisplayTransparentSprite et on change la coordonnée Y en ajoutant la variable vitesse,que nous définirons tout à l'heure. Et voilà c fini, le mouvement de nos étoiles est programmé.
Au niveau de la syntaxe avec les listes chainées, sachez que pour appeler une variable qui a été définie dans une structure on fait : nomliste()\variable le "\" est important !
Bon c'est bien beau tout ca mais maintenant les étoiles, va bien falloir leur donner une position initiale et puis donner une valeur à la variable vitesse non ? Allons y en dessous ajoutez ceci :
Code : Tout sélectionner
For i = 1 To 150
AddElement(Stars())
AddElement(Stars2())
Stars()\posx = Random(800)
Stars()\posy = Random(600)
Stars()\vitesse = 2
Stars2()\posx = Random(800)
Stars2()\posy = Random(600)
Stars2()\vitesse = 1
Next
Ensuite nous définissons la vitesse à 2 pour les étoiles claires, et à 1 pour les étoiles foncées, c ce qui va donner l'effet de profondeur. Remarquez que pour définir les variables on utilise toujours la syntaxe des listes chainée (c un coup à prendre mais vous verrez vous vous y ferez très vite).
Parfait, il ne reste plus qu'à programmer la boucle principale :
Code : Tout sélectionner
Repeat
ClearScreen(RGB(0,0,0))
DisplayEtoile()
ExamineKeyboard()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
Je reste à votre disposition pour des infos complémentaires sur ce tutoriel, si vous avez des questions !
bon code !
------ EDIT ----- Mise à jour en PB 5.42 LTS en gardant au maximum le code de Crystal Noir
- Mise à jour de certaines commandes
- Création des 2 sprites plutôt qu'un chargement d'images (sans compter que les liens sont morts dans l'exemple ci dessus)
- Utilisation d'une seule structure pour les 2 sprites
J'ai commenté les modifs dans le code
Code : Tout sélectionner
;Tutorial Listes Chaînées
; Original code : Crystal Noir
; MaJ 5.42 : Ar-S
;Initialisation des composants
InitSprite()
InitKeyboard()
InitMouse()
InitSound()
; On déclare les futures procédures pour qu'elles soient repérées en début et/ou fin de code
Declare Creation_Etoile()
Declare DisplayEtoile()
; On va déclarer les 2 constantes étoile en commençant par 1
Enumeration 1
#Star
#Star2
EndEnumeration
Global NombreEtoile = 50
; 1 structure peut servir à plusieurs sprites
Structure Etoile
posx.f
posy.f
vitesse.f
EndStructure
Global NewList Stars.Etoile()
Global NewList Stars2.Etoile()
;Création de la fenêtre principale
MaFenetre = OpenScreen(800,600,32,"Test",#PB_Screen_SmartSynchronization,60)
If MaFenetre = 0
MessageRequester("Erreur", "Impossible d'ouvrir une fenêtre DirectX", #PB_MessageRequester_Ok)
End ; on quitte
Else
Creation_Etoile()
; Boucle principale
Repeat
ClearScreen(RGB(0,0,0))
DisplayEtoile()
ExamineKeyboard()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
EndIf
; /// PROCEDURES ////////////////////
Procedure Creation_Etoile()
; // Création des sprites
; Etoile 1
; - Creation du sprite vide
CreateSprite(#Star,2,2)
; On remplit ce sprite d'une étoile blanche de 2x2 pixels
StartDrawing(SpriteOutput(#Star))
Box(0,0,2,2,RGB(255,255,255) )
StopDrawing()
; Etoile 2
; - Creation du sprite vide
CreateSprite(#Star2,2,2)
; On remplit ce sprite d'une étoile rouge de 2x2 pixels
StartDrawing(SpriteOutput(#Star2))
Box(0,0,2,2,RGB(255,0,0) )
StopDrawing()
EndProcedure
Procedure DisplayEtoile()
ResetList(Stars())
For i = 1 To NombreEtoile
AddElement(Stars())
AddElement(Stars2())
Stars()\posx = Random(800)
Stars()\posy = Random(600)
Stars()\vitesse = 2
Stars2()\posx = Random(800)
Stars2()\posy = Random(600)
Stars2()\vitesse = 1
Next
While NextElement(Stars())
If Stars()\posy > 600
Stars()\posy = -5
EndIf
DisplaySprite(#Star, Stars()\posx, Stars()\posy)
Stars()\posy + Stars()\vitesse
Wend
ResetList(Stars2())
While NextElement(Stars2())
If Stars2()\posy > 600
Stars2()\posy = -5
EndIf
DisplaySprite(#Star2, Stars2()\posx, Stars2()\posy)
Stars2()\posy + Stars2()\vitesse
Wend
EndProcedure
; /////////FIN PROCEDURES ////////////////////////////////////