Partage
  • Partager sur Facebook
  • Partager sur Twitter

Pygame lent ?

23 juillet 2021 à 18:28:37

Bonjour,

j'ai effectué ce code :

import pygame
import os
import random

def center(surface, ecran):
    centerScreenX = ecran.get_width()/2
    centerScreenY = ecran.get_height()/2
    centerSurfaceX = surface.get_width()/2
    centerSurfaceY = surface.get_height()/2

    ecran.blit(surface, (centerScreenX - centerSurfaceX, centerScreenY - centerSurfaceY))
    pygame.display.flip()

def printMainMenu(ecran, surfaces_menu, rects_menu):
    for surface in range(len(surfaces_menu)):
        if rects_menu[surface] == "center":
            center(surfaces_menu[surface], ecran)
        else:
            ecran.blit(surfaces_menu[surface], rects_menu[surface])
            pygame.display.flip()


pygame.font.init()

class Texte:
    def __init__(self, pathToFont, size, texte, color):
        self.font = pygame.font.Font(pathToFont, size)
        self.text = self.font.render(texte, True, color)
        self.__h = self.text.get_height()
        self.__w = self.text.get_width()
        self.__x = self.text.get_rect()[0]
        self.__y = self.text.get_rect()[1]

    def display(self, ecran, rect):
        ecran.blit(self.text, rect)
        pygame.display.flip()

    def get_height(self):
        return self.__h
    def get_width(self):
        return self.__w
    def get_abscisse(self):
        return self.__x
    def get_ordonnee(self):
        return self.__y


class Cartes:
    def __init__(self):
        self.listcategorie = []               #liste des cartes appartenant à une catégorie
        self.selection = []             #liste des cartes sélectionnées aléatoirement parmi la première la liste
    
    def extract_cards(self, filepath):
        fichier = open(filepath)
        line = 'c'
        while line != '':     #= tant qu'on a pas ateint la fin du fichier
            line = fichier.readline()
            line = line.replace('\n','')
            self.listcategorie.append(line)   

    def select_cards(self, nbcartes):                   #nbcartes = le nombre de cartes qui seront sélectionnées pour la catégorie concernée (calculé au préalable)        
        for i in range(nbcartes):
            index = random.randint(len(self.listcategorie))
            self.selection.append(self.listcategorie[index])
            self.listcategorie.pop(index)



#definition of colors
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
yellow = (255,255,0)
light_blue = (40,130,255)


ecran = pygame.display.set_mode((0,0))
ecran.fill(light_blue)
width_ecran = ecran.get_width()
height_ecran = ecran.get_height()

#initialisation images boutons et affichage
bouton_play = pygame.image.load("button_play.png")
bouton_play_selected = pygame.image.load("selected_play.png")
bouton_quit = pygame.image.load("button_quit.png")
bouton_quit_selected = pygame.image.load("selected_quit.png")
center(bouton_play,ecran)

title_game = Texte("Royalacid.ttf", 75, "Time's Up", yellow)
title_game.display(ecran, (width_ecran/2 - title_game.get_width()/2 , height_ecran/12 - title_game.get_height()/2))
play_text = Texte("Classic_title.ttf", 65, "PLAY", yellow)
play_text.display(ecran, (width_ecran/2 - play_text.get_width()/2 , height_ecran/3.5 - play_text.get_height()/2))

surfaces_menu = [bouton_play,bouton_quit,title_game.text,play_text.text]
rects_menu = ["center",(width_ecran/2 - bouton_quit.get_width()/2, height_ecran/1.20 - bouton_quit.get_height()), (width_ecran/2 - title_game.get_width()/2 , height_ecran/12 - title_game.get_height()/2), (width_ecran/2 - play_text.get_width()/2 , height_ecran/3.5 - play_text.get_height()/2)]
#initial display
printMainMenu(ecran, surfaces_menu, rects_menu)

continuer = True    #booléen qui maintien le programme
start = False       #booléen qui lance le jeu
play = False        #booléen qui détecte si la souris est sur le bouton play
quit = False        #booléen qui détecte si la souris est sur le bouton quit
while continuer:
    surfaces_menu = [title_game.text,play_text.text]
    rects_menu = [(width_ecran/2 - title_game.get_width()/2 , height_ecran/12 - title_game.get_height()/2), (width_ecran/2 - play_text.get_width()/2 , height_ecran/3.5 - play_text.get_height()/2)]
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            continuer = False

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_q:
                continuer = False 

        if event.type == pygame.MOUSEMOTION:   
            play_rect = bouton_play.get_rect()
            play_rect[0] = width_ecran/2 - bouton_play.get_width()/2
            play_rect[1] = height_ecran/2 - bouton_play.get_height()/2         
            if play_rect.collidepoint(event.pos[0], event.pos[1]):
                play = True
                surfaces_menu.append(bouton_play_selected)
                centered_button = (width_ecran/2 - bouton_play_selected.get_width()/2 , height_ecran/2 - bouton_play_selected.get_height()/2)
                rects_menu.append(centered_button)
            #elif 
            else:
                play=False
                surfaces_menu.append(bouton_play)
                rects_menu.append("center")
                surfaces_menu.append(bouton_quit)
                rects_menu.append((width_ecran/2 - bouton_quit.get_width()/2, height_ecran/1.20 - bouton_quit.get_height()))

    printMainMenu(ecran, surfaces_menu, rects_menu)

