Pygame: des exemples pour débuter

De Centre de Ressources Numériques - Labomedia
Révision de 20 septembre 2015 à 09:14 par Serge (discussion | contributions) (Installation de pygame et kivy pour python 2.7)

(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à : navigation, rechercher

La documentation pygame officielle est touffue, difficile à parcourir et pas toujours à jour.

Il est parfois difficile de trouver comment faire certaines choses simples, comme créer une fenêtre bleue et non pas noire.

Il ne faut surtout pas télécharger les sources sur http://pygame.org/download.shtml mais sur bitbucket.org.

Avis tout à fait personnel et partial. pygame est utilisé par des étudiants qui partagent leurs jeux,

  • leur code est loin d'être au top
  • pourquoi faire simple quand on peut faire compliqué ?
  • trop souvent mal ou pas documenté !

Ce qui suis a été testé avec python 3.4.

Ressources

Beaucoup d'exemple datent de 2002 à la création de pygame ! et repris ... repris ...

Installation depuis un PPA

Installation de pygame et kivy pour python 3

Vérifié sur Linux Mint 17 Qiana

sudo add-apt-repository ppa:thopiekar/pygame
sudo add-apt-repository ppa:kivy-team/kivy
sudo apt-get update
sudo apt-get install python3-kivy

Ça n'installe pas pygame !!

sudo apt-get install mercurial
sudo pip3 install hg+http://bitbucket.org/pygame/pygame

Installation de pygame et kivy pour python 2.7

sudo apt-get install python-kivy

pygame:

sudo apt-get install mercurial
sudo pip install hg+http://bitbucket.org/pygame/pygame

Fichiers

Pourquoi importer pygame.locals ?

Le module pygame.locals contient quelques variables telles que les types d'evénement (QUIT, KEYDOWN, etc.) et touches clavier (K_ESCAPE, K_LEFT, etc.). Avec la syntaxe from pygame.locals import *, on utilise QUIT à la place de pygame.locals.QUIT.

Comme je n'arrive pas à trouver la liste de ces variables, je trouve que c'est du bordel, et on va s'en passer ! Je crée donc je suis dangereux. De toute façon, en python, on préfère l'explicite à l'implicite.

Redimensionnement de la fenêtre

http://www.pygame.org/wiki/WindowResizing?parent=CookBook Ce n'est pas simple car il faut gérer les objets dans la nouvelle fenêtre, donc on ne le fait pas.

Une fenêtre avec un fond bleu

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import pygame

# Before you can do much with pygame, you will need to initialize it
pygame.init()
# Init de clock
clock = pygame.time.Clock()

CIEL = 0, 200, 255  # parenthèses inutiles, l'interpréteur reconnaît un tuple

def main():
    fenetre = pygame.display.set_mode((640, 480))

    # loop
    loop = True
    # Création d'une image de la taille de la fenêtre
    background = pygame.Surface(fenetre.get_size())

    while loop:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = False

        # Superposition du fond ciel
        background.fill(CIEL)
        fenetre.blit(background, (0, 0))

        # Rafraîchissement de l'écran
        pygame.display.flip()
        # By calling Clock.tick(10) once per frame, the program will never run
        # at more than 10 frames per second
        clock.tick(10)

if __name__ == '__main__':
    main()

Texte

Liste des polices possibles

print(pygame.font.get_fonts())

Un texte orange sur fond bleu

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import pygame

pygame.init()
clock = pygame.time.Clock()

CIEL = 0, 200, 255
ORANGE = 255, 100, 0

def main():
    fenetre = pygame.display.set_mode((640, 480))

    loop = True
    while loop:
        background = pygame.Surface(fenetre.get_size())
        background.fill(CIEL)

        # Définition de la police
        bigText = pygame.font.SysFont('freesans', 36)

        # Définition du texte
        # render(text, antialias, rgb color tuple)
        title_text = bigText.render("Maître Corbeau sur un arbre perché",
                                    True, ORANGE)
        # Position: horizontal au centre , vertical = 50
        # Le centre du texte est au centre quelque soit le texte
        # Le texte est inscrit dans un rectangle
        textpos = title_text.get_rect()
        # Placement du texte en x et y
        textpos.centerx = fenetre.get_rect().centerx
        textpos.centery = 50

        # Collage du texte sur le fond
        background.blit(title_text, textpos)

        # Ajout du fond dans la fenêtre
        fenetre.blit(background, (0, 0))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = False

        # Actualisation de l'affichage
        pygame.display.flip()
        # 10 fps
        clock.tick(10)

if __name__ == '__main__':
    main()

Des rectangles comme boutons

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

import pygame

pygame.init()
clock = pygame.time.Clock()

CIEL = 0, 200, 255
WHITE = 255, 255, 255
GREEN = 0, 255, 0
RED = 255, 0, 0

def main():
    fenetre = pygame.display.set_mode((640, 480))
    loop = True
    green_color = GREEN
    white_color = WHITE
    while loop:
        background = pygame.Surface(fenetre.get_size())
        background.fill(CIEL)

        # Ajout du fond dans la fenêtre
        fenetre.blit(background, (0, 0))

        # Draw a rectangle outline
        rect_white = pygame.draw.rect(fenetre, white_color, [75, 10, 100, 50],
                                        5)
        # Draw a solid rectangle
        rect_green = pygame.draw.rect(fenetre, green_color, [250, 10, 100, 50])

        # retourne 1 si le curseur est au dessus du rectangle
        mouse_xy = pygame.mouse.get_pos()
        over_white = rect_white.collidepoint(mouse_xy)
        over_green = rect_green.collidepoint(mouse_xy)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = False
            # si clic, le vert devient rouge
            elif event.type == pygame.MOUSEBUTTONDOWN and over_green:
                green_color = RED
            # le rectangle se cache
            elif event.type == pygame.MOUSEBUTTONDOWN and over_white:
                white_color = CIEL

        # Actualisation de l'affichage
        pygame.display.flip()
        # 10 fps
        clock.tick(10)

if __name__ == '__main__':
    main()

Une ébauche d'interface graphique

#! /usr/bin/env python3
# -*- coding: utf-8 -*-

# server_gui.py

#############################################################################
# Copyright (C) Labomedia February 2015
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franproplin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#############################################################################

import pygame
import sys

pygame.init()
clock = pygame.time.Clock()

BLACK = 0, 0, 0
WHITE = 255, 255, 255
CIEL = 0, 200, 255
RED = 255, 0, 0
ORANGE = 255, 100, 0
GREEN = 0, 255, 0


class Button:
    '''Ajout d'un bouton avec un texte sur img
    Astuce: ajouter des espaces dans les textes pour avoir une même largeur
    de boutons
    dx, dy décalage du bouton par rapport au centre
    action si click
    Texte noir
    '''

    def __init__(self, fond, text, color, font, dx, dy):
        self.fond = fond
        self.text = text
        self.color = color
        self.font = font
        self.dec = dx, dy
        self.state = False  # enable or not
        self.title = self.font.render(self.text, True, BLACK)
        textpos = self.title.get_rect()
        textpos.centerx = self.fond.get_rect().centerx + self.dec[0]
        textpos.centery = self.dec[1]
        self.textpos = [textpos[0], textpos[1], textpos[2], textpos[3]]
        self.rect = pygame.draw.rect(self.fond, self.color, self.textpos)
        self.fond.blit(self.title, self.textpos)

    def update_button(self, fond, action=None):
        self.fond = fond
        mouse_xy = pygame.mouse.get_pos()
        over = self.rect.collidepoint(mouse_xy)
        if over:
            action()
            if self.color == RED:
                self.color = GREEN
                self.state = True
            elif self.color == GREEN:
                # sauf les + et -, pour que ce soit toujours vert
                if len(self.text) > 5:  # 5 char avec les espaces
                    self.color = RED
                self.state = False
        # à la bonne couleur
        self.rect = pygame.draw.rect(self.fond, self.color, self.textpos)
        self.fond.blit(self.title, self.textpos)

    def display_button(self, fond):
        self.fond = fond
        self.rect = pygame.draw.rect(self.fond, self.color, self.textpos)
        self.fond.blit(self.title, self.textpos)


class Game:
    def __init__(self):
        self.screen = pygame.display.set_mode((640, 480))
        self.level = 1
        self.loop = True

        # Définition de la police
        self.big = pygame.font.SysFont('freesans', 48)
        self.small = pygame.font.SysFont('freesans', 36)

        self.create_fond()
        self.create_button()

    def update_textes(self):
        self.textes = [ ["Buggy Server", ORANGE, self.big, 0, 50],
                        ["Level", BLACK, self.small, 0, 150],
                        [str(self.level), BLACK, self.small, 0, 200]]

    def create_fond(self):
        # Image de la taille de la fenêtre
        self.fond = pygame.Surface(self.screen.get_size())
        # En bleu
        self.fond.fill(CIEL)

    def create_button(self):
        self.reset_button = Button(self.fond, "   Reset   ", RED, self.small, 0, 300)
        self.start_button = Button(self.fond, "   Start   ", RED, self.small, 0, 360)
        self.quit_button  = Button(self.fond, "   Quit   ", RED, self.small, 0, 420)
        self.moins_button = Button(self.fond, "  -  ", GREEN, self.small, -100, 200)
        self.plus_button  = Button(self.fond, "  +  ", GREEN, self.small, 100, 200)

    def display_text(self, text, color, font, dx, dy):
        '''Ajout d'un texte sur fond. Décalage dx, dy par rapport au centre.
        '''
        mytext = font.render(text, True, color)  # True pour antialiasing
        textpos = mytext.get_rect()
        textpos.centerx = self.fond.get_rect().centerx + dx
        textpos.centery = dy
        self.fond.blit(mytext, textpos)

    def plus(self):
        self.level += 1
        if self.level == 6: self.level = 5

    def moins(self):
        self.level += -1
        if self.level == 0: self.level = 1

    def infinite_loop(self):
        while self.loop:
            self.create_fond()

            # Boutons
            self.reset_button.display_button(self.fond)
            self.start_button.display_button(self.fond)
            self.quit_button.display_button(self.fond)
            self.moins_button.display_button(self.fond)
            self.plus_button.display_button(self.fond)
            for event in pygame.event.get():
                if event.type == pygame.MOUSEBUTTONDOWN:
                    self.reset_button.update_button(self.fond, action=reset)
                    self.start_button.update_button(self.fond, action=start)
                    self.quit_button.update_button(self.fond, action=gamequit)
                    self.moins_button.update_button(self.fond, action=self.moins)
                    self.plus_button.update_button(self.fond, action=self.plus)

            self.update_textes()
            for text in self.textes:
                self.display_text(text[0], text[1], text[2],
                                        text[3], text[4])

            # Ajout du fond dans la fenêtre
            self.screen.blit(self.fond, (0, 0))
            # Actualisation de l'affichage
            pygame.display.update()
            # 10 fps
            clock.tick(10)


def reset():
    print("reset")

def start():
    print("start")

def gamequit():
    print("Quit")
    pygame.quit()
    sys.exit()

if __name__ == '__main__':
    game = Game()
    game.infinite_loop()

pygame est une bibliothèque de bas niveau

  • Que c'est moche !
  • Que de lignes pour des choses simples !

Une alternative pour un GUI: kivy

Ressources

Installation

Un server pour le jeu de Buggy

Mais sans la fonction server, cet essai sert juste à tester le GUI, puis à créer une application Android.