1

I'm creating an endless runner/ platformer game using pygame and am working on collision detection between the player rect and the rect of any object in the foreground list, as they will be randomly generated. I've tried using help from other questions, friends and even chatGPT but it still wont work, upon jumping the player will fall through the object they are meant to land on in the fgs list and leave the screen as they fall. I've tried everything i can think of but nothing works.

One thing i am positive of is the loop i have to generate the position of the building correctly captures the width, height, X and Y values into the fgWidth[], fgHeight[], fgRectX[] and fgRectY[] lists (respectively), as the print function outputs the correct numbers i calculated. these lists are further used to determine the position of the rects, but it doesn't seem to be working, or maybe something else isn't working, but i thought to add that just in case people were wondering if those list values were correct.

I am new to coding games using pygame and python, so i may have missed something very obvious, if i have please just let me know. Thanks in advance!!!

The code is below:

import pygame
from pygame.locals import *
import random
import math
import time 

pygame.init()

# create the game window
game_width = 1920
game_height = 1080
size = (game_width, game_height)
game = pygame.display.set_mode(size)
pygame.display.set_caption('Neon Rush')

# game variables
score = 0
speed = 3

class Player(pygame.sprite.Sprite):

    gravity = 1

    def __init__(self, x, y, width, height):

        pygame.sprite.Sprite.__init__(self)

        self.height = 96
        self.action = 'running'
        self.health = 1
        self.y_vel = 0
        self.x_vel = 25
        self.rect = pygame.Rect(x, y, width, height)
        self.mask = None
        self.direction = "right"
        self.animation_count = 0
        self.fall_count = 0
        self.jump_count = 0
        self.hit = False
        self.hit_count = 0
        self.y = 792

        self.jumpActive = False

        # load the running sprites
        self.running_sprites = []
        self.running_sprite_index = 0
        for i in range(3):
            running_sprite = pygame.image.load(f'images/player/running/run{i}.png').convert_alpha()
            scale = self.height / running_sprite.get_height()
            new_width = running_sprite.get_width() * scale
            new_height = running_sprite.get_height() * scale
            running_sprite = pygame.transform.scale(running_sprite, (new_width, new_height))
            self.running_sprites.append(running_sprite)

        # load the jumping sprites
        self.jumping_sprites = []
        self.jumping_sprite_index = 0
        for i in range(5):
            jumping_sprite = pygame.image.load(f'images/player/jumping/jump{i}.png').convert_alpha()
            scale = self.height / jumping_sprite.get_height()
            new_width = jumping_sprite.get_width() * scale
            new_height = jumping_sprite.get_height() * scale
            jumping_sprite = pygame.transform.scale(jumping_sprite, (new_width, new_height))
            self.jumping_sprites.append(jumping_sprite)

        # load the slide sprites
        self.sliding_sprites = []
        self.sliding_sprite_index = 0
        for i in range(3):
            sliding_sprite = pygame.image.load(f'images/player/sliding/slide{i}.png').convert_alpha()
            scale = self.height / sliding_sprite.get_height()
            new_width = sliding_sprite.get_width() * scale
            new_height = sliding_sprite.get_height() * scale
            sliding_sprite = pygame.transform.scale(sliding_sprite, (new_width, new_height))
            self.sliding_sprites.append(sliding_sprite)

        # set the initial sprite rect
        self.rect = self.running_sprites[self.running_sprite_index].get_rect()

        # number of frames player is invincible after getting hurt
        self.invincibility_frame = 0


    def draw(self):
        ''' draw the sprite based on the character action and index '''

        if self.action == 'running':
            running_sprite = self.running_sprites[int(self.running_sprite_index)]

            # add invincibility effect when hurt
            if self.invincibility_frame > 0:
                self.invincibility_frame -= 1
            if self.invincibility_frame % 10 == 0:
                game.blit(running_sprite, (25, self.y))

        elif self.action == 'jumping' or self.action == 'landing':
            jumping_sprite = self.jumping_sprites[int(self.jumping_sprite_index)]

            # add invincibility effect when hurt
            if self.invincibility_frame > 0:
                self.invincibility_frame -= 1
            if self.invincibility_frame % 10 == 0:
                game.blit(jumping_sprite, (25, self.y))

        elif self.action == 'sliding':
            sliding_sprite = self.sliding_sprites[int(self.sliding_sprite_index)]

            # add invincibility effect when hurt
            if self.invincibility_frame > 0:
                self.invincibility_frame -= 1
            if self.invincibility_frame % 10 == 0:
                game.blit(sliding_sprite, (25, self.y))


    def update(self):
        ''' update the sprite index so the next sprite image is drawn '''
        ''' also update the y position when jumping or landing '''

        if self.action == 'running':

            # increment the sprite index by 0.2
            # so it takes 5 frames to get to the next index
            self.running_sprite_index += 0.25

            # go back to index 0 after the last sprite image is drawn
            if self.running_sprite_index >= 3:
                self.running_sprite_index = 0

            # update the rect
            self.rect = self.running_sprites[int(self.running_sprite_index)].get_rect()

        elif self.action == 'jumping' or self.action == 'landing':

            # increment the sprite index by 0.1
            # so it takes 10 frames to get to the next index
            self.jumping_sprite_index += 0.14

            # go back to index 0 after the last sprite image is drawn
            if self.jumping_sprite_index >= 4:
                self.jumping_sprite_index = 0

            self.y += self.y_vel

            # change to running when character touches the ground
            if self.y == 792:
                self.action = 'running'

                # allows the player to jump again
                self.jumpActive = False



            # update the rect
            self.rect = self.jumping_sprites[int(self.jumping_sprite_index)].get_rect()


        elif self.action == 'sliding':
            # increment the sprite index by 0.2
            # so it takes 5 frames to get to the next index
            self.sliding_sprite_index +=  0.2

            # go back to index 0 after the last sprite image is drawn
            if self.sliding_sprite_index >= 3:
                self.sliding_sprite_index = 0

            # update the rect
            self.rect = self.sliding_sprites[int(self.sliding_sprite_index)].get_rect()

    # handles the movement of the character
    def move(self, dy):
        self.rect.y += dy
        self.rect.x = 25

    # updates movement values and variables every frame
    def loop(self, fps):
        self.y_vel += min(1, (self.fall_count / fps) * self.gravity)
        self.move(self.y_vel)

        self.fall_count += 1
        self.update()

    # jump
    def jump(self):
        self.y_vel = -self.gravity * 8
        self.animation_count = 0
        self.jump_count += 1
        if self.jump_count == 1:
            self.fall_count = 0
        if self.action not in ['jumping', 'landing']:
            self.action = 'jumping'

    #slide
    def slide(self):
        ''' make the player go to jumping action when not already jumping, landing or sliding '''
        if self.action not in ['jumping', 'landing', 'sliding']:
            self.action = 'sliding'

