0

I am creating a game where the player moves around a grid and dodges rocks, but my code for detecting collision doesn't seem to work.

import pygame
from pygame.locals import *
import random

pygame.init()

xSize = 500
ySize = 500
win = pygame.display.set_mode((xSize, ySize), RESIZABLE)

pygame.display.set_caption('Grid Game: Featuring Sad Blue Circle')

grid = pygame.image.load('gr.png').convert()
clock = pygame.time.Clock()

rockWait = 1000
rock_spawn_ev = pygame.USEREVENT

class player(object):

    def __init__(self):
        self.right = [pygame.image.load('right_%s.png' % frame) for frame in range(1, 9)]
        self.x = 109
        self.y = 109
        self.frameCount = 0
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #rect for collision

    def draw(self, win):
        if self.frameCount + 1 >= 40:
            self.frameCount = 0
        win.blit(self.right[self.frameCount//5], (self.x, self.y))
        self.frameCount +=1
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #update rect position


class rock(object):

    def __init__(self, vel):
        self.rock = pygame.image.load('rock.png')
        self.vel = vel
        self.ran = random.randint(0, 3)
        self.ran2 = random.randint(1, 10) * 50 - 41
        if self.ran > 1:
            self.x = 550
            self.y = 550
        else:
            self.x = -50
            self.y = -50
        rocks.append(self)
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #rect for collision

    def draw(self, win): 
        if self.ran == 0: #top to bottom
            self.y += self.vel
        win.blit(self.rock, (self.ran2, self.y))

        if self.ran == 2: #bottom to top
            self.y -= self.vel
        win.blit(self.rock, (self.ran2, self.y))

        if self.ran == 1: #left to right
            self.x += self.vel
        win.blit(self.rock, (self.x, self.ran2))

        if self.ran == 3: #right to left
            self.x -= self.vel
        win.blit(self.rock, (self.x, self.ran2))
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #update rect position


def rgw():
    win.blit (grid, (0,0))
    player.draw(win)
    for rock in rocks:
        rock.draw(win)
        colliding = player.rect.colliderect(rock.rect)

        if colliding:
            print('collide') #nothing happens, even when touching rock
    pygame.display.update()

pygame.time.set_timer(rock_spawn_ev, rockWait)

player = player()

rocks = []

run = True
while run:
    clock.tick(60)

    events = pygame.event.get()

    for event in events:
        if event.type == pygame.QUIT:
            run = False
        if event.type == rock_spawn_ev:
            rock(6)

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP and player.y > 9:
                player.y -= 50
            elif event.key == pygame.K_DOWN and player.y < ySize - 41:
                player.y += 50
            elif event.key == pygame.K_LEFT and player.x > 9:
                player.x -= 50
            elif event.key == pygame.K_RIGHT and player.x < xSize - 41:
                player.x += 50

    rgw()
pygame.quit()

I think that colliding = player.rect.colliderect(rock.rect) should return True when touching a rock, but "collide" never gets printed, in this for loop:

for rock in rocks:
        rock.draw(win)
        colliding = player.rect.colliderect(rock.rect)

        if colliding:
            print('collide') #nothing happens, even when touching rock

I know that the for loop itself works, because the rocks are being drawn

class player(object):

    def __init__(self):
        self.x = 109
        self.y = 109
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #rect for collision

    def draw(self, win):
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #update rect position


class rock(object):

    def __init__(self):
        rocks.append(self)
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #rect for collision

    def draw(self, win): 
        self.rect = pygame.Rect(self.x, self.y, 32, 32) #update rect position

player = player()
rocks = []
def rgw():
    win.blit (grid, (0,0))
    player.draw(win)
    for rock in rocks:
        rock.draw(win)
        colliding = player.rect.colliderect(rock.rect)
        if colliding:
            print('collide') #nothing happens, even when touching rock
    pygame.display.update()

Shgaug
  • 11
  • 4
  • Sorry if this is a silly question. I'm new to pygame. – Shgaug Jun 18 '20 at 22:34
  • 1
    It will help if you can make a [mre]. – khelwood Jun 18 '20 at 22:36
  • @khelwood Ok, I made one – Shgaug Jun 18 '20 at 23:57
  • 1
    Your player image is 32x32 pixels right? Normally you set the rect off the image: `self.rect = self.image.get_rect()`. If the rect has an incorrect size, this could cause your issue. Maybe try drawing the collision rects too themselves (just the outline) when you paint the sprites. – Kingsley Jun 19 '20 at 02:33

1 Answers1

2

First of all, there is no rock drawn at the position (self.x, self.y), but there are rocks drawn at the positions (self.ran2, self.y) and (self.x, self.ran2)


I recommend to create the rectangles which surround the objects from the corresponding pygame.Surface objects. Use get_rect() to generate a pygame.Rect object with the size of the image and set the position by keyword arguments (self.rect = self.rock.get_rect(topleft = (self.x, self.ran2))) or use the rectangle which is returned by pygame.Surface.blit. For instance:

class player(object):
    # [...]

    def draw(self, win):
        # [...]
        self.rect = win.blit(self.right[self.frameCount//5], (self.x, self.y))
class rock(object):
    # [...]

    def draw(self, win): 
        # [...]
        self.rect = win.blit(self.rock, (self.x, self.ran2))

Since in the class rock are drawn 2 rocks at the positions (self.ran2, self.y) and (self.x, self.ran2), you have to set 2 different rectangle objects:

class rock(object):
    # [...]

    def draw(self, win): 
        # [...]

        self.rect_1 = win.blit(self.rock, (self.ran2, self.y))

        # [...]

        self.rect_2 = win.blit(self.rock, (self.x, self.ran2))

And you have to do 2 collision tests:

def rgw():
    win.blit (grid, (0,0))
    player.draw(win)
    for rock in rocks:
        rock.draw(win)

        colliding = player.rect.colliderect(rock_1.rect) or player.rect.colliderect(rock_2.rect)
        if colliding:
            print('collide') #nothing happens, even when touching rock

    pygame.display.update()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174