Conseils

Tutoriel pour la programmation de jeux 2D en C: Snake

Tutoriel pour la programmation de jeux 2D en C: Snake

Ce didacticiel a pour but d’enseigner la programmation de jeux en 2D et le langage C au moyen d’exemples. L'auteur avait l'habitude de programmer des jeux au milieu des années 1980 et était concepteur de jeux chez MicroProse pendant un an dans les années 90. Bien que la plupart de ces éléments ne soient pas pertinents pour la programmation des grands jeux 3D actuels, ils constitueront une introduction utile pour les petits jeux occasionnels.

Mise en œuvre de serpent

Des jeux tels que serpent où des objets se déplacent sur un champ 2D peuvent représenter les objets de jeu dans une grille 2D ou sous la forme d'un tableau d'objets à une seule dimension. "Objet" signifie ici n'importe quel objet du jeu, pas un objet utilisé dans la programmation orientée objet.

Contrôles de jeu

Les touches se déplacent avec W = haut, A = gauche, S = bas, D = droite. Appuyez sur Echap pour quitter le jeu, sur f pour basculer la cadence (ce qui n'est pas synchronisé avec l'affichage, donc rapide), sur la touche de tabulation pour basculer les informations de débogage et sur p pour la suspendre. Quand il est en pause, la légende change et le serpent clignote,

Dans le serpent les objets de jeu principaux sont

  • Le serpent
  • Pièges et fruits

Aux fins du jeu, un tableau d’entités contiendra chaque objet du jeu (ou une partie du serpent). Cela peut également aider lors du rendu des objets dans le tampon d'écran. J'ai conçu les graphiques pour le jeu comme suit:

  • Corps de serpent horizontal - 0
  • Corps de serpent vertical - 1
  • Tête en 4 x 90 degrés de rotation 2-5
  • Queue en 4 x 90 degrés de rotation 6-9
  • Courbes de changement de direction. 10-13
  • Apple - 14
  • Fraise - 15
  • Banane - 16
  • Piège - 17
  • Voir le fichier graphique serpent snake.gif

Il est donc logique d’utiliser ces valeurs dans un type de grille défini sous la forme blockWIDTH * HEIGHT. Comme il n'y a que 256 emplacements dans la grille, j'ai choisi de la stocker dans un tableau à une seule dimension. Chaque coordonnée sur la grille 16 x16 est un entier compris entre 0 et 255. Nous avons utilisé ints pour rendre la grille plus grande. Tout est défini par #defines avec WIDTH et HEIGHT 16. Comme la représentation graphique du serpent est de 48 x 48 pixels (GRWIDTH et GRHEIGHT #defines), la fenêtre est définie initialement comme étant 17 x GRWIDTH et 17 x GRHEIGHT légèrement plus grande que la grille. .

Cela présente des avantages en termes de vitesse de jeu, car l’utilisation de deux index est toujours plus lente qu’un, mais cela signifie que, au lieu d’ajouter ou de soustraire 1 des coordonnées Y du serpent pour se déplacer verticalement, vous soustrayez WIDTH. Ajoutez 1 pour aller à droite. Cependant, étant sournois, nous avons également défini une macro l (x, y) qui convertit les coordonnées x et y au moment de la compilation.

Qu'est-ce qu'une macro?

#define l (X, Y) (Y * WIDTH) + X

La première ligne est l’indice 0-15, la deuxième 16-31, etc. Si le serpent est dans la première colonne et qu’il se déplace à gauche, le contrôle pour toucher le mur, avant de se déplacer à gauche, doit vérifier si la coordonnée% WIDTH == 0 et pour la coordonnée du mur droit% WIDTH == WIDTH-1. Le% est l'opérateur du module C (comme l'arithmétique d'horloge) et renvoie le reste après la division. 31 div 16 feuilles un reste de 15.

Gérer le serpent

Il y a trois blocs (tableaux int) utilisés dans le jeu.

  • serpent, un anneau tampon
  • shape - Contient les index graphiques Snake
  • dir - Maintient la direction de chaque segment du serpent, y compris la tête et la queue.

Au début de la partie, le serpent a deux segments, une tête et une queue. Les deux peuvent pointer dans 4 directions. Au nord, la tête correspond à l'indice 3, la queue à 7, à la tête est à 4, à la queue 8, à la tête sud à 5 et à la queue 9, et à l'ouest à la tête 6 et à la queue 10. Bien que le serpent ait deux segments de long, la tête et la queue sont toujours séparées de 180 degrés, mais une fois que le serpent a grandi, elles peuvent atteindre 90 ou 270 degrés.

Le jeu commence avec la tête tournée vers le nord à l'emplacement 120 et la queue tournée vers le sud à 136 ° C, à peu près au centre. Avec un léger coût d'environ 1 600 octets de stockage, nous pouvons améliorer sensiblement la vitesse du jeu en maintenant les emplacements du serpent dans la mémoire tampon de l'anneau de serpent mentionnée ci-dessus.

Qu'est-ce qu'un tampon de sonnerie?

Une mémoire tampon en anneau est un bloc de mémoire utilisé pour stocker une file d'attente de taille fixe et suffisamment grande pour contenir toutes les données. Dans ce cas, c'est juste pour le serpent. Les données sont placées à l'avant de la file d'attente et retirées à l'arrière. Si l'avant de la file d'attente atteint la fin du bloc, il s'enroule autour. Tant que le bloc est assez grand, l'avant de la file d'attente ne rattrapera jamais l'arrière.

Chaque emplacement du serpent (c'est-à-dire la coordonnée int unique) de la queue à la tête (c'est-à-dire à l'envers) est stocké dans le tampon en anneau. Cela procure des avantages en termes de rapidité car peu importe la longueur du serpent, seuls la tête, la queue et le premier segment après la tête (s'il existe) doivent être changés au fur et à mesure de leur déplacement.

Le stocker à l'envers est également bénéfique, car lorsque le serpent aura de la nourriture, il grandira lorsqu'il sera déplacé. Pour ce faire, déplacez la tête d’un emplacement dans la mémoire tampon circulaire et modifiez l’ancien emplacement de la tête pour qu’il devienne un segment. Le serpent est composé d'une tête, de 0 à n segments), puis d'une queue.

Lorsque le serpent mange des aliments, la variable atefood est définie sur 1 et cochée dans la fonction DoSnakeMove ().

Déplacer le serpent

Nous utilisons deux variables d'index, headindex et tailindex, pour pointer vers les emplacements de tête et de queue dans le tampon circulaire. Celles-ci commencent à 1 (index en tête) et à 0. L'emplacement 1 dans le tampon en anneau contient l'emplacement (0-255) du serpent sur le tableau. L'emplacement 0 contient l'emplacement de la queue. Lorsque le serpent avance d'un emplacement, les éléments tailindex et headindex sont incrémentés d'un point et se retournent à 0 lorsqu'ils atteignent 256. Le lieu où se trouvait la tête se trouve donc là où se trouve la queue.

Même avec un très long serpent qui s'enroule et se convole par 200 segments. seuls le headindex, le segment situé à côté de la tête et le tailindex changent à chaque mouvement.

Notez qu'en raison du fonctionnement de SDL, nous devons dessiner le serpent entier à chaque image. Chaque élément est dessiné dans le frame buffer puis retourné pour être affiché. Cela présente toutefois un avantage: nous pouvons dessiner le serpent en déplaçant doucement quelques pixels, et non une position entière de la grille.