PyGame code doesn't execute properly when event is executed - python

I am trying to make the most simple pythong code that will respond when a button is pressed on a joystick. I used code from several different examples and I still cannot get it to work. The following code will not dispatch the event when I press the trigger (or any button for that matter)
import pygame
joy = []
def handleJoyEvent(e):
if e.type == pygame.JOYBUTTONDOWN:
str = "Button: %d" % (e.dict['button'])
if (e.dict['button'] == 0):
print ("Pressed!\n")
else:
pass
def joystickControl():
while True:
e = pygame.event.wait()
if (e.type == pygame.JOYBUTTONDOWN):
handleJoyEvent(e)
# main method
def main():
pygame.joystick.init()
pygame.display.init()
for i in range(pygame.joystick.get_count()):
myjoy = pygame.joystick.Joystick(i)
myjoy.init()
joy.append(myjoy)
# run joystick listener loop
joystickControl()
# allow use as a module or standalone script
if __name__ == "__main__":
main()

I assume you've tried leaving off the if and just printing str?
Your joystick might also not be working properly. Does it work in other programs?
If you are using linux you might need to install a joystick driver. For Windows, check the device manager.

Related

play & pause are detecting for alternate tabs from TWS device on Linux using python but the same code worked fine in windows

def on_press(key):
if key == keyboard.Key.media_play_pause: #to identify paly & pause
print("status got changed")
if key == keyboard.Key.media_next: #to identify forword cammand track
print("Next track started")
if key == keyboard.Key.media_previous: #to identify privous cammand track
print("Previous track started")
def stetaupdate ():
global tapdflag
if (tapdflag == 0)
tapdflag = 1
with keyboard.Listener(on_press=on_press) as listener: #thredding
listener.join()
t = threading.Thread(target = stetaupdate)
This code works fine to detect play and pause events in Windows, but I am using the same code in Linux, and it is missing alternate events for play and pause with earbuds, but next and previous events were working fine.

Run simultaneous process inside python class

I'm developping a game using pygame and I want to create a loading screen while the assets are loaded. The loading screen have animations, so loading screen and assets loading should be occurring at the same time.
Consider the code below:
class Game:
def __init__(self):
self.loading_screen()
self.load_assets()
def loading_screen(self):
# do something while load_assets() is running
def load_assets(self):
# load all assets needed
I've tried Process from multiprocessing, but I dont know how to keep loading_screen() running without freezes while load_assets() are running.
Also, I've tried threads, but python doesn't run threads simultaneously, so, in some moment, the loading_screen() will freeze. (This could be wrong, but this was observed in the game)
Some help about this?
Thanks for all
Threads are suitable for this. Nothing runs exactly simultaneously on a multi user system anyway.
import threading
from time import sleep
class Game:
def __init__(self):
self.loading_screen()
def loading_screen(self):
t = threading.Thread(target=self.load_assets)
t.daemon = True
t.start()
while t.isAlive():
sleep(0.1)
print("loading screen")
print ("assets done, ready to proceed now")
def load_assets(self):
i = 0
while i < 10:
print("loading assets")
i += 1
sleep(1)
g = Game()
print("done")
This puts your asset loading to a thread and then enters loading_screen() in the main thread. This just prints messages to demonstrate they both run in parallel.
I can understand what problems the OP is having, a preferred solution is to use multiprocessing rather than multithreading. The given demo from the first answer uses time.sleep for simulating 'heavy loading' in the loading function, but when loading is actually going to take place, it will take a major amount of performance out of the CPU.
So it might happen that your loading animation is playing at 5-10 FPS when you expected 100+ FPS from it.
In this case, it is best to use multiprocessing to achieve the same. From what I have heard, it is a bit complicated to implement it, but it is quite possible. The loading function will then run as a separate process, not a separate thread from the same process.
Here is a small demo program to illustrate a loading screen using multiprocessing:
import multiprocessing
from multiprocessing.connection import Connection
def loading_screen(conn: Connection, stage):
clock = pygame.time.Clock()
fps = 60
c = 0
font = pygame.font.SysFont('consolas', 25)
while True:
screen.fill((0, 0, 50))
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_ESCAPE:
return
if conn.poll(): # check if any object is available to be received or not
# this line is used to prevent waiting until the next object is received
c = conn.recv() # if available, receive the object
if c == 'end':
# process end condition checking
return
pygame.draw.rect(screen, 'white', (50, 50, c, 50))
screen.blit(font.render(f'{c} / {stage * 100} % [stage {stage}]', True, 'white'), (50, 150))
screen.blit(font.render('Check console for status', True, 'white'), (50, 200))
pygame.display.update()
clock.tick(fps)
pygame.display.set_caption(f'Multiprocessing Loading Screen [FPS = {int(clock.get_fps())}]')
def resource_load(conn: Connection, items):
# load resources
# for now it increments a counter and sends it via the connection object
# you can replace it for CPU intensive processes
# and pass the loaded objects to the connection object
c = 0
while True:
c += 1
if c > items:
conn.send('end') # signal end of loading current stage
return # returning will end the process automatically
conn.send(c) # send the counter value via the connection object
if __name__ == '__main__':
import pygame
pygame.init()
screen = pygame.display.set_mode((500, 300)) # initialize display
receiver, sender = multiprocessing.Pipe(duplex=False) # initialize sender and receiver connection objects [unidirectional]
print('Program to demonstrate a simple loading screen using multiprocessing')
print()
print('starting stages...')
multiprocessing.Process(target=resource_load, args=(sender, 100)).start()
print('loading stage 1')
loading_screen(receiver, 1)
multiprocessing.Process(target=resource_load, args=(sender, 200)).start()
print('loading stage 2')
loading_screen(receiver, 2)
multiprocessing.Process(target=resource_load, args=(sender, 300)).start()
print('loading stage 3')
loading_screen(receiver, 3)
input('finished loading all stages... press Enter to exit console') # press Enter inside the console to exit program
EDIT:
I have made a video on this if interested: https://www.youtube.com/watch?v=KWGDgPldPVo

