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
skrx
  • 19,980
  • 5
  • 34
  • 48
RaZiiiGG
  • 203
  • 1
  • 15

1 Answers1

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
skrx
  • 19,980
  • 5
  • 34
  • 48
  • 1
    Side note: Better don't use built-in names like `object` for your variables. Check out [Program Arcade Games](http://programarcadegames.com) (chapters 12 and 13) if you want to learn how to use classes and pygame sprites. – skrx Aug 01 '18 at 05:24
  • 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? – RaZiiiGG Aug 01 '18 at 11:38
  • 1
    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)`. – skrx Aug 01 '18 at 11:44
  • 1
    "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. – skrx Aug 01 '18 at 11:56
  • Thank oyu, it is clearer now. I still have 1 more question. `if self.right > 600 or self.left < 320:` I understand what right and left does, but how can you just write right and left for the first time in code? right and left are only used here and it works. I know that means coordinates but how can it mean coordinates if you used it for the first time. – RaZiiiGG Aug 01 '18 at 13:42
  • 1
    These attributes are inherited from the [`pygame.Rect`](http://www.pygame.org/docs/ref/rect.html) class. Because the `MovingRect` is a subclass of `pygame.Rect`, it has all the attributes and methods of a normal rect. – skrx Aug 01 '18 at 14:12