Outils pour utilisateurs

Outils du site


nsi:tds:pygame:snake

Ceci est une ancienne révision du document !



Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Snake sur Pygame

Présentation

On se propose de réaliser un jeu de serpent sur Pygame. Le jeu du serpent a un principe simple : on contrôle un serpent sur une grille, on peut le faire aller en haut, en bas, à gauche et à droite.

  • C'est la tête du serpent que l'on contrôle. Les anneaux du serpents passent toujours par les mêmes cases que les anneaux précédents.
  • Si la tête du serpent percute un de ses anneaux, c'est perdu.
  • Des récompenses apparaissent aléatoirement. Quand le serpent passe dessus, il grandit.
  • Le serpent devient donc de plus en plus long et il est de plus en plus difficile de le déplacer sans qu'il se croque lui même.

Pour les premières : Pygame utilise la programmation orientée objet. On parle de classes et des objets. On peut s'en sortir sans comprendre tous les détails.

L'idée générale est la suivante : En Python, on dispose d'entités de formes diverses. On a des entiers, des tableaux… On a le droit de manipuler ces entités, elles ont des propriété. Par exemple on peut faire len sur un tableau et une chaîne mais pas sur un entier.

Une classe permet de définir une nouvelle entité et ses propriétés. La classe est donc une sorte de plan de construction et un manuel d'utilisation. Les entités crées selon se modèle sont appelées des objets. Quand on crée un objet, on dit qu'on l'instancie.

Dit autrement, par exemple, on peut parler du concept de pomme. Qu'est ce que c'est qu'une pomme ? à quoi on la reconnaît ? qu'est ce qu'on peut faire avec ? Toutes ces considérations abstraites, c'est la classe. Quand on a une vraie pomme, c'est une instance de pomme.

Les modules

Nous allons créer 2 modules et un principal. Un premier module définira le fonctionnement du serpent. Un second module définira les récompenses.

Les récompenses

C'est extrêmement simple et cela va permettre de présenter des choses.

# fichier apple.py
import pygame

class Apple(pygame.sprite.Sprite):
    COLOR = (255,100,0)
    SIZE = 20
    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

Dans les versions classiques du Snake, le serpent mange des pommes, c'est pourquoi j'ai appelé la récompense Apple.

Dans ce module bien sûr, on import pygame.

signature de la classe
class Apple(pygame.sprite.Sprite):

signifie que l'on crée un modèle Apple. Ce modèle est censé être un objet graphique, un sprite. Gérer le graphique n'est jamais simple c'est pourquoi on utilise une bibliothèque comme Pygame.

(pygame.sprite.Sprite) signifie que notre modèle reprend tout un tas de définitions déjà faites par Pygame. Notre Apple sera donc un sprite.

constantes de classe
    COLOR = (255,100,0)
    SIZE = 20

Ces constantes nous permettent de définir l'apparence de la pomme. Pour nous, ce sera un simple carré de couleur. La couleur est définie en RGB, ici c'est du rouge. SIZE nous donne la taille en pixels. La pomme sera donc un carré rouge de 20 pixels de côté.

Comme ces constantes sont définies à l'intérieur de la classe, on peut les atteindre en écrivant Apple.COLOR par exemple, ou bien self.COLOR quand on parle depuis l'intérieur de la classe.

initialisation
    def __init__(self, x, y):

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.

Dans toutes les fonctions de la classe (on dit des méthodes), self représente la pomme elle même.

Dans ce cas, on veut créer la pomme quelque à la position x et y.

super
    super().__init__()

Comme notre Apple est un sprite Pygame, Pygame a déjà défini sa propre fonction d'initialisation. Cette ligne permet d'appeler l'initialisation Pygame de sorte que notre Apple ait bien toutes les caractéristiques nécessaires pour que Pygame en fasse un sprite valable.

Nous pourrons poursuivre avec nos initialisations.

Le graphique
    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

Les sprites Pygame ont toujours un attribut image et un attribut rect.

  • image définit ce qui est affiché. Ici on crée une surface carrée que l'on remplit en couleur.
  • rect représente le cadre où sera affiché cette image. Si nous voulions pouvoir déplacer le sprite, il faudrait jouer sur rect.

Le main avec les récompenses

# fichier main.py
import pygame
from random import randrange
pygame.init() # initialisation de pygame

from apple import Apple

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 = pygame.srpite.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.add(apple)      # ajout de la pomme au groupe de tous les sprites

# 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

    # dessine les sprites
    all.draw(screen)

    # met à jour l'affichage
    pygame.display.flip()


# boucle finie
pygame.quit() # lance la fermeture de la fenêtre

Le code est commenté, vous devriez comprendre.

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.

# 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

Le main avec la tête de serpent

Le main avec les récompenses

# 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 = pygame.srpite.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.add(apple)      # ajout de la pomme au groupe de tous les sprites

# création de la tête    
head = Head(300,200)
all.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.draw(screen)

    # met à jour l'affichage
    pygame.display.flip()


# boucle finie
pygame.quit() # lance la fermeture de la fenêtre

Il reste à faire...

  • 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
nsi/tds/pygame/snake.1683884602.txt.gz · Dernière modification : de goupillwiki