Rectangle glitching, not moving with the rest

import pygame
import sys
from pygame.sprite import Sprite
class Settings:
    def __init__(self):
        self.raindrop_speed = 3
        self.raindrop_direction = -1
        self.raindrop_dropseed = 3
        self.backgroundcolor = (30,30,30)
class Drop(Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load("raindrop.png")
        self.rect = self.image.get_rect()
        self.rect.y = self.rect.height
        self.rect.x = self.rect.width
        self.x_cord = self.rect.x
        self.y_cord = self.rect.y

class RainDrop:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((1200,800))
        self.settings = Settings()
        self.backgroundcolor = self.settings.backgroundcolor
        self.raindrops = pygame.sprite.Group()
        self.screen_rect = self.screen.get_rect()
        self._add_raindrops()
    def _add_raindrops(self):
        new_raindrop = Drop()
        drop_height = new_raindrop.rect.height 
        drop_width = new_raindrop.rect.width
        print(drop_width)
        screen_space = self.screen_rect.width
        screen_height_space = self.screen_rect.height
        aviable_row_space = screen_height_space//(drop_height*2)
        avivable_screen_space = screen_space - (drop_width*2)
        amount_of_columns = avivable_screen_space//(drop_width*2)
        self._add_columns(amount_of_columns,aviable_row_space)
        
    def _add_columns(self,amount_of_columns,aviable_row_space):
        for height_of_drops in range(aviable_row_space):
            for number_of_drops in range(amount_of_columns):
                drop = Drop()
                drop.x_cord = (drop.rect.width *2)* number_of_drops
                drop.y_cord =(drop.rect.height *2)* height_of_drops
                drop.rect.x = drop.x_cord
                drop.rect.y = drop.y_cord
                self.raindrops.add(drop)
    def _bring_down_raindrops(self):
        for drop in self.raindrops:
            drop.y_cord += self.settings.raindrop_dropseed
            drop.rect.y = drop.y_cord
    def _update_drops(self):
        height_counter = 1
        self.raindrops.update()
        for drop in self.raindrops.copy():
            drop.x_cord += self.settings.raindrop_direction * self.settings.raindrop_speed  
            drop.rect.x = drop.x_cord
            if drop.rect.right >= self.screen_rect.right:
                self.settings.raindrop_direction = -1
                self._bring_down_raindrops()
            elif drop.rect.left <= 0:
                self.settings.raindrop_direction = 1
                self._bring_down_raindrops()
            #if drop.rect.y >= self.screen_rect.height or drop.rect.y <= 0:
            #    drop.rect.x = drop.rect.width
             #   drop.y_cord = drop.rect.height 
              #  drop.rect.y = drop.y_cord
        print(height_counter)
        print(self.raindrops)
    
    def _update_game(self):
        self.screen.fill(self.backgroundcolor)
        self.raindrops.draw(self.screen)
        pygame.display.flip()
    def _check_events(self):
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    sys.exit()
    def run_game(self):
        while True:
            self._check_events()
            self._update_drops()
            self._update_game()

if __name__ == "__main__":
    rd = RainDrop()
    rd.run_game()

Everytime I run this program the rectangle(waterdrops) when they reach the end of the screen a bigger gap appears I have looked at the code for several hours and I can not see what the problem is, I think it has to do with the condition in bottom but I am not sure I have messed with it and changed some values but it still does the same thing.

Answers 1

  • Your problem is in what you do when you recognize that you've hit the edge of the screen. You do this when you find any drop that has gone off of the screen, and at that point, you reverse direction. The problem is, you've already moved some of the drops on the top row in one direction, but after you recognize the edge of the screen, you then go on to move the rest of the drops in the opposite direction in that same pass. This is how things get out of wack.

    What you want to do is note that you've hit the edge of the screen, but not do anything differently right away, so that you still deal with all of the drops on the screen the same way in that pass. After you've drawn all of the drops, you then change direction.

    Here's a version of _update_drops that will do this:

    def _update_drops(self):
        height_counter = 1
        self.raindrops.update()
        # assume we haven't hit either edge of the screen
        reverse = 0
        for drop in self.raindrops.copy():
            drop.x_cord += self.settings.raindrop_direction * self.settings.raindrop_speed
            drop.rect.x = drop.x_cord
            if drop.rect.right >= self.screen_rect.right:
                # remember that we hit the right edge of the screen
                reverse = -1
            elif drop.rect.left <= 0:
                # remember that we hit the left edge of the screen
                reverse = 1
    
        # if we hit one of the edges, change directions and drop down
        if reverse != 0:
            self.settings.raindrop_direction = reverse
            self._bring_down_raindrops()
    

Related Articles