PureBasic:Listes chainées et SpriteCollision
Un article de Games Creators Network.
PureBasic:Listes chainées et SpriteCollision
<< Précédent | Sommaire | Suivant >>
Sommaire |
[modifier] Introduction
Dans ce tut vous apprendrez à utiliser :
- Les listes chaînées
- Les collisions des sprites
Dans cet exemple , nous allons afficher des météorites qui défilent à l'écran , le joueur pourra piloter un vaisseau et tirer sur les météorites. les météorites volent en éclat lorqu'elles sont touchées par un missile du joueur.
[modifier] Initialisation
Ce tutoriel reprend le programme minimal déjà évoqué au cours du tutoriel Premiers pas avec PureBasic.
Ensuite on déclare les procédures utilisées par le programme .
;Declare les Procedures Declare AddTir(X.l,Y.l) Declare GestionTir() Declare AddMeteorite() Declare GestionMeteorite() Declare AddEclats(ID.l,X.l,Y.l) Declare GestionEclats()
Puis on définit quelques constantes.Elles permettront d'identifier plus aisément les sprites par la suite.
C'est plus parlant d'écrire DisplaySprite(#Vaisseau,x,y) que DisplaySprite(0,x,y).
;Sprites ;Nombre de météorites différentes #MaxMeteorites=25 Enumeration #Vaisseau #Tir #Meteorite #Eclats = #PB_Compiler_EnumerationValue + #MaxMeteorites EndEnumeration
Et pour finir , on définit deux structures.
Structure s_sprite ID.l ; No du sprite X.l Y.l Vitesse.l EndStructure Structure s_particule Extends s_sprite DX.l DY.l EndStructure
[modifier] Listes Chaînées
PureBasic possède une bibliothèque permettant de gérer très simplement les listes chaînées.
- NewList permet d'initialiser une liste chaînée.
Dans notre exemple , nous aurons besoin d'une liste pour les météorites , les tirs et les éclats des météorites.
NewList TirJoueur.s_sprite() NewList Meteorite.s_sprite() NewList Eclats.s_particule()
- AddElement() permet d'ajouter un élément à une liste chaînée.
- CountList() renvoie le nombre d'éléments contenus dans la liste spécifiée.
On affiche en permanence des météorites sur l'écran .
Procedure AddMeteorite() If CountList(Meteorite())<10 ; si le nombre de météorites est inférieur à 10 AddElement(Meteorite()) ; On ajoute une météorite Meteorite()\id=#Meteorite+Random(#MaxMeteorites) Meteorite()\x=Random(800-SpriteWidth(#Meteorite)) ;La météorite est créée en dehors de l'écran Meteorite()\y=-Random(500) Meteorite()\vitesse=1+Random(3) EndIf EndProcedure
Quand le joueur tire on ajoute un tir à la liste.
Procedure AddTir(X.l,Y.l) AddElement(TirJoueur()) TirJoueur()\id = #Tir ; No de sprite TirJoueur()\x=x ;Position de départ du tir TirJoueur()\y=y TirJoueur()\vitesse=4 ;Vitesse de déplacement d'un tir EndProcedure
Quand un tir touche une météorite celle ci explose et des éclats sont affichés
Procedure AddEclats(ID.l,X.l,Y.l)
n=4+Random(5) ;Nombre d'éclats
For i=1 To n
AddElement(Eclats()) ;Ajoute un éclat à la liste Eclats()
Eclats()\id=ID+#MaxMeteorites+1 ;Détermine le sprite de l'éclat
Eclats()\x=x ;Position de départ d'un éclat
Eclats()\y=y
While Eclats()\DX=0 Or Eclats()\DY=0 ;DX ou DY doivent être différents de zéro
Eclats()\DX=2-Random(4) ;Pour éviter qu'un éclat reste sur place
Eclats()\DY=2-Random(4)
Wend
Next i
EndProcedure
- DeleteElement() supprime l'élément courant de la liste spécifiée.
- ForEach() énumère tous les élèments d'une liste chaînée. Si la liste est vide, ForEach : Next quitte immédiatement, sans entrer dans la boucle.
Cette fonction est utile pour tester l'ensemble d'une liste, par exemple pour savoir si un tir touche une météorite.
Procedure GestionTir() ForEach TirJoueur() TirJoueur()\y - TirJoueur()\vitesse DisplaySprite(TirJoueur()\id,TirJoueur()\x,TirJoueur()\y) ;Si le tir sort de l'écran on l'efface If TirJoueur()\y<0 DeleteElement(TirJoueur()) Continue EndIf ;Test si un tir touche une météorite ForEach Meteorite() If SpritePixelCollision(TirJoueur()\ID,TirJoueur()\x, TirJoueur()\y,Meteorite()\ID,Meteorite()\x,Meteorite()\y) DeleteElement(TirJoueur()) AddEclats(Meteorite()\ID,Meteorite()\x,Meteorite()\y) DeleteElement(Meteorite()) Break 2 EndIf Next Next EndProcedure
[modifier] Les collisions
Pour en savoir plus sur les collisions : Détection pixel-perfect des collisions 2D.
PureBasic est doté de deux fonctions pour la gestion des collisions.
Remarque : SpritePixelCollision() vérifie d'abord s'il y a une collision possible en testant les boîtes englobantes des sprites, il est donc inutile de faire ce test soi même avec SpriteCollision() avant d'appeler la fonction SpritePixelCollision().
[modifier] Programme complet
;Initialise l'environnement nécessaire au fonctionnement des sprites et pour ouvrir un écran.
InitSprite()
;Initialise l'environnement propre à la gestion du clavier.
InitKeyboard()
;Ouvre un nouvel écran avec les caractéristiques Largeur, Hauteur et Profondeur.
OpenScreen(800,600,32,"Demo")
;Declare les Procedures
Declare AddTir(X.l,Y.l)
Declare GestionTir()
Declare AddMeteorite()
Declare GestionMeteorite()
Declare AddEclats(ID.l,X.l,Y.l)
Declare GestionEclats()
;Sprites
;Nombre de météorites différentes
#MaxMeteorites=25
Enumeration
#Vaisseau
#Tir
#Meteorite
#Eclats = #PB_Compiler_EnumerationValue + #MaxMeteorites
EndEnumeration
Structure s_sprite
ID.l ; No du sprite
X.l
Y.l
Vitesse.l
EndStructure
Structure s_particule Extends s_sprite
DX.l
DY.l
EndStructure
NewList TirJoueur.s_sprite()
NewList Meteorite.s_sprite()
NewList Eclats.s_particule()
Global Vaisseau.s_sprite,Meteorite.s_sprite
;Sprite vaisseau
CreateSprite(#Vaisseau,32,32)
StartDrawing(SpriteOutput(#Vaisseau))
Line(SpriteWidth(#Vaisseau)/2,0,SpriteWidth(#Vaisseau)/2,SpriteHeight(#Vaisseau),RGB(255,255,0))
Line(SpriteWidth(#Vaisseau)/2,0,-SpriteWidth(#Vaisseau)/2,SpriteHeight(#Vaisseau),RGB(255,255,0))
Line(0,SpriteHeight(#Vaisseau)-1,SpriteWidth(#Vaisseau),0,RGB(255,255,0))
FillArea(SpriteWidth(#Vaisseau)/2,SpriteHeight(#Vaisseau)/2,RGB(255,255,0),RGB(255,155,0))
StopDrawing()
Vaisseau\x=400-SpriteWidth(#Vaisseau)/2 ; Centre le Vaisseau
Vaisseau\y=600-SpriteHeight(#Vaisseau)
Vaisseau\vitesse=2
;Sprite pour les tirs
CreateSprite(#Tir,3,3)
StartDrawing(SpriteOutput(#Tir))
Box(0,0,3,3,RGB(255,55,55))
StopDrawing()
;Sprite des météorites et des particules
For i=#Meteorite To #Meteorite+#MaxMeteorites
Couleur=RGB(Random(255),Random(255),Random(255))
Size=25+Random(25)
CreateSprite(i,size,size)
StartDrawing(SpriteOutput(i))
Circle(SpriteWidth(i)/2,SpriteHeight(i)/2,(SpriteWidth(i)/2),Couleur)
StopDrawing()
;Sprite des particules
Size/2
p=i+#MaxMeteorites+1
CreateSprite(p,size,size)
StartDrawing(SpriteOutput(p))
DrawingMode(4)
Circle(SpriteWidth(p)/2,SpriteHeight(p)/2,SpriteWidth(p)/2,Couleur)
StopDrawing()
Next i
Repeat
;Inverse le buffer d'arrière plan avec le buffer visible à l'écran.
;La partie invisible du buffer remplace alors complètement La partie visible.
FlipBuffers()
;Efface l'écran courant avec la couleur specifiée.
ClearScreen(0,0,30)
;Met à jour l'état du clavier.Cette fonction doit être appelée avant d'utiliser les commandes
;KeyboardInkey(), KeyboardPushed() et KeyboardReleased().
If ExamineKeyboard()
If KeyboardPushed(#PB_Key_Left)
Vaisseau\x - Vaisseau\Vitesse
If Vaisseau\x <0
Vaisseau\x=0
EndIf
ElseIf KeyboardPushed(#PB_Key_Right)
Vaisseau\x + Vaisseau\Vitesse
If Vaisseau\x > 800-SpriteWidth(#Vaisseau)
Vaisseau\x=800-SpriteWidth(#Vaisseau)
EndIf
EndIf
If KeyboardPushed(#PB_Key_Space) And ElapsedMilliseconds()-DernierTir>100 ;Autorise un tir tous les 100 ms
DernierTir=ElapsedMilliseconds()
AddTir(Vaisseau\x+SpriteWidth(#Vaisseau)/2,Vaisseau\y)
EndIf
EndIf
AddMeteorite()
GestionMeteorite()
GestionTir()
GestionEclats()
DisplayTransparentSprite(#Vaisseau,Vaisseau\x,Vaisseau\y)
Until KeyboardPushed(#PB_Key_Escape)
Procedure AddTir(X.l,Y.l)
AddElement(TirJoueur())
TirJoueur()\id = #Tir
TirJoueur()\x=x
TirJoueur()\y=y
TirJoueur()\vitesse=4
EndProcedure
Procedure AddEclats(ID.l,X.l,Y.l)
n=4+Random(5) ;Nombre d'éclats
For i=1 To n
AddElement(Eclats()) ;Ajoute un éclat à la liste Eclats()
Eclats()\id=ID+#MaxMeteorites+1 ;Détermine le sprite de l'éclat en fonction de la météorite touchée
Eclats()\x=x ;Position de départ d'un éclat
Eclats()\y=y
While Eclats()\DX=0 Or Eclats()\DY=0 ;DX ou DY doivent être différents de zéro
Eclats()\DX=2-Random(4) ;Pour éviter qu'un éclat reste sur place
Eclats()\DY=2-Random(4)
Wend
Next i
EndProcedure
Procedure GestionEclats()
ForEach Eclats()
Eclats()\x+Eclats()\DX
Eclats()\y+Eclats()\DY
;Si un éclat sort de l'écran , on le supprime
If Eclats()\x>800 Or Eclats()\x<SpriteWidth(Eclats()\id) Or Eclats()\y>600 Or Eclats()\y<SpriteHeight(Eclats()\id)
DeleteElement(Eclats())
Continue
EndIf
DisplayTransparentSprite(Eclats()\id,Eclats()\x,Eclats()\y)
Next
EndProcedure
Procedure GestionTir()
ForEach TirJoueur()
TirJoueur()\y - TirJoueur()\vitesse
DisplaySprite(TirJoueur()\id,TirJoueur()\x,TirJoueur()\y)
;Si le tir sort de l'écran on l'efface
If TirJoueur()\y<0
DeleteElement(TirJoueur())
Continue
EndIf
;Test si un tir touche une météorite
ForEach Meteorite()
If SpritePixelCollision(TirJoueur()\ID,TirJoueur()\x ,TirJoueur()\y,Meteorite()\ID,Meteorite()\x,Meteorite()\y)
DeleteElement(TirJoueur())
AddEclats(Meteorite()\ID,Meteorite()\x,Meteorite()\y)
DeleteElement(Meteorite())
Break 2
EndIf
Next
Next
EndProcedure
Procedure AddMeteorite()
If CountList(Meteorite())<10
AddElement(Meteorite())
Meteorite()\id=#Meteorite+Random(#MaxMeteorites)
Meteorite()\x=Random(800-SpriteWidth(#Meteorite))
;La météorite est créée en dehors de l'écran
Meteorite()\y=-Random(500)
Meteorite()\vitesse=1+Random(3)
EndIf
EndProcedure
Procedure GestionMeteorite()
ForEach Meteorite()
Meteorite()\y + Meteorite()\vitesse
;Si une météorite sort de l'écran , on la supprime
If Meteorite()\y>600
DeleteElement(Meteorite())
Continue
EndIf
DisplayTransparentSprite(Meteorite()\id,Meteorite()\x,Meteorite()\y)
Next
EndProcedure
[modifier] Passage à la version V4.0
Il y a deux choses à faire pour que le programme précédent fonctionne avec la version 4.0 de PureBasic.
- Rendre toutes les listes chaînées globales
Global NewList TirJoueur.s_sprite() Global NewList Meteorite.s_sprite() Global NewList Eclats.s_particule()
C'est la solution la plus simple. L'autre solution consisterait à modifier les procédures pour qu'elles acceptent en paramètre les listes chaînées. Vous trouverez un exemple dans ce tutoriel
- Mettre un seul paramètre à la commande ClearScreen()
;Efface l'écran courant avec la couleur specifiée. ClearScreen(RGB(0,0,30))
Et voila, vous pouvez à nouveau faire joujou :)

