Lag dans mon projet PyGame

Résolu/Fermé
MEZIANE002 - 24 avril 2023 à 01:32
 MEZIANE002 - 24 avril 2023 à 16:08

Bonjour, je suis en train de créer un petit logiciel qui a pour vocation de m'aider à la conception de mon RPG, le problème est qu'il lagge affreusement après un certain nombre de cellules à l'écran. Si l'on crée un tableau de 10 par 10, ça va encore mais mon jeu utilise des maps d'au moin 32 par 18 et là c'est inutilisable. Merci de votre aide. Voilà mon code :

import pygame

def display_text(text,w,font,color,screen,position):
    screen.blit(pygame.font.SysFont(font,w).render(text,True, color), position)

def bordure(rect, e, screen):
    b1 = pygame.Rect((rect.x, rect.y), (e, rect.h))
    b2 = pygame.Rect((rect.x+rect.w-e, rect.y), (e, rect.h))
    b3 = pygame.Rect((rect.x, rect.y), (rect.w, e))
    b4 = pygame.Rect((rect.x, rect.y+rect.h-e), (rect.w, e))
    pygame.draw.rect(screen, (0,0,0), b1)
    pygame.draw.rect(screen, (0,0,0), b2)
    pygame.draw.rect(screen, (0,0,0), b3)
    pygame.draw.rect(screen, (0,0,0), b4)

class Cellule:

    def __init__(self, x, y, elm, t):
        self.x = x
        self.y = y
        self.elm = elm
        self.rect = pygame.Rect((x,y), (t,t))
    
    def draw(self, screen, e, k):
        bordure(self.rect, e, screen)
        display_text(self.elm, k, "arial", (0,0,0), screen, (self.rect.x+self.rect.w/3, self.rect.y+self.rect.w/4))
    
    def overlap(self):
        return self.rect.collidepoint(pygame.mouse.get_pos())
    
    def is_clicked(self, bool=True):
        return pygame.mouse.get_pressed()[0] and self.overlap() and bool


print("Bienvenue dans le Map Maker !")

cmd=input("Dimensions de la Map : ")
w,h = int(cmd.split()[0]), int(cmd.split()[1])

cmd=input("Taille des cellules : ")
t = int(cmd)

cmd=input("Eléments : ")
l=[" "]
l+=cmd.split()

pygame.init()
screen = pygame.display.set_mode((1000,600))
pygame.display.set_caption("Map Maker Pygame")

n=0

m=[]

for i in range(h):
    m.append([Cellule(t*j+20, t*i+80, 'X', t) for j in range(w)])


while True:
    mouse = not pygame.mouse.get_pressed()[0] 

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    
    screen.fill((255,255,255))

    selecteur = Cellule(430, 10, l[n], 60)
    selecteur.draw(screen, 3, 30)

    if selecteur.is_clicked(bool=mouse):
        if n != len(l)-1:
            n+=1
        else:
            n=0
    
    for i in m:
        for j in i:
            j.draw(screen, 2, t//2)
    
    pygame.display.flip()
A voir également:

2 réponses

Salut,

Qu'est censé faire ton code ?
Il faudrait quand même utiliser des noms de variables correctes, parce que des w, h, t, l, n… Rendent un code difficile à lire…
Pour ma part, il n'y a pas de ralentissement probant.

Testé avec

# cmd=input("Dimensions de la Map : ")
# w,h = int(cmd.split()[0]), int(cmd.split()[1])

# cmd=input("Taille des cellules : ")
# t = int(cmd)

# cmd=input("Eléments : ")
# l=[" "]
# l+=cmd.split()

w = 32
h = 18
t = 25
l = tuple(chr(i) for i in range(97, 123))


Que se passe-t-il lorsque tu l'exécutes ?

Maintenant plutôt que de créer à chaque tour un objet Cellule, déclare-le avant la boucle, et passe la valeur textuelle lors du draw.

Ajoute aussi un objet Clock afin de réguler la vitesse d'exécution.

clock = pygame.time.Clock()
while True:
    clock.tick(30)
    # …
0

Bonjour, je ne suis pas sur d'avoir compris, concernant la clock, je l'ai fait et cela lag encore.

0

Ok, en regardant un peu les temps d'exécution, on voit que ce qui fait ralentir est ta fonction display_text, en initialisant la police avant, le lag n'est plus, donc je ne sais comment fonctionne SDL, mais j'imagine qu'il doit y avoir un accès disque chaque fois qu'un objet SysFont est instanciée et que rien n'est gardé en mémoire.

En changeant ainsi :

pygame.init()
font_game = pygame.font.SysFont('Arial', 12)
def display_text(text,w,font,color,screen,position):
    screen.blit(font_game.render(text,True, color), position)

Plus de souci.

Donc, revois la façon dont sont créées tes cellules, nul besoin de générer chaque fois une police, ni même les bordures, cela devrait être fait à l'instance, mettre le texte et bordure sur une surface et c'est tout.

Un exemple avec sprites.

import pygame


class Cell(pygame.sprite.Sprite):
    def __init__(self, x, y, size, text):
        super().__init__()
        self._text = text
        self.image = pygame.Surface((size, size)).convert()
        self.image.fill((255, 255, 0))
        self._image = self.image.copy()
        self.rect = self.image.get_rect()
        self.rect.topleft = x, y
        self.font = pygame.font.SysFont('mono', 10, True)
        self._text_draw()

    def _text_draw(self):
        text_surf = self.font.render(self._text, True, (0, 0, 0)).convert_alpha()
        center = self.rect.w / 2, self.rect.h / 2
        self.image.blit(text_surf, text_surf.get_rect(center=center))

    [A]property
    def text(self):
        return self._text
    
    text.setter
    def text(self, value):
        self._text = value
        self.image = self._image.copy()
        self._text_draw()


pygame.init()
screen = pygame.display.set_mode((800, 600))
screen.convert()
display_group = pygame.sprite.Group()
cells = [Cell(x, y, 24, 'X') for x in range(0, 600, 25) for y in range(0, 400, 25)]
display_group.add(cells)

clock = pygame.time.Clock()
running = True
while running:
    for evt in pygame.event.get():
        if evt.type == pygame.QUIT:
            running = False
    screen.fill((0, 0, 0))
    display_group.update()
    display_group.draw(screen)
    pygame.display.update()
    clock.tick(30)
    # Affichage FPS
    # print(clock.get_fps())

pygame.quit()

Tu peux mettre n'importe quoi sur l'image, les bordures, etc.

NB: le [A] est à remplacer par le @, car ccm l'interprète comme une adresse mail…

0

Merci

0