Why is my collision test always returning ‘true’ and why is the position of the rectangle of the image always wrong (0, 0)?

Posted on

Solving problem is about exposing yourself to as many situations as possible like Why is my collision test always returning ‘true’ and why is the position of the rectangle of the image always wrong (0, 0)? and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about Why is my collision test always returning ‘true’ and why is the position of the rectangle of the image always wrong (0, 0)?, which can be followed any time. Take easy to follow this discuss.

Why is my collision test always returning ‘true’ and why is the position of the rectangle of the image always wrong (0, 0)?

My collide_rect function isn’t working properly. It always returns True, when it’s not suppose to. I have tried looking on the internet but nothing is working for me. I think the collide rect somehow did not use the actual coordinates for the two sprites. Can anyone help with this?

import pygame
import pygame.sprite
import sys
gameDisplay = pygame.display.set_mode((800,600))
pygame.display.set_caption("test_collision")
clock = pygame.time.Clock()
crashed = False
class Ball(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("ball.png")
        self.rect = self.image.get_rect()
        self.x = 280
        self.y = 475
        self.col = False
    def update(self):
        gameDisplay.blit(self.image, (self.x,self.y))
        self.rect = self.image.get_rect()
    def test_collisions(self,sprite):
        self.col = pygame.sprite.collide_rect(self,sprite)
class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.x = 1000
        self.y = 483
        self.image = pygame.image.load("obstacle.png")
        self.time = pygame.time.get_ticks()
        self.rect = self.image.get_rect()
    def change_x(self):
        self.time = pygame.time.get_ticks()
        self.x = -(self.time/5) + 800
    def update(self):
        self.rect = self.image.get_rect()
        gameDisplay.blit(self.image,(self.x,self.y))
obstacle = Obstacle()
ball = Ball()
while not crashed:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True
    gameDisplay.fill((255,255,255))
    ball.update()
    obstacle.change_x()
    obstacle.update()
    ball.test_collisions(obstacle)
    if ball.col:
        print("colided")
    pygame.display.flip()
    clock.tick(1000)
pygame.quit()
sys.exit()

P.S This is my first post 🙂

Asked By: aqua959

||

Answer #1:

pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, but it returns a rectangle that always starts at (0, 0) since a Surface object has no position.
The Surface is placed at a position on the display with the blit function.

You’ve to set the location of the rectangle, either by a keyword argument, e.g:

self.rect = self.image.get_rect(topleft = (self.x, self.y))

or an assignment to a virtual attribute (see pygame.Rect), e.g:

self.rect = self.image.get_rect()
self.rect.topleft = (self.x, self.y)

It is absolutely unnecessary to add some extra attributes self.x and self.y. Use the location of the rectangle instead. e.g:

class Ball(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("ball.png")
        self.rect = self.image.get_rect(topleft = (280, 475))
        self.col = False
    def update(self):
        gameDisplay.blit(self.image, self.rect)
    def test_collisions(self,sprite):
        self.col = pygame.sprite.collide_rect(self,sprite)
class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("obstacle.png")
        self.time = pygame.time.get_ticks()
        self.rect = self.image.get_rect(topleft = (1000, 483))
    def change_x(self):
        self.time = pygame.time.get_ticks()
        self.rect.x = -(self.time/5) + 800
    def update(self):
        gameDisplay.blit(self.image, self.rect)

Further note, that you can get rid of the methods Ball.update() respectively Obstacle.update() (you can delete them), if you use a pygame.sprite.Group and call .draw(), which uses the .image and .rect properties of the contained sprites, to draw them. e.g.:

obstacle = Obstacle()
ball = Ball()
all_sprites = pygame.sprite.Group([obstacle, ball])
while not crashed:
    # [...]
    gameDisplay.fill((255,255,255))
    all_sprites.draw(gameDisplay)
    pygame.display.flip()
    clock.tick(1000)
Answered By: Rabbid76
The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published. Required fields are marked *