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)
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.
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.
Modifié le 27 avril 2023 à 16:09
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.