(bonne lecture...)

il n'est pas encore fini, mais j'ai un blocage : au moment ou la souris passe sur le bouton play, ce qui est censé le "sélectionner", et le faire passer en gris (l.134-142), ça marche, mais il met longtemps à afficher la version grise du bouton play.

j'ai pensé à l'optimisation donc j'ai utilisé la technique du "profiling" comme elle été appelée sur le site où je me suis renseigné, tout ça pour savoir qu'aucune fonction ne ralentissait vraiment le process...

donc, je suis dépassé, et j'ai besoin d'aide.

quelqu'un aurait-il une solution ???

  • Partager sur Facebook
  • Partager sur Twitter
23 juillet 2021 à 18:50:57

Je me demande si tu n'accumules pas trop de surfaces (lignes 122, 128), puisque sauf erreur de ma part, à chaque mouvement de souris, tu va ajouter soit bouton_play soit bouton_play_selected.
peut-être traiter la variable play en dehors de la boucle des évènements

Et tu oublie de fermer le fichier dans extract_cards (il y a un open mais pas de close)

-
Edité par umfred 23 juillet 2021 à 18:51:50

  • Partager sur Facebook
  • Partager sur Twitter
23 juillet 2021 à 21:51:30

Mais pourquoi les gens s'obstinent à tout mettre dans une seule boucle événementielle ? Je renonce à aider sur pygame, je laisse umfred s'en charger il est bien plus patient ...

Bon un dernier pour la route. Si t'as qu'un seul bouton à gérer et qu'il n'y a rien d'autre à faire qu'attendre le clic dessus, tu crées une fonction dédiée, même bloquante osef, qui retourne une action. Genre 0 le bouton est cliqué, 1 l'utilisateur a appuyez sur 'q', 2 l'utilisateur a fermé la fenêtre, etc ... La fonction aura sa propre boucle événementielle. C'est plus claire et plus facile à intégrer.

  • Partager sur Facebook
  • Partager sur Twitter

Python c'est bon, mangez-en. 

23 juillet 2021 à 23:58:31

josmiley a écrit:

Mais pourquoi les gens s'obstinent à tout mettre dans une seule boucle événementielle ? Je renonce à aider sur pygame, je laisse umfred s'en charger il est bien plus patient ...

Bon un dernier pour la route. Si t'as qu'un seul bouton à gérer et qu'il n'y a rien d'autre à faire qu'attendre le clic dessus, tu crées une fonction dédiée, même bloquante osef, qui retourne une action. Genre 0 le bouton est cliqué, 1 l'utilisateur a appuyez sur 'q', 2 l'utilisateur a fermé la fenêtre, etc ... La fonction aura sa propre boucle événementielle. C'est plus claire et plus facile à intégrer.

j'y ai pensé mais le bouton play sera pas le seul à gérer, y'aura aussi le bouton quit....

umfred a écrit:

Je me demande si tu n'accumules pas trop de surfaces (lignes 122, 128), puisque sauf erreur de ma part, à chaque mouvement de souris, tu va ajouter soit bouton_play soit bouton_play_selected.
peut-être traiter la variable play en dehors de la boucle des évènements

Et tu oublie de fermer le fichier dans extract_cards (il y a un open mais pas de close)

-
Edité par umfred il y a environ 4 heures

j'ai supprimé les lignes 125 et 126, j'ai remplacé les ligne 139-141 par
surfaces_menu[0] = bouton_play_selected  

et les lignes 143-146 par

surfaces_menu[0] = bouton_play

ça passe ?

PS : après test, la fluidité du passage non selectionné --> selectionné  a l'air assez aléatoire...

-
Edité par alexpatt 24 juillet 2021 à 0:00:13

  • Partager sur Facebook
  • Partager sur Twitter
24 juillet 2021 à 2:16:01

Un tuto provenant du site de Pygame : https://www.patternsgameprog.com/series/discover-python-and-patterns/ (EN)

Je comprends Jos qui fait allusion à Hugo dans son coup de gueule.

Je suis en train de suivre le lien que je propose. Il est tard, je suis un peu fatigué, mais je vais essayer d'avancer. J'aime beaucoup ces tutos qui parlent des design patterns.

-
Edité par CristianoRolando 24 juillet 2021 à 2:25:26

  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
24 juillet 2021 à 13:38:57

josmiley a écrit:

Mais pourquoi les gens s'obstinent à tout mettre dans une seule boucle événementielle ? Je renonce à aider sur pygame, je laisse umfred s'en charger il est bien plus patient ...


Mais du coup il faut faire du multithreading ? Nan ? Je vois pas trop l'intérêt à première vue. Je dois mal comprendre.
  • Partager sur Facebook
  • Partager sur Twitter
