1

I am trying to make a tetris game and below is my code to make the blocks move. I want the block to keep moving when an arrow key is held down and to stop when it is released. But when I run the code, it stops the block even if the key isn't released.

   def set_keyboard_dirs(cur_block, width, height, events): # events stores pygame.event.get() as I use it multiple times in my code
        global move_timer # only moves block one time per set number of frames
        cur_block.reset_collisions(height)
        for event in events:
            if event.type == pygame.KEYDOWN:  # sets magnitude and direction of movement
                if event.key == pygame.K_RIGHT:
                    cur_block.dir = (cur_block.length, 0)
                elif event.key == pygame.K_LEFT:
                    cur_block.dir = (-cur_block.length, 0)
                elif event.key == pygame.K_DOWN:
                    cur_block.dir = (0, cur_block.length)
                elif event.key == pygame.K_UP:
                    cur_block.rotate(height, width)
                elif event.key == pygame.K_SPACE: # just moves the block instantly to the bottom of the screen by equating it to a 'projection' already there. 
                    cur_block.shape = deepcopy(cur_block.projection)
            elif event.type == pygame.KEYUP:  # stops block from moving
                print(event.key) # I called this to see what's happening, and event.key is printed event when I didn't release the key. 
                cur_block.dir = (0, 0)

        cur_block.move()

Because of the above, the block moves one step at a time instead of continuously (for as long as they are holding it) like I want. How can I fix it please? The rest of the game works so I really want this to work too. Thanks a lot in advance.

EDIT: I have also tried setting controls using pygame.key.get_pressed() as follows:

def set_keyboard_dirs(cur_block, width, height):
    global move_timer, keys
    cur_block.reset_collisions(height)
    cur_block.dir = (0, 0)
    if keys[pygame.K_UP] or keys[pygame.K_w]:
        cur_block.rotate(height, width)
    elif keys[pygame.K_SPACE]:
        cur_block.shape = deepcopy(cur_block.projection)
    elif (keys[pygame.K_DOWN] or keys[pygame.K_s]) and 2 not in cur_block.collisions: # 1, 2, 3 are collisions in left, down and right directions
        cur_block.dir = (0, cur_block.length)
    elif (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and 1 not in cur_block.collisions:
        cur_block.dir = (cur_block.length, 0)
    elif (keys[pygame.K_LEFT] or keys[pygame.K_a]) and 3 not in cur_block.collisions:
        cur_block.dir = (-cur_block.length, 0)
    else:
        print('ran reset') # this statement print even as i'm holding down a key for some reason
        cur_block.dir = (0, 0)
    if cur_block.dir != (0, 0) and move_timer == 0:
        cur_block.move()
        move_timer = 7

in the former case, if I remove the KEYUP event and in the latter case if I remove the else statement, the block moves continuously (but cannot stop) which also shows that it is those statements are what is causing the problem, I think. And this is the only place is my code where I define my cur_block.dir as well.

Vijay
  • 65
  • 10

2 Answers2

0

That is probably because your for loop runs 1 time per frame, so if you hold down your button it count as you pressed it 1 time at that specific frame, same with the KEYUP events. You can try to make two variables outside of the mainloop left=False and right=False And outside of your current for loop, you check if any button pressed.

#these are outside of the mainloop
left=False
right=False



keys = pygame.key.get_pressed()  # checks for key events (put this outside of the for loop, but still be inside your mainloop)
if keys[pygame.K_LEFT]:
    right = False
    left = True
elif keys[pygame.K_RIGHT]:
    left = False
    right = True

# if none of those buttons pressed, it sets the values back to False
else:
    right = False
    left = False

# using the left value, if its true, it will do your action every frame, 
#(you can adjust the speed of your block later)

if left:
    #  do something
    cur_block.dir = (-cur_block.length, 0)
if right:
    # do something else


and then if you press LEFT key for example, the value of Left will be true, and then you can check: if any of those values true > do something.

Based on your example code, this is the only thing that I can come up with. I hope it works.

Cappi
  • 21
  • 4
  • Hi, I also did try using pygame.key.get_pressed() first, but for some reason the else statement ran every time, even as I was pressing say like the right key. I'll edit my question on top to show you want I did before. Idk why that's happening, it hasn't happened to me before – Vijay Apr 26 '20 at 09:19
0

In your code the movement of the block is canceled if any key is released, not if the special key is released. You would have to implements special cases if on of the cursor keys is released:

elif event.type == pygame.KEYUP:
    if event.key == pygame.K_RIGHT:
        # [...]
    elif event.key == pygame.K_LEFT:
        # [...]
    # [...]

I recommend to set the movement direction, dependent on the key states which are returned by pygame.key.get_pressed():

def set_keyboard_dirs(cur_block, width, height, events):
    global move_timer
    cur_block.reset_collisions(height)

    keys = pygame.key.get_pressed()

    cur_block = [0, 0]
    if key[pygame.K_RIGHT]:
        cur_block.dir[0] += cur_block.length
    if key[pygame.K_LEFT]:
        cur_block.dir[0] -= cur_block.length
    if key[pygame.K_DOWN]:
        cur_block.dir[1] += cur_block.length
    if key[pygame.K_UP]:
        cur_block.rotate(height, width)
    if key[pygame.K_SPACE]:
        cur_block.shape = deepcopy(cur_block.projection)

    cur_block.move()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • if I try pygame.key.get_pressed(), I run into a similar problem. I edited my comment above to show you what I mean. – Vijay Apr 26 '20 at 09:42
  • I called it in the main loop before to get it in every frame, but even if I try call it in the function like you said, the block still only moves one step every time I press and hold the key instead of moving continuously. It's weird cause I had a game before when I used pygame.key.get_pressed() and it went fine but now it is not, and I have no idea why, even if I look at the codes next to each other, it is almost the same as I did before. – Vijay Apr 26 '20 at 10:06
  • @Vijay So what should I do? I can't see your code. You have to debug your code yourself. Do you call `pygame.display.set_mode()` in the application loop? – Rabbid76 Apr 26 '20 at 10:07
  • oh, yes that is also called every time in the main loop – Vijay Apr 26 '20 at 10:24
  • @Vijay Remove it! The information which is returned by `pygame.key.get_pressed()` is set by the event handling. When `pygame.display.set_mode()` the display and io events are is reinitialize – Rabbid76 Apr 26 '20 at 10:27
  • ooooh! I see, I wasn't aware of that, thank you, it works now. – Vijay Apr 26 '20 at 11:12