Outils pour utilisateurs

Outils du site


nsi:tds:pygame:snake

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Prochaine révision
Révision précédente
nsi:tds:pygame:snake [2023/05/12 11:20] – créée goupillwikinsi:tds:pygame:snake [2023/05/13 23:57] (Version actuelle) goupillwiki
Ligne 78: Ligne 78:
 Cette fonction spéciale (en Python, les ''%%__%%'' indiquent toujours quelque chose de particulier) sert à la création de l'objet. Cette fonction spéciale (en Python, les ''%%__%%'' indiquent toujours quelque chose de particulier) sert à la création de l'objet.
  
-Quand on va créer un objet ''Apple'', Python va réserver l'espace nécessaire en mémoire puis va automatiquement appeler la fonction ''%%__init__%% pour l'initialiser.+Quand on va créer un objet ''Apple'', Python va réserver l'espace nécessaire en mémoire puis va automatiquement appeler la fonction ''%%__init__%%'' pour l'initialiser.
  
 Dans toutes les fonctions de la classe (on dit des méthodes), ''self'' représente la pomme elle même. Dans toutes les fonctions de la classe (on dit des méthodes), ''self'' représente la pomme elle même.
Ligne 130: Ligne 130:
 # c'est plus simple quand on met les sprites dans des groupes # c'est plus simple quand on met les sprites dans des groupes
 apples = pygame.sprite.Group() # groupe contenant les pommes apples = pygame.sprite.Group() # groupe contenant les pommes
 +all_sprites = pygame.sprite.Group()    # groupe contenant tous les sprites
  
 # ajout de 15 pommes # ajout de 15 pommes
Ligne 136: Ligne 137:
     y = randrange(100, 400)     y = randrange(100, 400)
     apple = Apple(x, y) # création de la pomme en x, y     apple = Apple(x, y) # création de la pomme en x, y
-    apples.add(candy)   # ajout de la pomme crée dans le groupe des pommes+    apples.add(apple)   # ajout de la pomme crée dans le groupe des pommes 
 +    all_sprites.add(apple)      # ajout de la pomme au groupe de tous les sprites
  
 # lancement d'une boucle assurant le rafraichissement du jeu # lancement d'une boucle assurant le rafraichissement du jeu
Ligne 156: Ligne 158:
             running = False # permet la fin de la boucle             running = False # permet la fin de la boucle
  
-    # dessine les pommes +    # dessine les sprites 
-    apples.draw(screen)+    all_sprites.draw(screen)
  
     # met à jour l'affichage     # met à jour l'affichage