Python one button macro for games

Here is my Python 2.7.13 script that is basically a so called "one key macro" for a video game. Based on information captured from a part of the game screen it presses the right key combinations instead of the player. So the player is spamming the f key and the script presses other keys alongside f.
It is working as is, however at random times (1-5 minutes after start) the script just stops or something similar. I can see in windows task manager that the script is running, however nothing happens when I press the f key.
At the beggining I was wrote the code a little bit more unoptimised and it took a screenshot more than once / keypress. The script "froze" more often back then.
Can this be beacause of too many screenshots? Or did I messed up somewhere?
import pyautogui, pythoncom, pyHook
# Determine if an ability is ready or not
def ready(x,y, im):
if (im.getpixel((x,y)) != (0,0,0)):
return True
else:
return False
def ability1(im):
return (ready(17, 16, im) or ready(35, 16, im))
def ability2(im):
return ready(134, 9, im)
# Listen for keypress
def OnKeyboardEvent(event):
im = pyautogui.screenshot(region=(249, 770, 194, 26))
if (event.KeyID == 70): # Pressed the "f" key
if (ability1(im)):
pyautogui.hotkey('shift','4')
return True
if (ability2(im)):
pyautogui.press('-')
return True
pyautogui.press('1')
return True
# create a hook manager
hm = pyHook.HookManager()
# watch for all mouse events
hm.KeyDown = OnKeyboardEvent
# set the hook
hm.HookKeyboard()
# wait forever
pythoncom.PumpMessages()
If you're running this on live servers, this could be due to increased checks/interference from Warden.
I advise against using such automation on live servers, could lead to a ban if noticed.

Raspberry Pi and pygame.error: video system not initialized

