IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Programmation multimédia/Jeux Python Discussion :

Jeu saccadé: Timer ? Thread? sous python.


Sujet :

Programmation multimédia/Jeux Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 31
    Par défaut Jeu saccadé: Timer ? Thread? sous python.
    Bonjour,
    Je débute sous python.
    J'essaie de créer un jeu Space Invader pour apprendre à utiliser Pygame.
    J'utilise une main loop pour détecter toutes les touches tapées par l'utilisateur, mais je l'utilise aussi pour faire bouger les vaisseaux spatiaux ennemis.

    Problème: à chaque fois que le joueur bouge, que les ennemis bougent ou que le tir d'un deux bouge, je doit rafraichir le fond d'écran et tous les vaisseaux. Forcément sa saccade, au bout de deux tirs les vaisseaux ennemis ne bougent plus.

    D'où ma question:
    Existe -t- il une possibilité de timer ou thread sous Python qui permettrait d'exécuter des taches en arrière plan (faire bouger les ennemis) sans ralentir mon jeux.
    Ou bien, est ce que je n'optimise pas suffisamment mon programme ?

    Merci.

    Main loop:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    while inGame:
     
            count = count +1
     
    #------ displaying player ship
            move(clavier()) # détection des controles
    #--------- end
     
    #----- displaying computers ships
            if(Computer.loose == False):
     
                if (count%170)==0:
                    Computer.moveAll(width)
                    screen.blit(background,backgroundRect)
                    for x in Computer.ships:
                        screen.blit(x.image, x.rect )
                    screen.blit(Comica.image, Comica.rect)
                    count = 1
    #-------- end
     
    #---- shooting display
                if shooted == 1:
                    for x2 in shoots:
                        screen.blit(x2.image,x2.rect)
                        if ((x2.test == True) & ((count%25)==0)):
                            screen.blit(background, backgroundRect )
                            for x in Computer.ships:
                                screen.blit(x.image, x.rect )
                            screen.blit(Comica.image, Comica.rect)
                            x2.Continue(Computer)
                        elif(x2.test == False):
                            shoots.remove(x2)
    #----------end    
            else:
            #---- lost...
                inGame = False
                screen.blit(Computer.image, Computer.rect )
     
            pygame.display.update()

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    tu optimises surement pas assez, ou plutot, le code doit pas etre bien construit ...
    je code quasiment qu'avec pygame, et avant de le faire ralentir il faut vraiment beaucoup blitter de grosses images.
    poste le code complet, ou s'il est trop long un lien pour le downloader.
    je t'aiderai volontier.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 31
    Par défaut
    Mon image la plus grosse (le fond d'écran) fait entre 3,5 Ko et 5 ko, je doit la charger a chaque fois que les vaisseaux bougent ou qu'un tire bouge.
    Voici le code entier de mon main:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
     
    def SpaceInvader():
     
        pygame.init()
        #size=width,height=600,500
        #screen = pygame.display.set_mode(size)
     
     
     
        global width, screen, background, backgroundRect
        pygame.display.set_caption("Boolean Space Invader")
     
        background = pygame.image.load("background.gif")
        backgroundRect = background.get_rect()
     
        size = (width, height) = background.get_size()
        screen = pygame.display.set_mode(size)
     
     
     
        white=255,255,255,255
        global shooted
        global shoots
        shoots =[]
        shooted = 0
     
        #--- creating player AND computers ships
        global Comica
        Comica = PlayerShip()
     
        global Computer
        Computer = Wave(5)
        Computer.MyInit()
    #---- end
     
        pygame.key.set_repeat(500,30)
     
     
        count = 0
        inGame =  True
     
        screen.blit(background,backgroundRect)
        screen.blit(Comica.image, Comica.rect)
        for x in Computer.ships:
            screen.blit(x.image, x.rect )
     
        while inGame:
     
            count = count +1
     
    #------ displaying player ship
     
            move(clavier()) 
    #--------- end
     
    #----- displaying computers ships
            if(Computer.loose == False):
     
                if (count%170)==0:
                    Computer.moveAll(width)
                    screen.blit(background,backgroundRect)
                    for x in Computer.ships:
                        screen.blit(x.image, x.rect )
                    screen.blit(Comica.image, Comica.rect)
                    count = 1
    #-------- end
     
    #---- shooting display
                if shooted == 1:
                       for x2 in shoots:
                        screen.blit(x2.image,x2.rect)
                        if ((x2.test == True) & ((count%25)==0)):
                            screen.blit(background, backgroundRect )
                            for x in Computer.ships:
                                screen.blit(x.image, x.rect )
                            screen.blit(Comica.image, Comica.rect)
                            x2.Continue(Computer)
                        elif(x2.test == False):
                            shoots.remove(x2)
     
    #----------end    
            else:
            #---- lost...
                inGame = False
                screen.blit(Computer.image, Computer.rect )
     
            pygame.display.update()
     
     
     
     
    def clavier():
            # inputs from player
            for event in pygame.event.get():
     
                while event.type==pygame.KEYDOWN:
     
                    if event.key==pygame.K_UP:                 
                        return("up")
                    if event.key==pygame.K_DOWN:
                        return("down")
                    if event.key==pygame.K_LEFT:
                        return("left")
                    if event.key==pygame.K_RIGHT:
                        return("right")
                    if event.key==pygame.K_q:
                        sys.exit()
     
                if event.type==pygame.QUIT:
                    sys.exit()
     
     
     
     
     
     
     
     
     
    def move(direction):
        # direction depending of clavier() function
        X = 20
        global shooted
     
     
     
     
     
        if direction=="left":
            newpos=[-X,0]
            essai= Comica.rect.move(newpos)
            if essai[0]>=-10:
                Comica.move(-X)
                screen.blit(background,backgroundRect)
                screen.blit(Comica.image, Comica.rect)
                for x in Computer.ships:
                    screen.blit(x.image, x.rect )
     
        if direction=="right":
            newpos=[X,0]
            essai= Comica.rect.move(newpos)
            if essai[0]<width:
               Comica.move(X)
               screen.blit(background,backgroundRect)
               screen.blit(Comica.image, Comica.rect)
               for x in Computer.ships:
                    screen.blit(x.image, x.rect )
     
        if direction=="down":
            print "ok"
        if direction == "up":
            shooted = 1
            shoots.append( Shoot(Comica.X, Comica.Y))

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    76
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2008
    Messages : 76
    Par défaut
    Salut !

    Je rejoins josmiley, il me semble que c'est plus au niveau de la structure du code que ça se joue.

    Pour commencer, ce qui me frappe c'est que tu dessines (blit) plusieurs fois l'image de fond, en entier. Evidemment, c'est un peu lourd au final. La première optimisation serait de ne dessiner l'image de fond qu'une seule fois avant de peindre les autres objets du jeu (vaisseaux, projectiles, etc.). C'est souvent suffisant lorsque l'image de fond n'est pas trop grosse.
    Sinon, le top du top c'est de redessiner uniquement la portion d'écran où se trouve l'objet qui se déplace. La fonction blit possède un paramètre pour ne redessiner qu'une partie de la surface.

    Ensuite, il y a la question du timing du jeu comme tu le relèves dans ton post. Les calculs du jeu sont placés dans une boucle sans fin mais il n'y a rien pour réguler leur exécution au cours du temps. Cela pose deux petits problèmes. Le premier c'est que ton programme va tourner à des vitesses différentes suivants les machines ^^ Normal, le système va exécuter aussi vite que possible le code et recommencer, ad eternam. C'est assez ennuyeux pour régler la difficulté des jeux.
    Mais il y a une autre chose, ce genre de code à tendance à freezer le système parce que ton jeu va accaparer toutes les ressources, il ne laisse pas le temps aux autres tâches de s'exécuter.

    La solution la plus simple, c'est d'ajouter un temps d'arrêt à la fin de ta boucle principale avec pygame.time.wait(50) ou même avec un temps plus court pygame.time.wait(10).
    Là encore, la meilleure solution à mon avis, c'est de séparer dans deux méthodes la partie affichage de la partie calcul et de les cadencer précisément. De cette façon, tu peux régler à quelle vitesse ton jeu dois tout recalculer et afficher les éléments du jeu le reste du temps.

    Perso, j'utilise la structure suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    01    import pygame
    02
    03    class Jeu:
    04        """ Gestion de la logique du jeu et de son affichage. """
    05        def __init__(self):
    06            self.dureeRound = 50    # Durée d'un round en ms.
    07            self.jeuActif = True
    08            self.tLogique = 0           # Durée des calculs de logique.
    09
    10        def maj (self):
    11            """ Mise à jour du jeu. """
    12            t0 = pygame.time.get_ticks()
    13            while(self.jeuActif):
    14                t1 = pygame.time.get_ticks()
    15                # Logique
    16                if( (t1-t0) > self.dureeRound ):
    17                    self.majLogique()
    18                    t0 += self.dureeRound
    19                # Calcul du temps pris par la logique.
    20                if ( (t1-t0) > self.dureeRound ):
    21                    t0 = t1 - self.dureeRound
    22                    self.tLogique = t1-t0
    23                # Affichage
    24                self.pourcentTemps = float (t1-t0)/float(self.dureeRound)
    25                self.majAffichage()
    26
    27        def majLogique(self):
    28            """ Mise à jour . """
    29            ...
    30
    31        def majAffichage(self):
    32            """ Mise à jour. """
    33            ...
    La méthode majLogique contient les calculs du comportement du jeu, les tests, les décisions, etc. Elle se lance à intervalle de temps régulier (la valeur de self.dureeRound en millisecondes).
    La méthode majAffichage mets à jour l'affichage des éléments du jeu dès que possible, entre les appels de la méthode majLogique.

    Bien sur ce dispositif est un peu superflu pour un jeu comme space invaders, mais ça fonctionnes très bien et permet des jeux plus complexes au niveau des calculs ou du nombre d'éléments affichés.

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    1 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 1 068
    Par défaut
    bien, au vu du nombre de global que tu utilises, je pense qu'il va falloir tout reprendre du debut ^^
    1.structurer le code
    2.reflechir sur la routine d'affichage
    3.identifier les sprites
    3.1.que font les sprites, a quoi il repondent et quelles sonr leurs interactions

    pour un jeu de ce type je propose la structure suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    LES CLASS
    une class pour ma navette
        repond au clavier
        interagit avec les bullets,moi
    une class pour les ennemis
        autogéré
        interagit avec les ennemis(collisions)
    une class pour les bullets
        autogéré
        interagit avec les ennemis(collisions)
     
    LES VARIABLES
    moi
    ennemis=[...]
    bullets=[...]
     
    LES ROUTINES
    une routine d affichage simple(peu de sprites)
    une pour initialiser le jeu
    un loop
    le loop peut se presenter ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    while jeu:
        moi.update()
        #insérer ici par exemple la creation de nouvelle navettes ennemies
        #en fonction de celles detruites et du level
        for ennemi in ennemis : ennemi.update()
        for bullet in bullets : bullet.update()
        refresh() #la routine affichage
    l'affichage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    def refresh():
        screen.blit(background,(0,0))
        for sprite in [moi]+ennemis+bullets:
            screen.blit(sprite.image,sprite.position)
    l'initialisation pour creer les navettes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import pygame
    pygame.init()
    screen = pygame.display.set_mode(size)
    screen_rect = screen.get_rect()
    background = pygame.image.load('background.png')
    #etc ...
    moi = Moi()
    ennemis  = [Ennemi() for x in range(10)]
    bullets = []
    refresh()
    un exemple de class:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Moi:
        ''
        def __init__(self):
            self.image = pygame.image.load('me.png')
            self.rect = slef.image.get_rect() #plus simple que de rentrer les valeurs a la main
            self.rect.y = screen_rect.h-self.rect-h #place la navette en bas et
            self.rect.centerx = screen_rect.centerx #au centre du display
            self.impact = 10
            # d'une facon un peu barbare mais ça permet de modifier les constantes
            # genre 'size' sans se retaper tout le code
     
        def update(self):
            e = pygame.event.poll() # lit un evenement ce qui permet la lecture du clavier
            key = pygame.key.get_pressed() #lit le clavier
            if key[pygame.K_LEFT] : # si la fleche gauche est enfoncé
                if screen_rect.contains(self.rect.move(0,-2)):self.x -=2 # on teste que la navette va pas 
    #sortir de l'ecran; si c'est bon on la déplace
            elif  key[pygame.K_RIGHT] :
                #etc ....
    voilà pour commencer.
    ceux sont des exemples, je ne sais pas ce que fait ton jeu en fait, j'imagine un truc à la 'chicken invaders'.
    hésite pas à poser des questions ...

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 31
    Par défaut
    Ok, merci pour toutes ces réponses, avec pygame.time.wait(50) ca marche très bien. Je vais restructurer un peut le code pour que ce soit au moins plus lisible pour la suite.
    Merci tout le monde.

Discussions similaires

  1. Création du jeu Voltorb Flip sous Python
    Par MrGalactique dans le forum Général Python
    Réponses: 43
    Dernier message: 22/05/2013, 21h11
  2. [Freezes] Python+Threads sous Windows
    Par gslongo dans le forum GTK+ avec Python
    Réponses: 6
    Dernier message: 24/06/2008, 21h12
  3. Appel d'un fonction C sous Python et blocage des autres threads
    Par mkrzemin dans le forum Interfaçage autre langage
    Réponses: 3
    Dernier message: 07/02/2008, 14h52
  4. [Info]Sequenceur fiable: Timers, Threads
    Par vienin dans le forum Concurrence et multi-thread
    Réponses: 8
    Dernier message: 15/07/2005, 00h08
  5. Problème de creation de thread sous linux
    Par xilebo dans le forum POSIX
    Réponses: 4
    Dernier message: 27/10/2004, 09h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo