Jeu qui ramme affreusement (PyGame)

Résolu
MEZIANE002 - 22 avril 2023 à 21:09
 MEZIANE002 - 22 avril 2023 à 23:54

Bonjour, je code un rpg sur Pygame, au début il fonctionne bien, mais après quelques secondes il commence à Ramer, j'aimerais savoir quelle est la source du problèle, merci.

Voila le fichier main.py

import pygame
from essentiels import *

#Initialisation élémentaire
pygame.init()

c=1
d=[(1920, 1080), (1280, 720), (1360, 768)]
l,h=d[c]

screen = pygame.display.set_mode((l,h))
fps = 60
game=0
menu_=0
mouse = True

#Bouttons du Menu
play = Template((l/2,h/4+h/6), 270)
ecran = Template((l/2, (5*h)/12+h/6), 270)
quitter = Template((l/2, (5*h)/12+(2*h/6)), 270)

resolution = Template((l/2,h/4), 270)
pl_ecran = Template((l/2, (5*h)/12), 270)
menu = Template((l/2, (5*h)/12+h/6), 270)

#Initialisation du Niveau et du Joueur
joueur = Player((l/2, h/2), (50,50))
niveau = Tileset(["XXXXXXXXXXXXX",
                  "X           X",
                  'X    XXX    X',
                  "XX         XX",
                  "X           X",
                  "XXXX   XXXXXX"], {"X" : (120,120,120)}, (50,50),0,0)

#Boucle de Jeu
while True:

    mouse = not pygame.mouse.get_pressed()[0] 
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        
    pygame.time.Clock().tick(fps)

    l,h=d[c]
    
    if game == 0:  

        screen.fill((0,20,0))

        display_text("Zelda, La Quête de la liberté", 100,"arial" ,(255,220,220), screen, (15,40))

        play.draw_button("Jouer", screen)
        ecran.draw_button("Ecran", screen)
        quitter.draw_button("Quitter", screen)

        if ecran.is_clicked(bool=mouse):
            game=1
            mouse=False

        if quitter.is_clicked(bool=mouse):
            pygame.quit()
            exit()

        if play.is_clicked(bool=mouse):
            game=2

    if game == 1:

        screen.fill((0,20,0))

        display_text(str(d[c]), 50, "arial", (255,255,255), screen, (resolution.x+resolution.w+30, resolution.y))

        resolution.draw_button("Résolution", screen)
        pl_ecran.draw_button("Plein écran", screen)
        menu.draw_button("Menu", screen)

        if pl_ecran.is_clicked(bool=mouse):
            pygame.display.toggle_fullscreen()

        if resolution.is_clicked(bool=mouse):
            if c==2:
                c=0
            else:
                c+=1
            screen = pygame.display.set_mode((l,h))
        
        if menu.is_clicked(bool=mouse):
            game=0
    
    if game == 2:

        screen.fill((0,0,0))
        joueur.refresh()
        joueur.draw_hitbox(screen, (255,0,0))
        joueur.check_inputs()
        niveau.refresh()
        niveau.draw_hitboxes(screen)

        if place_meeting_tileset(joueur.x+joueur.dx, joueur.y, niveau, "X"):
            joueur.x -= joueur.dx
        
        if place_meeting_tileset(joueur.x, joueur.y+joueur.dy, niveau, "X"):
            joueur.y -= joueur.dy


    pygame.display.flip()


   

Et le fichier essentiel.py 

import pygame

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

def place_meeting(x, y, elm):
        return elm.collidepoint(x,y)

def place_meeting_tileset(x, y, tileset, elm):
        for i in tileset.hitboxes:
            if place_meeting(x,y,i[0]) and i[1]==elm:
                return True
        return False

def sign(x):
    return x/abs(x)

class Element:

    def __init__(self, position, hitbox):
        self.x = position[0]
        self.y = position[1]
        self.w = hitbox[0]
        self.h = hitbox[1]
        self.dx = 0
        self.dy = 0

    def set_position(self, x, y):
        self.x = x
        self.y = y

    def set_speed(self, dx, dy):
        self.dx = dx
        self.dy = dy

    def set_hitbox(self, w, h):
        self.w = w
        self.h = h

    def refresh(self):
        self.hitbox = pygame.Rect((self.x, self.y), (self.w, self.h))
        self.x += self.dx
        self.y += self.dy
    
    def set_image(self, img):
        self.img = pygame.image.load(img)

    def resize_image(self, x, y):
        self.img = pygame.transform.scale(self.img, (x, y))

    def draw_image(self, screen):
        screen.blit(self.img, (self.x, self.y))

    def draw_hitbox(self, screen, color):
        pygame.draw.rect(screen, color, self.hitbox)
    
    def collide(self, elm):
        return self.hitbox.colliderect(elm)
    
    def colide_tileset(self, tileset, elm):
        for i in tileset.hitboxes:
            if self.collide(i[0]) and i[1]==elm:
                return True
        return False
    
class Player(Element):
    def __init__(self, position, hitbox):
        super().__init__(position, hitbox)

    def check_inputs(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.dx = -5
            self.dy = 0
        if keys[pygame.K_RIGHT]:
            self.dx = 5
            self.dy = 0
        if keys[pygame.K_UP]:
            self.dy = -5
            self.dx = 0
        if keys[pygame.K_DOWN]:
            self.dy = 5
            self.dx = 0
        if not keys[pygame.K_DOWN] and not keys[pygame.K_UP]:
            self.dy = 0
        if not keys[pygame.K_LEFT] and not keys[pygame.K_RIGHT]:
            self.dx = 0
    
   
class Tileset:

    def __init__(self, level, colors, hitbox, x, y):
        self.level = level
        self.colors = colors
        self.w = hitbox[0]
        self.h = hitbox[1]
        self.x = x
        self.y = y
        self.hitboxes = []
    
    def refresh(self):
        cursor = [self.x,self.y]
        for i in self.level:
            for j in i:
                if not j == " ":
                    self.hitboxes.append([pygame.Rect(cursor[0], cursor[1], self.w, self.h), j] )
                cursor[0] += self.w
            cursor[0] = self.x
            cursor[1] += self.h
    
    def set_images(self, images):
        self.images = images
    
    def draw_hitboxes(self, screen):
        cursor = [self.x, self.y]

        for i in self.level:
            for j in i:

                if not j == " ":
                    pygame.draw.rect(screen, self.colors[j], (cursor[0], cursor[1], self.w, self.h))
                
                cursor[0] += self.w

            cursor[0] = self.x
            cursor[1] += self.h

class Button:

    def __init__(self, color,text_color, t, position):
        self.color = color
        self.w = t[0]
        self.h = t[1]
        self.x = position[0]-self.w/2
        self.y = position[1]-self.h/2
        self.text_color = text_color
        self.hitbox = pygame.Rect((self.x, self.y),(self.w, self.h))
        self.overlap_color = self.color
        self.text_overlap_color = self.text_color
        self.px = 0
        self.py = 0
        self.state = True

    def draw_button(self, text, w, font, screen):
        self.state = False
        if self.overlap():
            pygame.draw.rect(screen, self.overlap_color, self.hitbox)
            display_text(text,w,font,self.text_overlap_color,screen,(self.x + self.px, self.y + self.py))
        else:
            pygame.draw.rect(screen, self.color, self.hitbox)
            display_text(text,w,font,self.text_color,screen,(self.x + self.px, self.y + self.py))

    
    def padding(self, px, py):
        self.px = px
        self.py = py

    def overlap(self):
        return self.hitbox.collidepoint(pygame.mouse.get_pos())
    
    def is_clicked(self, bool=True):
        return pygame.mouse.get_pressed()[0] and self.overlap() and bool

    def overlap_change(self, a,b):
        self.overlap_color = a
        self.text_overlap_color = b

    def set_position(self, position):
        self.x = position[0]
        self.y = position[1]

class Template(Button):
    def __init__(self,position,w):
        super().__init__((37, 150, 190),(255,255,255), (w, 70), position)
        self.padding(12,3)
        self.overlap_change((255,100,100), (0,0,0))

    def draw_button(self, text, screen):
        super().draw_button(text, 50, "arial", screen)
        
A voir également:

1 réponse

Bonsoir.

Le problème se situe dans ta méthode Tileset.refresh, à chaque appel tu ajoutes des rectangles, ce qui fait qu'on se retrouve avec des milliers de Rect très rapidement.

Donc j'imagine qu'il faut vider les hitboxes avant de mettre à jour.

def refresh(self):
    self.hitboxes.clear()
    # ...

Et peut-être vérifier avant que le x et y ont bien changé avant de tout reconstruire ?

Il faut également éviter ceci :

pygame.time.Clock().tick(fps)

Et créer un objet Clock hors boucle plutôt que le recréer à chaque tour.

0

Je te remercie, j'ai aussi un problème au niveau de mes collisions (voir cette discussion). En gros, les collisions de mon joueur créent un espace de 5px quand elles sont faites en bas et à droite.

0