Why is my colliderect() not working correctly?

Question:

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

Asked By: IDNKEK

||

Answers:

It looks like the collision detection function is implemented in the Player class as the collision method. The method checks if the player’s rectangular bounding box (defined by the player_rect variable) collides with any of the platform bounding boxes, using the colliderect() method of the Rect class in Pygame.

If a collision is detected and the player is not currently jumping (self.jump == False) and the player’s vertical speed is non-negative (self.y_change >= 0), then the j variable is set to True, indicating that the player is on a platform and can jump again.

In the move method of the Player class, the player’s vertical position (self.playery) is updated based on the current vertical speed (self.y_change) and gravity (g). This method is called repeatedly in the game loop to update the player’s position over time.

One question, what is the expected behavior and how the code is currently behaving. But I am convinced that there is a problem with the implementation of the collision detection or the way that the player’s position is being updated. You may want to try printing out some variables or using a debugger to help isolate the issue.

Answered By: EurekaTriumphant

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()
Answered By: Rabbid76