24 juillet 2021 à 20:40:29

CristianoRolando a écrit:

Un tuto provenant du site de Pygame : https://www.patternsgameprog.com/series/discover-python-and-patterns/ (EN)

Je comprends Jos qui fait allusion à Hugo dans son coup de gueule.

Je suis en train de suivre le lien que je propose. Il est tard, je suis un peu fatigué, mais je vais essayer d'avancer. J'aime beaucoup ces tutos qui parlent des design patterns.

-
Edité par CristianoRolando il y a environ 18 heures

hehe je sais pas trop où chercher sur ce tuto ÉNORME y a pas une section où je pourrait directement aller et voir la partie susceptible de résoudre mon problème ?

animation peut-etre...?

  • Partager sur Facebook
  • Partager sur Twitter
24 juillet 2021 à 20:54:17

Dans le tuto, je ne sais plus à quelle page. Il dit clairement que pygame n'est pas optimisé du tout. Il faut parfois revoir à la baisse ses objectifs.

Pour info, la méthode update peut contenir une liste de rectangles. Ça ne met à jour que les rectangles que tu souhaites.

Si j'y pense, je te ponds un exemple simple. Je dois travailler l'algo, j'ai juste l'idée en tête. Mais, plus tard, j'ai faim !

Voilà, c'est peut-être pas parfait, il n'y a pas d'image non plus. Mais, comme les CPU sont ultra rapides avec les booléens, j'en ai utilisés :

import pygame as pg

"""
Modifier couleur d'un rectangle lorsqu'on passe la souris dessus
"""


pg.init()
clock = pg.time.Clock()
fps = 60
width = 640
height = 480
red = pg.Color(255,0,0)
fill_color = pg.Color(128,128,128)
blue = pg.Color(0,0,255)
white = pg.Color(255,255,255)
black = pg.Color(0,0,0)
out = True
window = pg.display.set_mode((width,height))

running = True

blue_rectangle = pg.draw.rect(window, (blue), (50, 400, 150, 50))
white_rectangle = pg.draw.rect(window, (white), (250, 400, 150, 50))
red_rectangle = pg.draw.rect(window, (red), (450, 400, 150, 50))
blue_to_black = white_to_black = red_to_black = False

rectangles = [blue_rectangle, white_rectangle, red_rectangle]
window.fill(fill_color)

pg.display.update()

while running:
  for event in pg.event.get():
    if event.type == pg.QUIT:
      running = False
    elif event.type == pg.MOUSEMOTION:
      x, y = event.pos
      if blue_rectangle.collidepoint(x,y):
        blue_to_black = True
      elif white_rectangle.collidepoint(x,y):
        white_to_black = True
      elif red_rectangle.collidepoint(x,y):
       red_to_black = True
      else:
        blue_to_black = False
        white_to_black = False
        red_to_black = False

  window.fill(fill_color)
  if blue_to_black:
    window.fill(black, blue_rectangle)
    pg.display.update(blue_rectangle)
  elif white_to_black:
    window.fill(black, white_rectangle)
    pg.display.update(white_rectangle)
  elif red_to_black:
    window.fill(black, red_rectangle)
    pg.display.update(red_rectangle)
  else:
    window.fill(blue, blue_rectangle)
    window.fill(white, white_rectangle)
    window.fill(red, red_rectangle)
    pg.display.update(rectangles)

  clock.tick(fps)

pg.quit()



-
Edité par CristianoRolando 24 juillet 2021 à 22:09:49

  • Partager sur Facebook
  • Partager sur Twitter
25 juillet 2021 à 12:01:18

j'ai lu ton code, et j'ai remarqué qu'à la ligne 66 ça parlait de fps...

je ne sais pas comment ça marche mais j'ai du coup rajouté les lignes 9 et 66à mon programme et ça marche....

j'en profite donc pour poser une autre question : le bouton play sur lequel la souris passe pour le "sélectionner" est plutot ovale. sauf qu'une surface est forcément carrée, donc quand la souris passe dans un coin de la surface, qui n'est pas vraiment le bouton, ça le sélectionne quand meme. quelqu'un connait un moyen de résoudre ça ??

-
Edité par alexpatt 25 juillet 2021 à 12:11:33

  • Partager sur Facebook
  • Partager sur Twitter
25 juillet 2021 à 19:17:51

Dans un vieux tuto pygame qui était référencé sur le site officiel. L'auteur dit qu'il vaut mieux éviter les collisions parfaites. Donc pour ton bouton ovale, j'ai entendu parler des dirty rects mais je ne sais pas à quoi ils servent. C'est compliqué à expliqué textuellement, mais, renseigne-toi dessus.

Sinon, tu gères la collision dans le rectangle inscrit dans l'ovale.

  • Partager sur Facebook
  • Partager sur Twitter
26 juillet 2021 à 15:20:49

@alexpatt, quand tu parles de lignes 139-141, j'ai du mal à voir de quelles lignes il s'agit. Dans le code que l'on voit on ne va que jusqu'à 133 :p
  • Partager sur Facebook
  • Partager sur Twitter