Search code examples
pythonpygamecollision-detectioncollision

Why is my colliderect() not working correctly?


Collision reacts to nothing, as if the platforms have shifted to the right. I am using it for the first time, so I would like an answer with an additional explanation...

    def collision(self, j):
        self.player_rect = pg.Rect(self.playerx, self.playery, player_w, player_h)
        for i in range(len(self.platfsx)):
            if self.player_rect.colliderect(pg.Rect(self.platfsx[i], self.platfsy[i], platf_w, platf_h)) and self.jump == False and self.y_change >= 0:
                j = True
                print("Hsllod")
        return j

Full code:

from random import *
import pygame as pg
import time
from math import *

pg.init()

'''Можна змінювати'''
WIDTH, HEIGHT = 500, 900
DIS = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption("NoName")

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)

FPS = 60

platf_h = 20    # Висота платформи
platf_w = 100   # Широта платформи
platfs_h = 120  # Відстань між платформами

player_h = 30
player_w = 25

g = .4 # Гравітація
jump_h = 16 # Висота стрибка


class Map(object):
    def __init__(self):
        self.platfsx = [randint(20, WIDTH - platf_w - 20) for i in range(19)]
        self.platfsy = [HEIGHT - 30 - i*platfs_h for i in range(19)]
        self.platfsx[0] = int(WIDTH/2 - platf_w/2)
    
    def create(self):
        if len(self.platfsx) <= 20:
            self.platfsx.append(randint(20, WIDTH - platf_w - 20))
        else:
            del self.platfsx[0]
        print(self.platfsx)
        
    def platf_draw(self):
        for i in range(len(self.platfsx)):
            pg.draw.rect(DIS, WHITE, (self.platfsx[i], self.platfsy[i], platf_w, platf_h))
            
    def background(self, color):
        DIS.fill(color)
    
    
class Player(Map):
    def __init__(self):
        super().__init__()
        self.playerx = int(WIDTH/2 - player_w/2)
        self.y_change = 0
        self.jump = False
        self.playery = HEIGHT - player_h - 30
    
    def create(self):
        pg.draw.rect(DIS, RED, [self.playerx, self.playery, player_w, player_h])
    
    def collision(self, j):
        self.player_rect = pg.Rect(self.playerx, self.playery, player_w, player_h)
        for i in range(len(self.platfsx)):
            if self.player_rect.colliderect(pg.Rect(self.platfsx[i], self.platfsy[i], platf_w, platf_h)) and self.jump == False and self.y_change >= 0:
                j = True
                print("Hsllod")
        return j
    
    def move(self):
        if self.jump:
            self.y_change = -jump_h
            self.jump = False
        self.playery += self.y_change
        self.y_change += g
        pg.time.delay(10)


def main():
    clock = pg.time.Clock()
    clock.tick(FPS)
    map = Map()
    player = Player()
    run = True
    while run:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
        keys_pressed = pg.key.get_pressed()
    
        map.background(BLACK)
        map.platf_draw()
        player.create()
        player.jump = player.collision(player.jump)
        player.move()
        pg.display.update()

    
    pg.quit()


if __name__ == "__main__":
    main()

Thank you


Solution

  • Actually you have 2 maps. A visible one (map = Map()) and a completely different invisible map in the base class of Player. Collision detection is computed against the invisible map, resulting in seemingly random behavior.Player should not be derived from Map, but you should pass the map to the collision method of Player.
    Additionally, please avoid using the name map for a variable, as this is the name of an internal function. I suggest to use the name game_map instead.

    class Player:
        def __init__(self):
            self.playerx = int(WIDTH/2 - player_w/2)
            self.y_change = 0
            self.jump = False
            self.playery = HEIGHT - player_h - 30
        
        def create(self):
            pg.draw.rect(DIS, RED, [self.playerx, self.playery, player_w, player_h])
        
        def collision(self, game_map, j):
            self.player_rect = pg.Rect(self.playerx, self.playery, player_w, player_h)
            for i in range(len(game_map.platfsx)):
                if self.player_rect.colliderect(pg.Rect(game_map.platfsx[i], game_map.platfsy[i], platf_w, platf_h)) and self.jump == False and self.y_change >= 0:
                    j = True
                    print("Hsllod")
            return j
        
        def move(self):
            if self.jump:
                self.y_change = -jump_h
                self.jump = False
            self.playery += self.y_change
            self.y_change += g
            pg.time.delay(10)
    
    def main():
        clock = pg.time.Clock()
        clock.tick(FPS)
        game_map = Map()
        player = Player()
        run = True
        while run:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    run = False
            keys_pressed = pg.key.get_pressed()
        
            game_map.background(BLACK)
            game_map.platf_draw()
            player.create()
            player.jump = player.collision(game_map, player.jump)  #<---
            player.move()
            pg.display.update()