Search code examples
python-3.xgraphicspygamekeypresspygame-surface

Pygame key.get_pressed acted on unintended object?


I am writing a simple class Block which holds four Rect from pygame. It has a key_press function which would move the four Rect when according keys are pressed. It also has a draw function which draws the four Rect on the screen.

The problem comes within the while loop below. Within the while loop, I want to move the block around with keys. Whenever the current block reaches the bottom of the screen, it stops there and a new block gets created. The key press functionality should now ONLY act on the new block.

However, the problem I have with the codes below is that, after the new block is created, the key press acts on BOTH of the blocks (i.e. pressing right would move both to the right).

so I guess my problem could be summed up into one question:

Why didn't the key press function act on the current block only, but both?

Thank you very much in advance!

import pygame
from pygame.rect import Rect

pygame.init()

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

# Set the height and width of the screen
block_size = 20
row, col = 20, 20
color = RED
size = [block_size * col, block_size * row]
screen = pygame.display.set_mode(size)


class Block(Rect):
    shape = []  # hold blocks which are part of the shape

    def __init__(self):
        self.block1 = Rect(0, block_size, block_size, block_size)
        self.block2 = Rect(0, block_size * 2, block_size, block_size)
        self.block3 = Rect(0, block_size * 3, block_size, block_size)
        self.block4 = Rect(0, block_size * 4, block_size, block_size)
        self.shape.append(self.block1)
        self.shape.append(self.block2)
        self.shape.append(self.block3)
        self.shape.append(self.block4)

    def key_press(self):
        key = pygame.key.get_pressed()
        if key[pygame.K_LEFT]:
            for item in self.shape:
                item.move_ip(-block_size, 0)

        if key[pygame.K_RIGHT]:
            for item in self.shape:
                item.move_ip(block_size, 0)

        if key[pygame.K_UP]:
            for item in self.shape:
                item.move_ip(0, -block_size)

        if key[pygame.K_DOWN]:
            for item in self.shape:
                item.move_ip(0, block_size)

    def draw(self, surface):
        for item in self.shape:
            pygame.draw.rect(surface, color, item)

    def get_bottom(self):
        return self.block4.bottom

done = False
clock = pygame.time.Clock()

curr_block = Block()

while not done:

    clock.tick(10)

    for event in pygame.event.get():  # User did something
        if event.type == pygame.QUIT:  # If user clicked close
            done = True  # Flag that we are done so we exit this loop

    screen.fill(WHITE)

    curr_block.key_press()

    if curr_block.get_bottom() >= block_size * row:
        curr_block = Block()

    curr_block.draw(screen)  # draw the falling block

    pygame.display.flip()

pygame.quit()





Solution

  • Every time when a new block is created by curr_block = Block(), then 4 new elements are append at the end of the list self.shape. If you only want to move the most resent blocks, then then you have to move the last 4 elements of self.shape. The last 4 elements can be accessed by self.shape[-4:] (See Subscriptions). For instance:

    class Block(Rect):
        # [...]
    
        def key_press(self):
            key = pygame.key.get_pressed()
    
            for item in self.shape[-4:]:
    
                if key[pygame.K_LEFT]:
                    item.move_ip(-block_size, 0)
    
                if key[pygame.K_RIGHT]:
                    item.move_ip(block_size, 0)
    
                if key[pygame.K_UP]:
                    item.move_ip(0, -block_size)
    
                if key[pygame.K_DOWN]:
                    item.move_ip(0, block_size)