Partager via


Small Basic: Tableaux de Sprites (fr-FR)

Cet article décrit l'utilisation des tableaux de sprites dans un programme Small Basic. Un sprite est une image qui se déplace dans un jeu graphique, ils peuvent représenter des aliens par exemple.

Souvent nous avons besoins de plusieurs copies de sprites qui vont et viennent lorsque le jeu s'exécute, et il est conseillé des stocker dans des tableaux. Cet article propose quelques explications et suggestions sur les moyens de contrôler dynamiquement les sprites efficacement.

Chargement des images de sprite

L'image d'un sprite se trouve dans un fichier (par exemple. jpg ou png). Ce fichier peut un fichier local sur votre PC ou socker en ligne sous forme d'URL. Si il est local alors vous devrez partager les images avec votre jeu dans un téléchargement zip, aussi il peut être préférable d'héberger le fichier sur le Web quand c'est possible.

Il est généralement préférable de créer un sprite avec une bordure transparente et en choisissant soigneusement la largeur et la hauteur en pixels.

Une fois que le sprite est créé, il est plus efficace de le charger qu'une seule fois dans votre programme en utilisant la méthode ImageList, et habituellement on fait cela avant que le jeu ne démarre car il peut prendre du temps à télécharger. L'image chargée peut être utilisée plusieurs fois pour avoir de multiple copies du sprite. Le code suivant est un exemple de chargement de l'image d'un sprite à partir d'une URL et test qu'il s'affiche correctement.

sprite = ImageList.LoadImage("http://litdev.co.uk/game_images/football.png")
Shapes.AddImage(sprite)

Sprite d'un Ballon de Football

Tableaux de sprites

Maintenant nous pouvons créer un tableau avec plusieurs copies du sprite, en utilisant l'image chargée, par exemple.

spriteImage  = ImageList.LoadImage("http://litdev.co.uk/game_images/football.png")
numSprite  = 10
For i =  1 To numSprite
  sprite[i] = Shapes.AddImage(spriteImage)
EndFor

Les sprites apparaissent tous par dessus les autres et nous ne pouvons pas encore faire grand chose avec.

Propriétés de Sprite

Les sprites sont des images, mais dans un jeu ils peuvent avoir d'autres propriétés comme la position, le statut, la vélocité et autres. Nous avons besoin de stocker ces informations pour chaque sprites dans des tableaux. Il y a plusieurs méthodes pour faire ça, mais ici nous proposons d'enregistrer toutes les informations d'un sprite dans un tableau et d'avoir un tableau de ce tableau de sprite - pour être précis un tableau à deux dimensions.

Les tableaux dans Small Basic peuvent être lents, mais sont nous gardons le nombre d'éléments à son minimum, cette méthode des avantages. Elle permettra également d'améliorer votre programmation en maintenant les données logiquement associées ensembles et permettre plus facilement la création et la suppression d'un sprite.

Le code ci-dessous est structuré avec des sous-routines, créant plusieurs sprites, les positionnant de manière aléatoire, puis les déplaçant. Nous pouvons avoir des sprites qui pivotent ou d'autres caractéristiques enregistrées dans les tableaux spriteData.

gw = 600
gh = 600
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
 
CreateSprites()
 
' Boucle du jeu
While ("True")
  start = Clock.ElapsedMilliseconds
  
  UpdateSprites()
  
  delay = 20  - (Clock.ElapsedMilliseconds - start)
  If (delay  > 0) Then
    Program.Delay(delay)
  EndIf
EndWhile
 
Sub CreateSprites
  spriteImage = ImageList.LoadImage("http://litdev.co.uk/game_images/football.png")
  'Les dimensions utilisées pour le sprite sont la moitié de la hauteur et de la largeur
  spriteWidth = ImageList.GetWidthOfImage(spriteImage)/2
  spriteHeight = ImageList.GetHeightOfImage(spriteImage)/2
  
  numSprite = 10
  For i =  1 To numSprite
    spriteData["image"] = Shapes.AddImage(spriteImage)
    spriteData["Xpos"] = spriteWidth + Math.GetRandomNumber(gw-2*spriteWidth)
    spriteData["Ypos"] = spriteHeight + Math.GetRandomNumber(gh-2*spriteHeight)
    spriteData["Xvel"] = Math.GetRandomNumber(11)-6
    spriteData["Yvel"] = Math.GetRandomNumber(11)-6
    sprites[i] = spriteData
  EndFor
EndSub
 
