Suppose that I want to make a very simply program in python that indicates how long a key is pressed. So if I type and hold the j key for a few moments, I am looking to write a program capable of displaying information like the key 'j' was pressed for 1.1 seconds.
From what I understand, the way this should be achieved is by detecting and timestamping the KEYDOWN events and KEYUP events, and making appropriate subtractions of timestamps. So it would suffice to detect KEYDOWN and KEYUP events.
There are a wide variety of questions and answers on SO concerning detecting a single keypress or about detecting single character input, such as this one or this one, which both use some form of getch. I've looked at the python curses library, and from what I can tell the primary form of key detection is also in the form of single-character getch(). But these do not detect the length of keypress --- they only detect KEYDOWN.
I recognize that detecting the length of a keypress is a necessary task in gaming, and so I expect that pygame has methods to detect keypress duration. But I would hope that it is possible to use a much slimmer and more direct library to detect keypress duration.
#Using pynput module: (Best)
You can use this code:
from pynput import keyboard
import time
def on_key_release(key): #what to do on key-release
time_taken = round(time.time() - t, 2) #rounding the long decimal float
print("The key",key," is pressed for",time_taken,'seconds')
return False #stop detecting more key-releases
def on_key_press(key): #what to do on key-press
return False #stop detecting more key-presses
with keyboard.Listener(on_press = on_key_press) as press_listener: #setting code for listening key-press
press_listener.join()
t = time.time() #reading time in sec
with keyboard.Listener(on_release = on_key_release) as release_listener: #setting code for listening key-release
release_listener.join()
#Using pygame: (Good)
import time
import pygame
import os
os.environ["SDL_VIDEO_CENTERED"] = "1"
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Time")
clock = pygame.time.Clock()
pygame.init()
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
break
if event.type == pygame.KEYDOWN:
# detect key 'a'
if event.key == pygame.K_a: # key 'a'
t = time.time()
if event.type == pygame.KEYUP:
if event.key == pygame.K_a: # key 'a'
t = time.time() - t; t = str(t); t = t[:5]
print("You pressed key 'a' for",t,'seconds')
screen.fill((255, 255, 255))
pygame.display.update()
clock.tick(40)
It will only detect the keys that you will write in the code.
Use pip install pynput to install pynput.
Use pip install pygame to install pygame.
Related
So i'm building an application that controls a mini drone and to control the drone i use DragonRise Inc. PC TWIN SHOCK Gamepad USB joystick in Pygame. What i want it to do, is go through a while loop every 70ms and check if there is a Pygame joystick event. If so than execute some code. If not, then execute some other piece of code.
What I've read online is that is done by checking if the length of the pygame.event.get() list is greater than 0. If so, there is motion, if not (else) no motion. But unfortunately this doesn't work well.
The situation is when i push the joystick axis up, it executes not only the block of code associated with pygame.JOYAXISMOTION event but also the else block of code.
Anyone know how to fix this, or have a better solution ?
import time
import pygame
done = False
deadzone = 0.1
pygame.init()
pygame.joystick.init()
joystick = pygame.joystick.Joystick(0)
joystick.init()
while not done:
events = pygame.event.get()
if len(events) > 0:
for event in events:
if event.type == pygame.JOYAXISMOTION:
if joystick.get_axis(1) < -1 * deadzone:
print('Throttle Up')
if joystick.get_axis(1) > deadzone:
print('Throttle Down')
else:
print('No Event')
time.sleep(0.07)
You don't have to evaluate the JOYAXISMOTION at all. pygame.joystick.Joystick.get_axis gets the current position of an axis. Just evaluate the position with a 70ms interval. Use pygame.time.Clock.tick instead of time.sleep:
clock = pygame.time.Clock()
while not done:
clock.tick(70)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
axis_pos = joystick.get_axis(1)
if axis_pos < -1 * deadzone:
print('Throttle Up')
elif axis_pos > deadzone:
print('Throttle Down')
else:
print('No Event')
When I want to freeze my pygame window for a few seconds I usually use time.sleep(). However, if I accidentaly press any key on my keyboard meanwhile it detects the key after the time has passed. Is there any way to freeze my pygame window so that the code won’t consider the key pressed?
You have to use pygame.time.wait() rather than time.sleep(). Be aware that the input has to be set in millisecond.
See documentation: time.wait()
Here is an example where the screen will change color every frame. The title bar displays the last key pressed.
If the space bar is pressed, the color change is paused for three seconds. Key presses are ignored, but other events may be handled during this period.
This is accomplished by setting up a custom timer and using a variable to track the paused state.
import pygame
import itertools
CUSTOM_TIMER_EVENT = pygame.USEREVENT + 1
my_colors = ["red", "orange", "yellow", "green", "blue", "purple"]
# create an iterator that will repeat these colours forever
color_cycler = itertools.cycle([pygame.color.Color(c) for c in my_colors])
pygame.init()
pygame.font.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode([320,240])
pygame.display.set_caption("Timer Example")
done = False
paused = False
background_color = next(color_cycler)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == CUSTOM_TIMER_EVENT:
paused = False
pygame.display.set_caption("")
pygame.time.set_timer(CUSTOM_TIMER_EVENT, 0) # cancel the timer
elif not paused and event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pygame.time.set_timer(CUSTOM_TIMER_EVENT, 3000)
pygame.display.set_caption("Paused")
paused = True
else:
pygame.display.set_caption(f"Key: {event.key} : {event.unicode}")
if not paused:
background_color = next(color_cycler)
#Graphics
screen.fill(background_color)
#Frame Change
pygame.display.update()
clock.tick(5)
pygame.quit()
EDIT: Change to ignore key-presses during the paused period as the question asked.
Pygame sound effects do not play for a few seconds if the corresponding buttons (to play the sound effect) is pressed for four consecutive times.
I'm currently trying to experiment with different keys of the piano.
I've tried removing the pygame clock object.
I've tried making the Sound.play() into a function, as found in the code.
import pygame
pygame.init()
###LordKeys###
A5 = pygame.mixer.Sound('PianoKeys/A5.wav')
A6 = pygame.mixer.Sound('PianoKeys/A6.wav')
def A56():
A5.play()
A6.play()
###############################################
run = True
win = pygame.display.set_mode((700,700))
pygame.display.set_caption("Piano Gen")
while run:
win.fill((255,255,255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
A56()
pygame.display.update()
Expected Results: the sound effect to play when the key is pressed, regardless of frequency.
You have to use the Sound function to play the sound. The sound variable you have created does not have a play() function.
Replace
A5.play()
A6.play()
with
pygame.mixer.Sound.play(A5)
pygame.mixer.Sound.play(A6)
So I decided to play the sounds on a channel and that solved the problem!
def A56():
channel1.play(A5)
channel1.play(A6)
We are having a holiday party at work, and are trying to set up a Family Feud game. With that, I'm trying to program a buzzer system. I am very new to pygame so maybe there is a better approach to what I'm trying to do.
I've written the following code which works to some degree. Right now, it recognizes the button and displays the picture as it should; however, it is recognizing all button presses where I only want it to recognize the first until after it is reset. For example, the left side buzzes in first, I want their picture to be displayed - then if the right team buzzes in after, I want that button to be ignored. Then if a third (reset) button is pushed, it resets back to the beginning to begin tracking for the first button pushed again. Any help would be greatly appreciated!
import pygame
import pdcurses
#import RPi.GPIO as GPIO
import image
import time
import clock
from pygame import mixer
from pygame.locals import *
displayWidth = 1600
displayHeight = 1200
pygame.init()
#mixer.init()
#pygame.display.init()
screen = pygame.display.set_mode((displayWidth, displayHeight))
pygame.display.set_caption('Family Feud')
pygame.display.update()
def reset():
global screen
kids = pygame.image.load("kids.jpg")
screen.blit(kids, (0,0))
pygame.display.update()
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_LEFT:
leftBuzzer = pygame.image.load("ice cream.jpg")
screen.blit(leftBuzzer,(0,0))
pygame.display.update()
if event.key == K_RIGHT:
rightBuzzer = pygame.image.load("snowman.jpg")
screen.blit(rightBuzzer,(0,0))
pygame.display.update()
if event.key == K_q:
pygame.quit()
if event.key == K_r:
reset()
You could add an alreadyPressed boolean and for each buzzer press have an if statement check alreadyPressed before displaying anything.
Okay, so I want to make an overlay screen.
So whenever the keypress is p then the screen pauses and a screen pops up saying
: "Press 'q' to quit or 'c' to continue,"
something like that.
Can anyone tell me how?
The easiest way to do this is using a submodule, then to create a new loop for blit()-ing to the screen and event handling for this pause menu.
(This is methodology only; this is how I work my projects.)
Update: 13/12/11
The following excerpt of code is from the "parent" module. This is just the loop section of code. What you're looking for is the line button.doAction(screen), which basically tells PyGame to execute the applicable submodule (not important; you just need to call the "child" function as you would normally).
while mainRunning:
# --- Event Catching & Handling ---
for event in pygame.event.get():
# Quit PyGame safely upon exit
if event.type == pygame.QUIT:
mainRunning = False
# Make the buttons do actions
if event.type == pygame.MOUSEBUTTONUP:
mousePos = pygame.mouse.get_pos()
for button in menuList:
X = button.getXPos()
Y = button.getYPos()
if X[0] < mousePos[0] < X[1] and Y[0] < mousePos[1] < Y [1]:
button.doAction(screen)
pygame.display.flip()
pygame.quit()
So if we say that the function we wanted was playGame.levelChoose() - remember, this is [submodule].[function] - then the loop in the "child" would be:
def levelChoose(screen, playerData, playerName):
levelChooseRunning = True
while levelChooseRunning:
# --- Event Catching & Handling ---
for event in pygame.event.get():
# Quit PyGame safely upon exit
if event.type == pygame.QUIT:
levelMenuRunning = False
pygame.display.flip()
(Of course, much code has been ommitted from these examples; if you'd like to pick apart the full files, they're over here on GitHub)
Let me know if there's more questions, because this probably just confused you some more...