91 views
# Créer le jeu du Serpent à l'aide du module Pyxel ## Objectif élève À la fin de la séquence, les élèves doivent obtenir un Snake où : - Le serpent se déplace automatiquement sur une grille. - L’utilisateur peut changer la direction avec les flèches du clavier. - Une pomme apparaît ; si le serpent la mange, il grandit et le score augmente. - La partie se termine en cas de collision avec un mur ou avec soi-même. ## I – Prise en main de Pyxel & grille de jeu Le point de départ est la construction d'une grille dans laquelle le serpent peut se déplacer. La commande `pyxel.rect(20, 30, 40, 50, 8)` permet de dessiner un rectangle de couleur rouge dont le coin supérieur gauche a pour coordonnées `(20, 30)`, une largeur de `40` et une hauteur de `50`. Le canevas de code ci-dessous que vous allez recopier dans votre interface Thonny pour démarrer le travail ``` python import pyxel LARGEUR = 128 HAUTEUR = 128 TAILLE_CASE = 8 def update(): # à faire : logique du jeu pass def draw(): pyxel.cls(0) # fond noir, on efface l'écran pyxel.rect(20, 30, 40, 50, 8) # tracer du rectangle d'exemple pyxel.init(LARGEUR, HAUTEUR, title="Snake - proto") pyxel.run(update, draw) ``` **à faire :** - modifier la taille du rectangle ainsi que sa position - à l'aide d'une ou 2 boucle(s), générer un pavage de l'écran de façon à dessiner un échiquier de 16x16 ## II - Gestion du déplacement de la tête du serpent La tête du serpent se déplace en permanence est n'est jamais immobile. elle est définie par sa position `x` et `y` et de sa *vitesse* `vx` et `vy` on peut la définir par un dictionnaire : ```python snake = {'x':64,'y':64,'vx':1,'vy':0} ``` Ainsi le serpent apparaît initialement au milieu de l'écran et on attend qu'il se déplace horizontalement vers la gauche. Il est maintenant possible de compléter la partie `update()` qui se charge de prendre en compte les touches sur lesquelles le joueur appuie pour faire changer la direction du snake, puis gère son déplacement ```python import pyxel LARGEUR = 128 HAUTEUR = 128 TAILLE_CASE = 8 snake = {'x':64,'y':64,'vx':1,'vy':0} def update(): global snake if pyxel.btn(pyxel.KEY_UP): snake['vy'] = # pour aller vers le up # mais il faut aussi compléter pour ne pas continuer dans la direction précédente ! if pyxel.btn(pyxel.KEY_DOWN): snake['vy'] = # pour aller vers le bas if pyxel.btn(pyxel.KEY_LEFT): snake['vx'] = # pour aller vers la gauche if pyxel.btn(pyxel.KEY_RIGHT): snake['vx'] = # pour aller vers la droite snake['x'] += snake['vx'] snake['y'] += snake['vy'] def draw(): pyxel.cls(0) # fond noir, on efface l'écran pyxel.rect(snake['x'], snake['y'], 8, 8, 8) # tracer de la tete pyxel.init(LARGEUR, HAUTEUR, title="Snake - proto") pyxel.run(update, draw) ``` **à faire :** - compléter le code pour pouvoir commander le déplacement du serpent - corriger de façon à ce qu'il ne se déplace qu'à vitesse constante et pas en diagonale - faire en sorte que s'il sorte de l'écran à droite, il réapparaisse à gauche et inversement et que s'il sort par le haut, il réapparaisse vers le bas et inversement - (pour plus tard) : le serpent ne peut pas partir immédiatement dans la direction opposée à son déplacement ## III - On ajoute le corps ! dans un premier temps, votre serpent ne contient que 3 segments : - une tête - 2 segments pour le corps cela fait qu'on ne va définir le corps que comme une liste supplémentaire de coordonnées : `corps = [(x1,y1),(x2,y2)]` **à faire :** - Compléter le code pour qu'initialement le serpent ait sa tête aux coordonnées (64,64) et que son corps soit horizontal sur sa gauche - le corps doit suivre la tête : pour cela il est nécessaire qu'à chaque frame la nouvelle coordonnée de la 1ere entrée du corps soit remplacée par les *anciennes* coordonnées de la tête du serpent avant que celle-ci ne soit mise à jour par le mouvement ; et la 2nde entrée du corps doit être remplacée par la coordonnée de la 1ere entrée avant que celle-ci ne soit effacée ! => Ecrire une fonction `ramper()` qui se chargera de transferer les coordonnées de la tête au corps pouis entre chaque segment du corps - la fonction `draw` dessine le corps du serpent d'une façon différente de la tête afin que le joueur puisse la différencier ## IV - on ajoute les pommes On ajoute une liste `pommes = []` qui va contenir des pommes que le serpent doit attraper. **à faire :** - Générer la fonction `new_pomme()` qui ajoute à la liste `pommes` un *tuple* de coordonnées aléatoires **entières et multiples de 8** à l'intérieur de l'écran - dans `draw()` faire une boucle affichant les pommes en traçant des cercles de la couleur de votre choix au milieu des cases ## V - Gestion des collisions **à faire :** - lorsque le serpent arrive sur une pomme, celle-ci est supprimée de la liste `pommes` - le serpent gagne un segment de corps lorsqu'une pomme est mangée - le jeu s'arrête lorsque la tête du serpent entre en collision avec une partie de son corps ##### corrigé ##### ```python import pyxel import random LARGEUR = 128 HAUTEUR = 128 NB_CASES = 16 TAILLE_CASE = LARGEUR // NB_CASES snake = {'x':64,'y':64,'vx':8,'vy':0} corps = [(56, 64), (48, 64)] pommes = [] max_pommes = 5 def new_pomme(): global max_pommes pomme_x = random.randrange(0,NB_CASES) * TAILLE_CASE pomme_y = random.randrange(0,NB_CASES) * TAILLE_CASE pommes.append((pomme_x, pomme_y)) if len(pommes) > max_pommes : pommes.pop(0) def ramper(): for i in range(len(corps) - 1, 0,-1): corps[i] = corps[i - 1] corps[0] = (snake['x'],snake['y']) def update(): global snake if pyxel.btn(pyxel.KEY_UP) and snake['vy'] == 0: snake['vy'] = -8 snake['vx'] = 0 # mais il faut aussi compléter pour ne pas continuer dans la direction précédente ! if pyxel.btn(pyxel.KEY_DOWN) and snake['vy'] == 0: snake['vy'] = 8# pour aller vers le bas snake['vx'] = 0 if pyxel.btn(pyxel.KEY_LEFT) and snake['vx'] == 0: snake['vx'] = -8# pour aller vers la gauche snake['vy'] = 0 if pyxel.btn(pyxel.KEY_RIGHT) and snake['vx'] == 0: snake['vx'] = 8# pour aller vers la droite snake['vy'] = 0 if pyxel.frame_count % 8 == 0: # on ne gère les déplacements que toutes les 8 frames if random.random() < 0.25 : new_pomme() ramper() snake['x'] += snake['vx'] snake['y'] += snake['vy'] if snake['x'] < 0 : snake['x'] = 128 if snake['y'] < 0 : snake['y'] = 128 if snake['x'] > 128 : snake['x'] = 0 if snake['y'] > 128 : snake['y'] = 0 def draw(): pyxel.cls(7) # fond noir, on efface l'écran for x in range(0, 128, 16): for y in range(0, 128, 8): k = 0 if (y // 8) % 2 == 1: k = 8 pyxel.rect(x + k, y, 8, 8, 13) # tracer du rectangle d'exemple for i in range(len(pommes)): pyxel.circ(pommes[i][0] + 4, pommes[i][1] + 4, 3, 5+i) for segment in corps: pyxel.rect(segment[0], segment[1], 8, 8, 8) pyxel.rect(snake['x'], snake['y'], 8, 8, 14) # tracer de la tete pyxel.init(LARGEUR, HAUTEUR, title="Snake - proto") pyxel.run(update, draw) ```