Sub UpdateSprites
  For i =  1 To numSprite
    spriteData = sprites[i] ' récupère le tableau du sprite en cours
    
    'Repositionne le centre du sprite
    spriteData["Xpos"] = spriteData["Xpos"] + spriteData["Xvel"]
    spriteData["Ypos"] = spriteData["Ypos"] + spriteData["Yvel"]
    
    'Rebondi contre les murs
    If (spriteData["Xpos"] < spriteWidth) Then
      spriteData["Xpos"] = spriteWidth
      spriteData["Xvel"] = -spriteData["Xvel"]
    ElseIf (spriteData["Xpos"] > gw-spriteWidth) Then
      spriteData["Xpos"] = gw-spriteWidth
      spriteData["Xvel"] = -spriteData["Xvel"]
    EndIf
    If (spriteData["Ypos"] < spriteHeight) Then
      spriteData["Ypos"] = spriteHeight
      spriteData["Yvel"] = -spriteData["Yvel"]
    ElseIf (spriteData["Ypos"] > gh-spriteHeight) Then
      spriteData["Ypos"] = gh-spriteHeight
      spriteData["Yvel"] = -spriteData["Yvel"]
    EndIf
    
    'Déplace le centre du sprite
    Shapes.Move(spriteData["image"],spriteData["Xpos"]-spriteWidth,spriteData["Ypos"]-spriteHeight)
    
    sprites[i] = spriteData 'enregistre le tableaux modifié du sprite (il peut avoir été modifié)
  EndFor
EndSub

Ce code peut sembler plus long que nécessaire, mais enregistrer toutes les données d'un sprite dans un tableau et ainsi d'avoir un tableau de sprites et une manière efficace de procéder si vous voulez créer et détruire des sprites pendant le jeu.

Recycler les sprites

Nous avons souvent besoin que les sprites apparaissent et disparaissent. L'une des méthodes pour le faire est de recycler les sprites à partir d'un "pool", en les activant et les utilisant que c'est nécessaire. C'est très bien par exemple pour les tirs de balles ou de missiles, quand nous avons besoin uniquement d'un nombre limité à l'écran en même temps.

L'exemple qui suit tire des missiles lorsqu'un bouton de la souris est cliqué. Une nouvelle propriété "Status" est définie dans spriteData qui est utilisée pour indiquer si le missile est actif ou pas. Les missiles inactifs sont masqués et ils ne sont affichés à l'écran que lorsqu'ils actif.

Missile Sprite

gw = 600
gh = 600
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
GraphicsWindow.MouseDown = OnMouseDown
 
CreateSprites()
 
'Boucle de jeu
While ("True")
  start = Clock.ElapsedMilliseconds
  
  If (mouseDown) Then
    FireMissile()
    mouseDown = "False"
  EndIf
  UpdateSprites()
  
  delay = 20  - (Clock.ElapsedMilliseconds - start)
  If (delay  > 0) Then
    Program.Delay(delay)
  EndIf
EndWhile
 
Sub CreateSprites
  spriteImage = ImageList.LoadImage("http://litdev.co.uk/game_images/missile.png")
  'Les dimensions utilisées pour le sprite sont la moitié de la hauteur et de la largeur
  spriteWidth = ImageList.GetWidthOfImage(spriteImage)/2
  spriteHeight = ImageList.GetHeightOfImage(spriteImage)/2
  
  numSprite = 50
  For i =  1 To numSprite
    spriteData["image"] = Shapes.AddImage(spriteImage)
    spriteData["Xpos"] = spriteWidth + Math.GetRandomNumber(gw-2*spriteWidth)
    spriteData["Ypos"] = gh-spriteHeight
    spriteData["Xvel"] = 0
    spriteData["Yvel"] = -5
    spriteData["Status"] = 0
    Shapes.HideShape(spriteData["image"])
    sprites[i] = spriteData
  EndFor
EndSub
 
Sub UpdateSprites
  For i =  1 To numSprite
    spriteData = sprites[i] 'récupère le tableau du sprite en cours
    
    If (spriteData["Status"] = 1) Then
      'Repositionne le centre du sprite
      spriteData["Xpos"] = spriteData["Xpos"] + spriteData["Xvel"]
      spriteData["Ypos"] = spriteData["Ypos"] + spriteData["Yvel"]
      
      'Déplace le centre du sprite
      Shapes.Move(spriteData["image"],spriteData["Xpos"]-spriteWidth,spriteData["Ypos"]-spriteHeight)
      
      'Ce sprite n'est plus utile ?
      If (spriteData["Ypos"] < -spriteHeight) Then
        spriteData["Status"] = 0
        Shapes.HideShape(spriteData["image"])
      EndIf
      
      sprites[i] = spriteData 'enregistre le tableau modifié du sprite (il peut avoir été modifié)
    EndIf
  EndFor
EndSub
 
Sub FireMissile
  For i =  1 To numSprite
    spriteData = sprites[i] 'récupère le tableau du sprite courant
    If (spriteData["Status"] = 0) Then
      spriteData["Status"] = 1
      Shapes.ShowShape(spriteData["image"])
      spriteData["Xpos"] = GraphicsWindow.MouseX
      spriteData["Ypos"] = gh-spriteHeight
      
      sprites[i] = spriteData 'enregistre le tableau modifié du sprite (il peut avoir été modifié)
      i = numSprite 'Fin de la boucle
    EndIf
  EndFor
EndSub
 
Sub OnMouseDown
  mouseDown = "True"