I'm trying to run pygame on my Raspberry Pi Zero W, which has a PS4 controller hooked up to it. I found some code that should work but I get this error when I try to python3 game.py:
Traceback (most recent call last):
File "controller.py", line 74, in
ps4.listen()
File "controller.py", line 52, in listen
for event in pygame.event.get():
pygame.error: video system not initialized
The same code from someone else on Stackoverflow got it to work (at least that's what I assume), but he had a different problem, yet the same code. I did try to run that code instead, but I got the same error. I tried all suggestions I could find from Stackoverflow, but none of them worked. Here's the code I found:
import os
import pprint
import pygame
class PS4Controller(object):
"""Class representing the PS4 controller. Pretty straightforward functionality."""
controller = None
axis_data = None
button_data = None
hat_data = None
def init(self):
"""Initialize the joystick components"""
pygame.init()
pygame.joystick.init()
self.controller = pygame.joystick.Joystick(0)
self.controller.init()
def listen(self):
"""Listen for events to happen"""
if not self.axis_data:
self.axis_data = {}
if not self.button_data:
self.button_data = {}
for i in range(self.controller.get_numbuttons()):
self.button_data[i] = False
if not self.hat_data:
self.hat_data = {}
for i in range(self.controller.get_numhats()):
self.hat_data[i] = (0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.JOYAXISMOTION:
self.axis_data[event.axis] = round(event.value,2)
elif event.type == pygame.JOYBUTTONDOWN:
self.button_data[event.button] = True
elif event.type == pygame.JOYBUTTONUP:
self.button_data[event.button] = False
elif event.type == pygame.JOYHATMOTION:
self.hat_data[event.hat] = event.value
# Insert your code on what you would like to happen for each event here!
# In the current setup, I have the state simply printing out to the screen.
os.system('clear')
pprint.pprint(self.button_data)
pprint.pprint(self.axis_data)
pprint.pprint(self.hat_data)
if __name__ == "__main__":
ps4 = PS4Controller()
ps4.init()
ps4.listen()
Any clue what to do and why it's not working? I run this on Jessie Lite, so there is no desktop or anything like that.
pygame.init fails silently when a module cannot be initialized:
No exceptions will be raised if a module fails, but the total number if successful and failed inits will be returned as a tuple. You can always initialize individual modules manually, but pygame.init()initialize all imported pygame modules is a convenient way to get everything started. The init() functions for individual modules will raise exceptions when they fail.
In your case, it didn't initialize the display. To have it fail loudly, call pygame.display.init explicitly:
import pygame.display
pygame.display.init()

Block pyhook from so-generated keystrokes?

I'm using pyhook and pyhk to map keystrokes on a windows XP machine, and it works fine except for when the keystroke (say, ctrl+z) already exists in the application. In that case, the ctrl+z passes to the application and triggers the action that has been mapped to it.
If you are familiar with autohotkey, note that autohotkey gets around this by defining hotkeys that can optionally be passed to the underlying application. Here's a bit of codes that gets at the idea. Note that I'm trying to keep track of when the ctrl key is down.
import pythoncom, pyHook
control_down = False
def OnKeyboardEvent_up(event):
global control_down
if event.Key=='Lcontrol' or event.Key=='Rcontrol':
control_down=False
return True
def OnKeyboardEvent(event,action=None,key='Z',context=None):
global control_down
if event.Key=='Lcontrol' or event.Key=='Rcontrol':
control_down=True
if control_down and event.Key==key:
print 'do something'
return False
if event.Key=='Pause':
win32gui.PostQuitMessage(1)
return False
# return True to pass the event to other handlers
return True
if __name__ == '__main__':
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.KeyUp = OnKeyboardEvent_up
hm.HookKeyboard() # set the hook
pythoncom.PumpMessages() # wait forever
Any help appreciated.
Thanks!
If you're insterested in Windows only, you can use win API, e.g. via ctypes:
>>> from ctypes import windll
>>> windll.user32.RegisterHotKey(0, -1, 0x0002, 0x5a)
After running these lines of code Ctrl (code = 0x0002) + Z (code = 0x5a) combination doesn't work any more in Python REPL.
So you should better look at what windows are those hotkey registered. More information you can find in MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646309(v=vs.85).aspx
I may totally wrong here, but from my understanding of the pyHook documentation, in order to prevent the key presses from being sent to another application you need to change the return True in def OnKeyboardEvent_up(event): and OnKeyboardEvent(event,action=None,key='Z',context=None): to return False (or anything else other than True.
In windows I noticed that if the code "Do something" takes too long than the key codes are passed to the application even if you return False in the OnKeyboardEvent handler. The solution for me was to pack the code in a thread launched by the key or key combination press. This is sufficiently fast to make the return False work as expected.
def OnKeyboardEvent(event):
if event.key == myKey:
myThred = threading.Thread(target=doSomething_Function).start()
return False

Categories