Ligne 170: Ligne 172:
  
 Avec le module ''apple.py'', ce programme est déjà fonctionnel. Mais il n'affiche que des pommes fixes et pas de serpent... Avec le module ''apple.py'', ce programme est déjà fonctionnel. Mais il n'affiche que des pommes fixes et pas de serpent...
 +
 +==== La tête du serpent ====
 +
 +On va se contenter pour l'instant d'un anneau de serpent que l'on pourra déplacer avec les flèches du clavier.
 +
 +<code python>
 +# fichier snake.py
 +import pygame
 +
 +class Head(pygame.sprite.Sprite):
 +    COLOR = (0, 255, 0)
 +    SIZE = 20
 +    VELOCITY = 2 # vitesse du serpent
 +    def __init__(self, x, y):
 +        super().__init__()
 +        self.image = pygame.Surface((self.SIZE, self.SIZE))
 +        self.image.fill(self.COLOR)
 +        self.rect = self.image.get_rect()
 +        self.rect.x = x
 +        self.rect.y = y
 +        self.vx = 0
 +        self.vy = 0
 +
 +    def move_up(self):
 +        # amorce un mouvement vers le haut
 +        # attention, sur l'écran, aller vers le haut, c'est diminuer les y !
 +        if self.vy > 0:
 +            # interdit d'aller dans le sens opposé -> sort de la fonction sans rien faire
 +            return
 +        self.vy = - self.VELOCITY
 +        self.vx = 0
 +
 +    def move_down(self):
 +        # amorce un mouvement vers le haut
 +        # attention, sur l'écran, aller vers le bas, c'est augmenter les y !
 +        if self.vy < 0:
 +            # interdit d'aller dans le sens opposé -> sort de la fonction sans rien faire
 +            return
 +        self.vy = self.VELOCITY
 +        self.vx = 0
 +
 +    def move_left(self):
 +        if self.vx > 0:
 +            # interdit d'aller dans le sens opposé -> sort de la fonction sans rien faire
 +            return
 +        self.vx = - self.VELOCITY
 +        self.vy = 0
 +
 +    def move_right(self):
 +        if self.vx < 0:
 +            # interdit d'aller dans le sens opposé -> sort de la fonction sans rien faire
 +            return
 +        self.vx = self.VELOCITY
 +        self.vy = 0
 +
 +    def update_position(self):
 +        # modifie les coordonnees selon la vitesse en cours
 +        self.rect.x += self.vx
 +        self.rect.y += self.vy
 +</code>
 +
 +==== Le main avec la tête de serpent ====
 +
 +==== Le main avec les récompenses ====
 +
 +<code python>
 +# fichier main.py
 +import pygame
 +from random import randrange
 +pygame.init() # initialisation de pygame
 +
 +from apple import Apple
 +from snake import Head
 +
 +clock = pygame.time.Clock() # Pour contrôler la vitesse d'affichage
 +
 +# création de la zone de dessin
 +WIDTH = 600
 +HEIGHT = 500
 +screen = pygame.display.set_mode((WIDTH, HEIGHT))
 +
 +# c'est plus simple quand on met les sprites dans des groupes
 +apples = pygame.sprite.Group() # groupe contenant les pommes
 +all_prites = pygame.sprite.Group()    # groupe contenant tous les sprites
 +
 +# ajout de 15 pommes
 +for i in range(15):
 +    x = randrange(100, 500)
 +    y = randrange(100, 400)
 +    apple = Apple(x, y) # création de la pomme en x, y
 +    apples.add(apple)   # ajout de la pomme crée dans le groupe des pommes
 +    all_sprites.add(apple)      # ajout de la pomme au groupe de tous les sprites
 +
 +# création de la tête    
 +head = Head(300,200)
 +all_sprites.add(head)
 +    
 +# lancement d'une boucle assurant le rafraichissement du jeu
 +running = True
 +BLACK = (0,0,0) # couleur noire
 +while running:
 +    clock.tick(60) # limite a 60 fps (frames per second)
 +
 +    # remplit le fond en noir pour créer la prochaine image
 +    screen.fill(BLACK)
 +
 +    # La gestion des éléments du jeu aura lieu ici : déplacement du personnage
 +    # apparition des bonbons, etc.
 +
 +    for event in pygame.event.get():
 +        # parcours les événements qui se sont produit
 +        if event.type == pygame.QUIT:
 +            # c'est un événement de type fermeture de fenêtre
 +            running = False # permet la fin de la boucle
 +
 +    # récupère la liste des états des touches
 +    keys = pygame.key.get_pressed()
 +    if keys[pygame.K_LEFT] and not keys[pygame.K_RIGHT]:
 +        # la touche flèche gauche est appuyée mais pas la flèche droite
 +        head.move_left()
 +    elif keys[pygame.K_RIGHT] and not keys[pygame.K_LEFT]:
 +        # la touche flèche droite est appuyée
 +        head.move_right()
 +    if keys[pygame.K_UP] and not keys[pygame.K_DOWN]:
 +        # la touche flèche haut est appuyée mais pas la flèche bas
 +        head.move_up()
 +    elif keys[pygame.K_DOWN] and not keys[pygame.K_UP]:
 +        # la touche flèche bas est appuyée mais pas la flèche haut
 +        head.move_down()
 +
 +    # met à jour la tête
 +    head.update_position()
 +
 +    # la tête touche-t-elle une pomme ?
 +    # l'argument True indique que les pommes touchées sont détruites
 +    hits = pygame.sprite.spritecollide(head, apples, True)
 +    n = len(hits)
 +    # pour l'instant on ne fait rien de n, on se contente de l'afficher en console
 +    if n > 0:
 +        print("mangé !")
 +
 +    # dessine les pommes
 +    all_sprites.draw(screen)
 +
 +    # met à jour l'affichage
 +    pygame.display.flip()
 +
 +
 +# boucle finie
 +pygame.quit() # lance la fermeture de la fenêtre
 +</code>
 +
 +===== Il reste à faire... =====
 +
 +  * ne faire apparaître les pommes qu'alignés sur une grille,
 +  * adapter le mouvement pour obéir à une logique de grille,
 +  * prévoir les anneaux du serpent et les faire se déplacer convenablement,
 +  * augmenter la taille du serpent à mesure qu'il mange,
 +  * faire perdre quand le serpent touche un bord ou quand il se croque lui-même,
 +  * afficher un score
 +
 +== Aligner sur une grille ==
 +
 +Les pommes on un taille ''Apple.SIZE = 20''. On voudrait qu'elle ne puissent avoir que des coordonnées en 0, 20, 40, 60, ... de sorte qu'elles ne tombent pas sur n'importe quelles coordonnées mais sur une grille.
 +
 +C'est rapide à faire : si ''x'' est  un entier quelconque et qu'on veut le ramener à un multiple de ''Apple.SIZE'', il suffit de faire le calcul ''x -= x % Apple.SIZE'' (ou ''self.SIZE'' si on fait ce calcul depuis l'intérieur de la classe).
 +
 +De la même façon, on désire que le serpent ne puisse tourner que quand il est aligné sur une grille. C'est simple également : il suffit n'autoriser le changement de sens que quand les coordonnées sont multiples de ''SIZE''.
 +
 +<code python>
 +self.rect.x % self.SIZE == 0 and self.rect.y % self.SIZE == 0
 +</code>
 +
 +plusieurs approche sont possibles :
 +  * ne permettre le changement que quand la tête est alignée. Autrement dit une pression sur un bouton est ignorée si elle n'est pas faite au moment de l'alignement,
 +  * enregistrer le dernier bouton appuyé mais n'en tenir compte qu'au prochain alignement.
 +
 +== Créer un anneau ==
 +
 +On peut créer la classe ''Anneau'' dans le module ''snake.py''. L'anneau sera très proche de ''Head''. Voici ce que l'on pourrait faire :
 +  * définir ''class Anneau(Head):'' de sorte que l'anneau hérite de toutes les fonctions de ''Head''.
 +  * modifier la fonction ''__init__'' : quand on crée un anneau, on le superpose avec le dernier anneau du serpent. Cette anneau sera l'anneau précédent. L'anneau créé devra suivre l'anneau précédent d'une certaine façon et devra donc toujours se rappeler son anneau précédent. Un anneau est donc comme une tête qui a un anneau précédent...\\ <code python>
 +def __init__(self, precedent):
 +    super().__init__(precedent.rect.x, precedent.rect.y)
 +    self.precedent = precedent
 +</code>
 +  * enfin modifier la fonction ''update_position'' de façon à, si l'anneau est aligné et si le précédent est à au moins une distance ''SIZE'' d'ajuster la vitesse.\\ <code python>
 +def update_position(self):
 +    # code disant : si aligné
 +    #     si précédent assez loin
 +    #         ajuster la vitesse
 +    super().update_position() # pour le reste, faire comme avec Head
 +</code>
 +
 +
 +
 +
 +
  
nsi/tds/pygame/snake.1683883258.txt.gz · Dernière modification : de goupillwiki