EndSub

Supprimer des sprites

Ajouter et supprimer des sprites pendant le jeu peut être nécessaire dans certains cas, par exemple lorsque nous ne savons quelle image il va avoir avant d'en avoir besoin où lorsque le nombre de sprite ne peut pas être facilement géré par un pool de taille fixe. Cependant, le pool de sprites reste la meilleure approche la plupart du temps.

  • Un sprite peut être supprimé si on est certain qu'on en aura plus besoins. En plus de devoir supprimer le tableau de données du sprite, il est nécessaire de supprimer la "forme" du sprite (Shapes.Remove). Si le nombre de formes de sprite non supprimés augmente, votre programme va ralentir considérablement.
  • Pour supprimer des éléments dans un tableau nous devons affecter la valeur "".  Toutefois, si nous supprimons les items d'un tableau, l'indexation de ce tableau ne sera plus séquentielle (1, 2, 3 ...) et nous devrons utiliser Array.GetAllIndices pour obtenir les indices actuels.
  • Pour ajouter des sprites dans un tableau nous aurons besoin d'utiliser un index inutilisé ou nous risquons d'écraser un sprite existant.

Avec ces points à l'esprits, voici le code ajoutant et supprimant des sprites dans le tableau de missiles quand c'est nécessaire, pour comparer avec la méthode "pool".

gw = 600
gh = 600
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
GraphicsWindow.MouseDown = OnMouseDown
 
CreateSprites()
 
'Boucle de jeu
While ("True")
  start = Clock.ElapsedMilliseconds
  
  If (mouseDown) Then
    FireMissile()
    mouseDown = "False"
  EndIf
  UpdateSprites()
  
  delay = 20  - (Clock.ElapsedMilliseconds - start)
  If (delay  > 0) Then
    Program.Delay(delay)
  EndIf
EndWhile
 
Sub CreateSprites
  spriteImage = ImageList.LoadImage("http://litdev.co.uk/game_images/missile.png")
  'Les dimensions utilisées pour le sprite sont la moitié de la hauteur et de la largeur
  spriteWidth = ImageList.GetWidthOfImage(spriteImage)/2
  spriteHeight = ImageList.GetHeightOfImage(spriteImage)/2
  
  sprites = ""
  nextSprite = 1
EndSub
 
Sub UpdateSprites
  spriteIndices = Array.GetAllIndices(sprites)
  For i =  1 To Array.GetItemCount(spriteIndices)
    index = spriteIndices[i] 'index du sprite courant
    spriteData = sprites[index] 'récupére le tableau du sprite courant
    
    'Repositionne le centre du sprite
    spriteData["Xpos"] = spriteData["Xpos"] + spriteData["Xvel"]
    spriteData["Ypos"] = spriteData["Ypos"] + spriteData["Yvel"]
    
    'Déplace le centre du sprite
    Shapes.Move(spriteData["image"],spriteData["Xpos"]-spriteWidth,spriteData["Ypos"]-spriteHeight)
    
    'Ce sprite est terminé ?
    If (spriteData["Ypos"] < -spriteHeight) Then
      Shapes.Remove(spriteData["image"])
      Sprites[index] = ""
    Else        
      sprites[index] = spriteData 'enregistre le tableau modifié du sprite (il peut avoir changé)
    EndIf
  EndFor
EndSub
 
Sub FireMissile
  spriteData["image"] = Shapes.AddImage(spriteImage)
  spriteData["Xpos"] = GraphicsWindow.MouseX
  spriteData["Ypos"] = gh-spriteHeight
  spriteData["Xvel"] = 0
  spriteData["Yvel"] = -5
  sprites[nextSprite] = spriteData
  nextSprite = nextSprite+1
EndSub
 
Sub OnMouseDown
  mouseDown = "True"
EndSub

Conclusion

Bien que cet article et plutôt orienté manipulation des tableaux de sprite, les méthodes utilisées dans le dernier exemple correspondent réellement à de bonnes techniques générales à étudier pour améliorer votre programmation. Elles vous permettrons de mieux passer à votre prochain langage après le Small Basic, où vous rencontrerez certainement des notions de classes et de collections.

  • Garder toutes les données liées ensemble et créer des tableaux ou des listes de ces données si vous avez besoin d'en avoir des copies multiples.
  • Utiliser des sous-routines pour exécuter des tâches spécifiques.
  • Garder systématiquement une trace de où et quand vous créez et supprimez des données. En général, cette discipline donnera des résultats plus rapide, une plus faible maintenance et un code plus efficace avec moins de bugs qui seront plus faciles à détecter et à corriger.

Comme dernière suggestion, si la vitesse des tableaux Small Basic devient un facteur limitant, alors des méthodes d'extensions peuvent être utilisées pour améliorer les performances, par exemple l'objet LDList de l'extension LitDev (en-US) pour Small Basic.  L'objet LDList est décrit dans cet* *article TechNet (en-US).


Voir Aussi

Autres Langues