Pygame action when no joystick event - python

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')

Related

pygame sprite not moving across screen when updates

I am trying to move my sprite across the screen when the window starts.... It moves for a second than stops for a while than it starts back up again. its not giving me an error.... So im really not sure whats going on here.... anyway here is the code.... any info is needed!
thanks,
import pygame
from sys import exit
pygame.init()
screen = pygame.display.set_mode((800,400))
sky_surface = pygame.image.load("bg_desert.png")
snail_surface = pygame.image.load("snailWalk1.png")
snail_x_pos = 600
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
snail_x_pos -=1
screen.blit(sky_surface,(0,0))
screen.blit(snail_surface,(snail_x_pos,350))
pygame.display.update()
Your loop will only execute when there are events. When there are no events, you don't move. If you wiggle your mouse in front of the screen, for example, you'll see pretty continuous movement.
You need to use pygame.time.set_timer to force an event for you to update.
It looks like the final 4 lines you have written are designed to run on each cycle of the for loop, however they will only run when an event occurs, because they are indented a block too far.
Your new code should look like this:
import pygame
from sys import exit
pygame.init()
screen = pygame.display.set_mode((800,400))
sky_surface = pygame.image.load("bg_desert.png")
snail_surface = pygame.image.load("snailWalk1.png")
snail_x_pos = 600
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
snail_x_pos -=1
screen.blit(sky_surface,(0,0))
screen.blit(snail_surface,(snail_x_pos,350))
pygame.display.update()

Python, pygame mouse position and which button is pressed

I have been trying to get my code collecting which mouse button is pressed and its position yet whenever I run the below code the pygame window freezes and the shell/code keeps outputting the starting position of the mouse. Does anybody know why this happens and more importantly how to fix it?
(For the code below I used this website https://www.pygame.org/docs/ref/mouse.html and other stack overflow answers yet they were not specific enough for my problem.)
clock = pygame.time.Clock()
# Set the height and width of the screen
screen = pygame.display.set_mode([700,400])
pygame.display.set_caption("Operation Crustacean")
while True:
clock.tick(1)
screen.fill(background_colour)
click=pygame.mouse.get_pressed()
mousex,mousey=pygame.mouse.get_pos()
print(click)
print(mousex,mousey)
pygame.display.flip()
You have to call one of the pygame.event functions regularly (for example pygame.event.pump or for event in pygame.event.get():), otherwise pygame.mouse.get_pressed (and some joystick functions) won't work correctly and the pygame window will become unresponsive after a while.
Here's a runnable example:
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
BG_COLOR = pygame.Color('gray12')
done = False
while not done:
# This event loop empties the event queue each frame.
for event in pygame.event.get():
# Quit by pressing the X button of the window.
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
# MOUSEBUTTONDOWN events have a pos and a button attribute
# which you can use as well. This will be printed once per
# event / mouse click.
print('In the event loop:', event.pos, event.button)
# Instead of the event loop above you could also call pygame.event.pump
# each frame to prevent the window from freezing. Comment it out to check it.
# pygame.event.pump()
click = pygame.mouse.get_pressed()
mousex, mousey = pygame.mouse.get_pos()
print(click, mousex, mousey)
screen.fill(BG_COLOR)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.

Determine length of keypress in python

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.

How can I detect if the user has double-clicked in pygame?

I know I can check if there was a left click
event.type == pygame.MOUSEBUTTONDOWN and event.button == LEFT
but how can I check if they double clicked? Also is there any way to check if the user moved the scroll wheel forward or backwards?
I'd just use the delta time value that clock.tick returns to increase a timer. In this example you have 0.5 seconds to double click otherwise the timer is reset.
import sys
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
BLACK = pg.Color('black')
FONT = pg.font.Font(None, 32)
def game():
clock = pg.time.Clock()
timer = 0
dt = 0
running = True
while running:
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
if timer == 0: # First mouse click.
timer = 0.001 # Start the timer.
# Click again before 0.5 seconds to double click.
elif timer < 0.5:
print('double click')
timer = 0
# Increase timer after mouse was pressed the first time.
if timer != 0:
timer += dt
# Reset after 0.5 seconds.
if timer >= 0.5:
print('too late')
timer = 0
screen.fill(BLACK)
txt = FONT.render(str(round(timer, 2)), True, (180, 190, 40))
screen.blit(txt, (40, 40))
pg.display.flip()
# dt == time in seconds since last tick.
# / 1000 to convert milliseconds to seconds.
dt = clock.tick(30) / 1000
if __name__ == '__main__':
game()
pg.quit()
sys.exit()
I've never used pygame - but:
Detecting double clicks: at a guess, instead of processing each click immediately, apply a 50ms delay and see if you get another click event in that time. The user probably won't notice the 50ms delay.
Distinguishing between scrollwheel up/down: see the comments on this documentation page. Apparently there are five buttons defined - left, middle, right, scrollwheel-up and scrollwheel-down. That is, you can capture scrollwheel events the same way you're capturing left clicks - you just need to look for SCROLL_UP or similar instead of LEFT.
Look up the documentation to find out exactly what SCROLL_UP is called.
A very simple solution is to define a pygame.time.Clock() to keep track of the time between two consecutive MOUSEBUTTONDOWN event.
Before the main loop define:
dbclock = pygame.time.Clock()
and in the event loop controller:
if event.type == pygame.MOUSEBUTTONDOWN:
if dbclock.tick() < DOUBLECLICKTIME:
print("double click detected!")
where DOUBLECLICKTIME is the maximum time allowed (in milliseconds) between two clicks for them being considered a double click. Define it before the mainloop. For example, to allow a maximum delay of half a second between the two clicks: DOUBLECLICKTIME = 500.
In pygame is possible to create as many pygame.time.Clock() objects are needed. dbclock must be used only for this purpose (I mean, no other calls to dbclock.tick() anywhere in the main loop) or it will mess with the tracking of the time between the two clicks.
For the sake of completeness, let me add also the answer about the scroll wheel, even if other answers already covered it.
The scroll wheel emits MOUSEBUTTONDOWN and MOUSEBUTTONUP events (it's considered a button). I can be identified by the event.button parameter, which is 4 when the wheel is rolled up, and 5 when the wheel is rolled down.
Set a timer when the mouse is pressed the first time to place a userevent on the pygame event queue, and set a variable to 1 to indicate a click. When the second click occurs, check the variable and set the timer event object to off. Check if the userevent comes up on the queue as this means the timer has timed out. see this beautiful answer for more information: Move an object every few seconds in Pygame
Here is the code, replace the double_click() call with your own function call:
def run():
global clock, double_click_event, timer
double_click_event = pygame.USEREVENT + 1
timer = 0
while True:
clock.tick(60)
check_events()
frame.update()
screen.blit(frame, (0,0))
pygame.display.flip()
def check_events():
global dispatcher, double_click_event, timer
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if timer == 0:
pygame.time.set_timer(double_click_event, 500)
timerset = True
else:
if timer == 1:
pygame.time.set_timer(double_click_event, 0)
double_click()
timerset =False
if timerset:
timer = 1
return
else:
timer = 0
return
elif event.type == double_click_event:
# timer timed out
pygame.time.set_timer(double_click_event, 0)
timer = 0
print "evt = dble click"
There doesn't appear to be a native double-click event. I'll guess you'd need to check the time between consecutive MOUSEBUTTONDOWN events.
The mouse wheel will generate pygame.MOUSEBUTTONDOWN events when rolled. The button will be set to 4 when the wheel is rolled up, and to button 5 when the wheel is rolled down

Pygame Overlays

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...

Categories