Question

I'm building a menu using pygame and I want to make it navigable using a specific gamepad. Ideally I want to be able to press and hold *down" on the D-pad repeatedly, or get something like on a keyboard where the first button press has a delay before repeatedly entering the same character (seemingly).

I'm trying to emulate the pygame.key.set_repeat(...) function for a Joystick. my approach so far has been

pygame.time.set_timer(pygame.USEREVENT, 10)
DELAY_TIME = 0.250 #ms
y_delay = True
while not done:
    for event in pygame.event.get():
        y_axis = gamepad.get_axis(1)
        if y_axis > 0.5: # pushing down
            main_menu.move_down()
            redraw() #redraw everything on the surface before sleeping
            if y_delay:
                time.sleep(DELAY_TIME)
                y_delay = False #don't delay the next time the y axis is used


        elif y_axis < -0.5: #pushing up
            # repetitive I know, but I'm still working on it
            main_menu.move_up()
            redraw()
            if y_delay: 
                time.sleep(DELAY_TIME)
                y_delay = False 

        else:
            y_delay = True # delay the next time

my issue is if someone taps up or down faster than DELAY_TIME they are limited to the DELAY_TIME before they can move again. Also if someone releases and depresses the up/down button within the time.sleep interval, python never sees that it was released at all and doesn't allow for a delay.

Maybe there's a way to do this using events or mapping the joystick to keys somehow? qjoypad doesn't cut it for me, and joy2keys is trash. I would need to do the mapping within the python program.

Was it helpful?

Solution

Sleep causes the program to halt execution, so it's not a viable option. You can also do this without using set_timer and events. I did it using a couple of flags and pygame.time's get_ticks.

import pygame
from pygame.locals import *

def main():
    pygame.init()
    pygame.display.set_mode((480, 360))
    gamepad = pygame.joystick.Joystick(0)
    gamepad.init()

    delay = 1000
    neutral = True
    pressed = 0
    last_update = pygame.time.get_ticks()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                return

        move = False
        if gamepad.get_axis(1) == 0:
            neutral = True
            pressed = 0
        else:
            if neutral:
                move = True
                neutral = False
            else:
                pressed += pygame.time.get_ticks() - last_update
        if pressed > delay:
            move = True
            pressed -= delay
        if move:
            print "move"
        last_update = pygame.time.get_ticks()

if __name__ == "__main__":
    main()
    pygame.quit()

When get_axis indicates no motion, the neutral flag is set, and the pressed timer is reset, causing the move flag to remain unset. When the neutral flag is unset, if it's newly set, the move flag is set. If it's not newly set, the pressed timer increases, and move is set only if the pressed timer is greater than delay.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top