# set the image for the sky
sky = pygame.image.load('images/bg/sky3.png').convert_alpha()
num_bg_tiles = math.ceil(game_width / sky.get_width()) + 1

# set the images for the parallax background
bgs = []
bgs.append(pygame.image.load('images/bg/bg1.png').convert_alpha())
bgs.append(pygame.image.load('images/bg/bg2.png').convert_alpha())
bgs.append(pygame.image.load('images/bg/bg3.png').convert_alpha())
bgs.append(pygame.image.load('images/bg/bg4.png').convert_alpha())

# for the parallax effect, determine how much each layer will scroll
parallax = []
for x in range(len(bgs)):
    parallax.append(0)

# set images for the buildings in the foreground
fgs = []
fgs.append(pygame.image.load('images/buildings/temp/building1.png').convert_alpha())
fgs.append(pygame.image.load('images/buildings/temp/building2.png').convert_alpha())
fgs.append(pygame.image.load('images/buildings/temp/building3.png').convert_alpha())
fgs.append(pygame.image.load('images/buildings/temp/building4.png').convert_alpha())

# create the player
player = Player(25, 10, 96, 96)

# game loop
clock = pygame.time.Clock()
fps = 60
slideActive = False
quit = False

while not quit:
    clock.tick(fps)
    for event in pygame.event.get():
        if event.type == QUIT:
            quit = True
        # press SPACE to jump
        if event.type == KEYDOWN and event.key == K_SPACE and player.jump_count < 2:
            player.jumping_sprite_index = 0
            player.jump()
            # set to true to prevent the player resetting the jump animation mid jump
            player.jumpActive = True
        # press 'C' to slide
        if event.type == KEYDOWN and event.key == K_c and slideActive == False:
            slideActive = True
            player.slide()
            # prevents jump glitches if slide and jump are pressed very close together
            player.jumpActive = False
        elif event.type == KEYDOWN and event.key == K_c and slideActive == True:
            slideActive = False
            player.action = 'running'
            # prevents jump glitches if slide and jump are pressed very close together

    # Move the player
    player.loop(fps)


    # Draw the sky
    for i in range(num_bg_tiles):
        game.blit(sky, (i * sky.get_width(), 0))

    # Draw each background layer
    for i in range(len(bgs)):
        bg = bgs[i]
        for j in range(num_bg_tiles):
            game.blit(bg, (j * bg.get_width() + parallax[i], 0))

    # Update how much each layer will scroll
    for i in range(len(parallax)):
        # Top layer should scroll faster
        parallax[i] -= i + 1
        if abs(parallax[i]) > bgs[i].get_width():
            parallax[i] = 0
       
    # RECT AND FOREGROUND POSITION CODE STARTS HERE !!!

    buildingX = 0
    fgRectX = []
    fgRectY = []
    fgHeight = []
    fgWidth = []

    for i in range(len(fgs)):
        fg = fgs[i]

        if i != 0:
            game.blit(fg, ((192 * i) + buildingX, 1080 - fg.get_height()))
            fgRectX.append((192 * i) + buildingX)
            fgRectY.append(1080 - fg.get_height())
            fgHeight.append(fg.get_height())
            fgWidth.append(fg.get_width())
            buildingX += fg.get_width()

            
            
        elif i == 0:
            game.blit(fg, ((192 * i), 1080 - fg.get_height()))
            fgRectX.append(192 * i)
            fgRectY.append(1080 - fg.get_height())
            fgHeight.append(fg.get_height())
            fgWidth.append(fg.get_width())
            buildingX += fg.get_width()

        
        print(fgWidth[i], fgHeight[i], fgRectY[i], fgRectX[i]) 


    # Check for collisions with objects in 'fgs' list
    for i in range (len(fgs)):
        if player.rect.colliderect(pygame.Rect(fgRectX[i], fgRectY[i], fgWidth[i], fgHeight[i])):
            # Check if player is on top of the object
            if player.y_vel > 0:
                # Set the player's position on top of the object
                player.rect.bottom = pygame.Rect(fgRectX[i], fgRectY[i], fgWidth[i], fgHeight[i]).top
                player.y_vel = 0
                player.jump_count = 0
                player.action = 'running'

                print('collided!!')

    # Draw the player
    player.draw()

    pygame.display.update()

pygame.quit()
2
  • @Rabbid76 that was it!! thank you so much. if you want to add your comment as an answer so i can approve it that'd be great!! Commented Jul 19, 2023 at 14:44
  • @Rabbid76 my pc was trippin myb Commented Jul 19, 2023 at 14:52

1 Answer 1

2

The position of the player.rect is never set. You must update player.rect.x and player.rect.y with the player's position, which in your case is (25, self.y), because the player is blit at this position:

player.rect.x = 25
player.rect.y = player.y
if player.rect.colliderect(pygame.Rect(fgRectX[i], fgRectY[i], fgWidth[i], fgHeight[i])):
    # [...]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.