Collisions qui laissent un espace PyGame

Fermé
MEZIANE002 - Modifié le 27 avril 2023 à 16:11
 vertigo - 23 avril 2023 à 15:23

Bonjour,

Les collisions de mon joueur laissent un espace de 5 pixels lorsqu'elles sont effectuées en bas et à droite. Voila mon code. Il y a deux fichiers)

main.py

import pygame
from essentiels import *

#Initialisation élémentaire
pygame.init()
x,y=0,0
c=1
d=[(1920, 1080), (1280, 720), (1360, 768)]
l,h=d[c]

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

#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), (30,30))
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()
        joueur.back_tileset(niveau, "X")

        niveau.refresh()
        niveau.draw_hitboxes(screen)

    pygame.display.flip()


elements.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
        
    def back_tileset(self, tileset, elm):
        
        if self.dx<0:
            if place_meeting_tileset(self.x+self.dx, self.y, tileset, elm):
                self.dx=0
            if place_meeting_tileset(self.x+self.dx, self.y+self.h, tileset, elm):
                self.dx=0
        else:
            if place_meeting_tileset(self.x+self.dx+self.w, self.y, tileset, elm):
                self.dx=0
            if place_meeting_tileset(self.x+self.dx+self.w, self.y+self.h, tileset, elm):
                self.dx=0
        
        if self.dy<0:
            if place_meeting_tileset(self.x, self.y+self.dy, tileset, elm):
                self.dy=0 
            if place_meeting_tileset(self.x+self.w, self.y+self.dy, tileset, elm):
                self.dy=0
        else:
            if place_meeting_tileset(self.x, self.y+self.dy+self.h, tileset, elm):
                self.dy=0 
            if place_meeting_tileset(self.x+self.w, self.y+self.dy+self.h, tileset, elm):
                self.dy=0
    
    def back(self,elm):
        
        if self.dx<0:
            if place_meeting(self.x+self.dx, self.y, elm):
                self.dx=0
            if place_meeting(self.x+self.dx, self.y+self.h, elm):
                self.dx=0
        else:
            if place_meeting(self.x+self.dx+self.w, self.y,  elm):
                self.dx=0
            if place_meeting(self.x+self.dx+self.w, self.y+self.h,  elm):
                self.dx=0
        
        if self.dy<0:
            if place_meeting(self.x, self.y+self.dy,  elm):
                self.dy=0 
            if place_meeting(self.x+self.w, self.y+self.dy, elm):
                self.dy=0
        else:
            if place_meeting(self.x, self.y+self.dy+self.h, elm):
                self.dy=0 
            if place_meeting(self.x+self.w, self.y+self.dy+self.h, elm):
                self.dy=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):
        self.hitboxes.clear()
        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)

1 réponse

Salut.

Difficile de s'y retrouver dans ton code.

Puis ce n'est pas au joueur de gérer ce qu'il va se passer en cas de collision, ni même gérer ses propres déplacements, mais à un niveau supérieur, là où les éléments ont été déclarés.


Généralement, et bien plus facile à gérer, est de garder en mémoire la position précédente des éléments pouvant se mouvoir, et lorsqu'une collision est détectée, le gestionnaire des collisions replace les éléments via une méthode des éléments genre move_back.

Pygame a plusieurs méthodes pour détecter des collisions de rectangles, on n'utilise généralement pas Rect.collidepoint, mais plus Rect.colliderect, Rect.collidelist, inutile de se prendre le chou à tester chaque points extérieurs de tes rectangles.

0