1

As you can see on this Picture,

Picture there is my rectangle (red) that I am controlling and green ones that I am not controlling. I want those green rectangles to constantly move from left to right (Every second one is moving in the opposite direction). I tried to do it, but I only managed them to go to one side and then they stop. I don't know how to make them go back to the other side and then do that constantly. Here is the picture how it looks after my if statement ends.

enter image description here

import pygame


pygame.init()
win = pygame.display.set_mode((1200, 600))
clock = pygame.time.Clock()
BLACK = (0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
GREEN = (13, 255, 0)

player = pygame.Rect(40, 45, 30, 30)
vel = 4


walls = [
pygame.Rect(0, 0, 1200, 20), pygame.Rect(0, 0, 20, 600),
pygame.Rect(0, 580, 1200, 20), pygame.Rect(1180, 0, 20, 600),
pygame.Rect(300, 0, 20, 530), pygame.Rect(20, 100, 230, 20),
pygame.Rect(70, 200, 230, 20), pygame.Rect(20, 300, 230, 20),
pygame.Rect(70, 400, 230, 20), pygame.Rect(600, 100, 20, 500),
]

movingobjectsleft = [
pygame.Rect(320, 120, 30, 30),
pygame.Rect(320, 240, 30, 30),
pygame.Rect(320, 360, 30, 30),
]

movingobjectsright = [
pygame.Rect(570, 180, 30, 30),
pygame.Rect(570, 300, 30, 30),
pygame.Rect(570, 420, 30, 30)
]

run = True
while run:
# Handle the events.
for event in pygame.event.get():
    if event.type == pygame.QUIT:
        run = False

keys = pygame.key.get_pressed()

# Update the player coordinates.
if keys[pygame.K_LEFT] and player.x > 0:
    player.x -= vel
if keys[pygame.K_RIGHT] and player.x < 1200 - player.width:
    player.x += vel
if keys[pygame.K_UP] and player.y > 0:
    player.y -= vel
if keys[pygame.K_DOWN] and player.y < 600 - player.height:
    player.y += vel

# Game logic for walls and moving objects
for wall in walls:
    # Check if the player rect collides with a wall rect.
    if player.colliderect(wall):
        print("Game over")

for object in movingobjectsleft:
    if player.colliderect(object):
        print("Game over")
    if object.x < 570:
        object.x += vel


for object in movingobjectsright:
    if player.colliderect(object):
        print("Game over")
    if object.x > 320:
        object.x -= vel

# Draw everything.
win.fill(WHITE)
pygame.draw.rect(win, RED, player)
# Drawing walls and moving objects
for wall in walls:
    pygame.draw.rect(win, BLACK, wall)

for object in movingobjectsright:
    pygame.draw.rect(win, GREEN, object)

for object in movingobjectsleft:
    pygame.draw.rect(win, GREEN, object)

pygame.display.update()
clock.tick(60)

pygame.quit()

I think something needs to be done here

for object in movingobjectsleft:
    if player.colliderect(object):
        print("Game over")
    if object.x < 570:
        object.x += vel


for object in movingobjectsright:
    if player.colliderect(object):
        print("Game over")
    if object.x > 320:
        object.x -= vel

1 Answer 1

1

You could create a pygame.Rect subclass with an additional vel attribute and an update method in which you move the rect and do the bounds checking (or create a class which has a rect and a vel attribute):

class MovingRect(pygame.Rect):

    def __init__(self, x, y, w, h, vel):
        # Call the __init__ method of the parent class.
        super().__init__(x, y, w, h)
        self.vel = vel

    def update(self):
        self.x += self.vel  # Move.
        if self.right > 600 or self.left < 320:  # If it's not in this area.
            self.vel = -self.vel  # Invert the direction.


vel_left = 4
vel_right = -4

movingrects = [
    MovingRect(320, 120, 30, 30, vel_left),
    MovingRect(320, 240, 30, 30, vel_left),
    MovingRect(320, 360, 30, 30, vel_left),
    MovingRect(570, 180, 30, 30, vel_right),
    MovingRect(570, 300, 30, 30, vel_right),
    MovingRect(570, 420, 30, 30, vel_right),
]

In the while loop:

for movingrect in movingrects:
    movingrect.update()  # Movement and bounds checking.
    if player.colliderect(movingrect):
        print("Game over")

# Draw everything.
# ...
for movingrect in movingrects:
    pygame.draw.rect(win, GREEN, movingrect)

If you need a timer, check out these answers: Countdown timer in Pygame


If you don't know yet how classes work, you could define a boolean flag (invert_direction) and set it to True when one of the rects leaves the specified area. If it's True after the for loop, invert the vel_left/vel_right variables.

vel_left = 4
vel_right = -4

run = True
while run:
    # Handle the events.
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()

    # Update the player coordinates.
    if keys[pygame.K_LEFT] and player.left > 0:
        player.x -= vel
    if keys[pygame.K_RIGHT] and player.right < 1200:
        player.x += vel
    if keys[pygame.K_UP] and player.top > 0:
        player.y -= vel
    if keys[pygame.K_DOWN] and player.bottom < 600:
        player.y += vel

    # Game logic for walls and moving objects
    for wall in walls:
        # Check if the player rect collides with a wall rect.
        if player.colliderect(wall):
            print("Game over")

    # Set this variable to True if the direction should be inverted.
    invert_left = False
    for object in movingobjectsleft:
        if player.colliderect(object):
            print("Game over")

        object.x += vel_left  # Move the object.

        # Check if the object has left the area.
        if object.right > 600 or object.left < 320:
            # Invert the direction after the loop.
            invert_left = True

    if invert_left:  # Invert the direction.
        vel_left = -vel_left

    # Now do the same for the right objects.
    invert_right = False
    for object in movingobjectsright:
        if player.colliderect(object):
            print("Game over")

        object.x += vel_right

        if object.right > 600 or object.left < 320:
            invert_right = True

    if invert_right:
        vel_right = -vel_right
Sign up to request clarification or add additional context in comments.

6 Comments

Side note: Better don't use built-in names like object for your variables. Check out Program Arcade Games (chapters 12 and 13) if you want to learn how to use classes and pygame sprites.
Thank you for your help once again. I've read chapter about classes and things are more clear now, but I still have some questions about the code you wrote. I don't understand what does ` super().__init__(x, y, w, h)` do. And why do I need self.vel = vel in rectangle class if I am using special velocity for moving rectangles. vel is only for my rectangle that I am controlling or?
When you're creating an instance, the __init__ method of the class gets called automatically. In the MovingRect class you have to call the __init__ method of the parent class pygame.Rect with the super function to initialize the rect. Instead of the super you could also write pygame.Rect.__init__(self, x, y, w, h).
"And why do I need self.vel = vel ..." -- The vel in the __init__ method is a local variable which has nothing to do with the vel variable in the global scope (you can give the local variable a different name to make it less confusing). When I instantiate the MovingRect objects, I pass the velocity vel_left as the fifth argument MovingRect(320, 120, 30, 30, vel_left) and that means the value of vel_left will be assigned to the vel in the __init__ method. I hope it's a bit clearer now.
These attributes are inherited from the pygame.Rect class. Because the MovingRect is a subclass of pygame.Rect, it has all the attributes and methods of a normal rect.
|

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.