Académie
Snake (Python)
Marquer des points

Marquer des points

Étape 5

Gestion de l'extension de la queue du serpent.
Gestion et affichage du score.

Quand le serpent s'allonge...

On va maintenant s'intéresser à la progression du jeu et à l'accroissement de la difficulté, qui est corrélée à l'allongement de la queue du serpent. Ce phénomène se produit à chaque fois que le serpent avale une pomme.

Commençons par écrire une fonction extendSnakeTail() qui va gérer l'allongement de la queue :

# ----------------------------------------------------------
# Snake management
# ----------------------------------------------------------

def extendSnakeTail():
    i = snake['head']
    n = snake['len']
    i = (i + 1) % n
    x = snake['x'][i]
    y = snake['y'][i]
    for _ in range(SNAKE_EXTENT):
        snake['x'].insert(i, x)
        snake['y'].insert(i, y)
    snake['len'] += SNAKE_EXTENT

Cette fonction s'appuie sur une nouvelle variable globale qui détermine la longueur de queue supplémentaire, c'est-à-dire le nombre de tronçons qu'on va ajouter au serpent :

# ----------------------------------------------------------
# Global variables
# ----------------------------------------------------------

SNAKE_EXTENT = 2

La fonction extendSnakeTail() est relativement simple :

On commence par se positionner sur l'extrémité de la queue du serpent (qui se trouve être la case qui suit immédiatement la tête) au niveau des listes snake['x'] et snake['y'] :

i = snake['head']
n = snake['len']
i = (i + 1) % n

On pioche alors la position (x,y) de l'extrémité de la queue :

x = snake['x'][i]
y = snake['y'][i]

Puis on va insérer, toujours à l'extrémité de la queue, des copies de x et y (SNAKE_EXTENT copies plus précisément) :

for _ in range(SNAKE_EXTENT):
    snake['x'].insert(i, x)
    snake['y'].insert(i, y)

Enfin, on met à jour la propriété qui caractérise la longueur des listes snake['len'] :

snake['len'] += SNAKE_EXTENT

Voilà un schéma qui résume la succession des opérations effectuées :

Gamebuino META

Par conséquent, les 2 tronçons supplémentaires occupent initialement la même position que celui de l'extrémité de la queue (puisque ce sont des copies). Ils se « dérouleront » progressivement au fur et à mesure que le serpent avancera sur la grille.

Il ne reste plus qu'à intégrer cette routine au niveau de l'ordonnanceur :

# ----------------------------------------------------------
# Game management
# ----------------------------------------------------------

def tick():
    if game['mode'] == MODE_START:
        resetSnake()
        spawnApple()
        game['mode'] = MODE_READY
    elif game['mode'] == MODE_READY:
        handleButtons()
        moveSnake()
        if snakeHasMoved():
            game['mode'] = MODE_PLAY
    elif game['mode'] == MODE_PLAY:
        handleButtons()
        moveSnake()
        if didSnakeEatApple():
            extendSnakeTail()
            spawnApple()
        if didSnakeBiteItsTail() or didSnakeHitTheWall():
            game['mode'] = MODE_START

    draw()

L'extension de la queue s'effectue pendant la phase MODE_PLAY lorsque le serpent avale une pomme :

if didSnakeEatApple():
    extendSnakeTail()
    spawnApple()

Et voilà ! Démonstration :

Démo

Parfait ! Maintenant, on va pouvoir s'occuper du score du joueur...

Gestion du score

Pour mémoriser le score au fur et à mesure de la progression du jeu, on va le stocker au niveau du moteur de jeu game :

# ----------------------------------------------------------
# Initialization
# ----------------------------------------------------------

game = {
    'mode':  MODE_START,
    'score': 0
}

Ensuite, on va l'incrémenter à chaque fois que le serpent avale une pomme. Et il ne faut pas oublier de le réinitialiser à chaque fois que le jeu passe en phase MODE_START :

# ----------------------------------------------------------
# Game management
# ----------------------------------------------------------

def tick():
    if game['mode'] == MODE_START:
        resetSnake()
        spawnApple()
        game['mode'] = MODE_READY
        game['score'] = 0
    elif game['mode'] == MODE_READY:
        handleButtons()
        moveSnake()
        if snakeHasMoved():
            game['mode'] = MODE_PLAY
    elif game['mode'] == MODE_PLAY:
        handleButtons()
        moveSnake()
        if didSnakeEatApple():
            game['score'] += 1
            extendSnakeTail()
            spawnApple()
        if didSnakeBiteItsTail() or didSnakeHitTheWall():
            game['mode'] = MODE_START

    draw()

Réinitialisation du score en début de partie :

if game['mode'] == MODE_START:
    resetSnake()
    spawnApple()
    game['mode'] = MODE_READY
    game['score'] = 0

Augmentation du score à chaque fois que le serpent avale une pomme :

if didSnakeEatApple():
    game['score'] += 1
    extendSnakeTail()
    spawnApple()

Il ne reste plus qu'à afficher le score ! Pour cela on va définir une nouvelle variable globale pour déterminer sa couleur d'affichage :

# ----------------------------------------------------------
# Global variables
# ----------------------------------------------------------

COLOR_SCORE = 0xffff

Puis on va ajouter une fonction drawScore() qui sera chargée de l'afficher à l'écran, qu'on appellera à partir de la méthode principale draw(), responsable de l'affichage global de la scène de jeu :

# ----------------------------------------------------------
# Graphic display
# ----------------------------------------------------------

def draw():
    clearScreen()
    drawWalls()
    drawSnake()
    drawScore()
    drawApple()

def drawScore():
    display.setColor(COLOR_SCORE)
    display.print(2, 2, game['score'])

Le score est affiché aux coordonnées (2,2).

Allez !... On sauve le script et on peut maintenant admirer le résultat :

Démo

On a pratiquement terminé notre Snake !  

Il nous reste à optimiser un peu les choses et à apporter quelques touches de finitions pour terminer la partie en beauté.

Direction la prochaine étape !

Etape suivante