Problems using pygame with a gamepad - python

Hi i'm using pygame for a school project but it seems to not work correctly.
First of all i try to use it with a gamepad and to make it return me joystick position but even when i use their own program
import pygame
# Define some colors
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
# This is a simple class that will help us print to the screen
# It has nothing to do with the joysticks, just outputing the
# information.
class TextPrint:
def __init__(self):
self.reset()
self.font = pygame.font.Font(None, 20)
def print(self, screen, textString):
textBitmap = self.font.render(textString, True, BLACK)
screen.blit(textBitmap, [self.x, self.y])
self.y += self.line_height
def reset(self):
self.x = 10
self.y = 10
self.line_height = 15
def indent(self):
self.x += 10
def unindent(self):
self.x -= 10
pygame.init()
# Set the width and height of the screen [width,height]
size = [500, 700]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
#Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Initialize the joysticks
pygame.joystick.init()
# Get ready to print
textPrint = TextPrint()
# -------- Main Program Loop -----------
while done==False:
# EVENT PROCESSING STEP
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
# Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
if event.type == pygame.JOYBUTTONDOWN:
print("Joystick button pressed.")
if event.type == pygame.JOYBUTTONUP:
print("Joystick button released.")
# DRAWING STEP
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(WHITE)
textPrint.reset()
# Get count of joysticks
joystick_count = pygame.joystick.get_count()
textPrint.print(screen, "Number of joysticks: {}".format(joystick_count) )
textPrint.indent()
# For each joystick:
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
textPrint.print(screen, "Joystick {}".format(i) )
textPrint.indent()
# Get the name from the OS for the controller/joystick
name = joystick.get_name()
textPrint.print(screen, "Joystick name: {}".format(name) )
# Usually axis run in pairs, up/down for one, and left/right for
# the other.
axes = joystick.get_numaxes()
textPrint.print(screen, "Number of axes: {}".format(axes) )
textPrint.indent()
for i in range( axes ):
axis = joystick.get_axis( i )
textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )
textPrint.unindent()
buttons = joystick.get_numbuttons()
textPrint.print(screen, "Number of buttons: {}".format(buttons) )
textPrint.indent()
for i in range( buttons ):
button = joystick.get_button( i )
textPrint.print(screen, "Button {:>2} value: {}".format(i,button) )
textPrint.unindent()
# Hat switch. All or nothing for direction, not like joysticks.
# Value comes back in an array.
hats = joystick.get_numhats()
textPrint.print(screen, "Number of hats: {}".format(hats) )
textPrint.indent()
for i in range( hats ):
hat = joystick.get_hat( i )
textPrint.print(screen, "Hat {} value: {}".format(i, str(hat)) )
textPrint.unindent()
textPrint.unindent()
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 20 frames per second
clock.tick(20)
# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit ()
It detect the gamepad but doesn't return me anything buttons/hats/joystick all the value stays at 0.
Even when i try it with my keyboard it detect the device but always return me 0 even when keys are pressed with pygame.key.get_pressed()
The problem is that i dont have a gamepad to experiment most of the time, so i tried with my keyboard to detect key which are pressed but i doesn't work either. My program was :
import pygame
import time
pygame.init()
while True:
print(pygame.key.get_pressed())
time.sleep(3)
But it doesn't matter which keys are pressed the value remains to 0 for all of them

Try going through and initializing all the joysticks only once outside of the loop and then remove the code that initializes them that's currently inside the loop. It may be that when you do that it clears-out some sort of input buffer giving you zeroed-out values. But without having a gamepad on hand to test this theory, this is just my guess.

Related

PyGame - RaspberryPi 3b+ with a ps3 controller

I am trying to use pygame with the raspberry pi to use a PlayStation 3 controller as an input for a car.
I have tested the controller with a demo code, and everything works fine. Then when I try to use it in my program, it reads 0.0 as the input, when the joysticks are moved. attached is my current code:
import pygame
class controller:
def __init__(self):
pygame.init()
pygame.joystick.init()
global joystick
joystick = pygame.joystick.Joystick(0)
joystick.init()
def get_value(self, axis):
value = joystick.get_axis(axis)
return value
control = controller()
val = control.get_value(0)
while True:
print(val)
I am aware that this test is only for axis 0, but the output is still 0.0 for all axes.
Below, i have attached the demo code, where all the values are properly read.
import pygame, sys, time #Imports Modules
from pygame.locals import *
pygame.init()#Initializes Pygame
pygame.joystick.init()
joystick = pygame.joystick.Joystick(0)
joystick.init()#Initializes Joystick
# get count of joysticks=1, axes=27, buttons=19 for DualShock 3
joystick_count = pygame.joystick.get_count()
print("joystick_count")
print(joystick_count)
print("--------------")
numaxes = joystick.get_numaxes()
print("numaxes")
print(numaxes)
print("--------------")
numbuttons = joystick.get_numbuttons()
print("numbuttons")
print(numbuttons)
print("--------------")
loopQuit = False
while loopQuit == False:
# test joystick axes and prints values
outstr = ""
for i in range(0,4):
axis = joystick.get_axis(i)
outstr = outstr + str(i) + ":" + str(axis) + "|"
print(outstr)
# test controller buttons
outstr = ""
for i in range(0,numbuttons):
button = joystick.get_button(i)
outstr = outstr + str(i) + ":" + str(button) + "|"
print(outstr)
for event in pygame.event.get():
if event.type == QUIT:
loopQuit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
loopQuit = True
# Returns Joystick Button Motion
if event.type == pygame.JOYBUTTONDOWN:
print("joy button down")
if event.type == pygame.JOYBUTTONUP:
print("joy button up")
if event.type == pygame.JOYBALLMOTION:
print("joy ball motion")
# axis motion is movement of controller
# dominates events when used
if event.type == pygame.JOYAXISMOTION:
# print("joy axis motion")
time.sleep(0.01)
pygame.quit()
sys.exit()
any feedback will be much appreciated.
The code is losing the reference to the initialised joystick. It needs to maintain an internal link to it. Note the use of self. in the class below. This keeps the reference inside the class, making "self.joystick" a member variable of the class. Python classes need the self. notation (unlike lots of (all?) other object orientated languages). While editing I changed some of the names to match the Python PEP-8 style guide, I hope that's OK ;)
class Controller:
def __init__( self, joy_index=0 ):
pygame.joystick.init() # is it OK to keep calling this?
self.joystick = pygame.joystick.Joystick( joy_index )
self.joystick.init()
def getAxisValue( self, axis ):
value = self.joystick.get_axis( axis )
return value
Maybe you left the extra code out of the question, but a PyGame program without an event loop will eventually lock up.
import pygame
# Window size
WINDOW_WIDTH = 300
WINDOW_HEIGHT = 300
class Controller:
""" Class to interface with a Joystick """
def __init__( self, joy_index=0 ):
pygame.joystick.init()
self.joystick = pygame.joystick.Joystick( joy_index )
self.joystick.init()
def getAxisValue( self, axis ):
value = self.joystick.get_axis( axis )
return value
### initialisation
pygame.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
clock = pygame.time.Clock()
pygame.display.set_caption( "Any Joy?" )
# Talk to the Joystick
control = controller()
# Main loop
done = False
while not done:
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Query the Joystick
val = control.getAxisValue( 0 )
print( "Joystick Axis: " + str( val ) )
# Update the window, but not more than 60fps
window.fill( (0,0,0) )
pygame.display.flip()
clock.tick_busy_loop(60)
pygame.quit()

why can't my code detect button down on a joystick

I am using the pygame.joystick method to use joysticks in my game, however, my code can only detect the model of the joystick, and cannot detect what buttons are down.
import pygame
# Define some colors
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
# This is a simple class that will help us print to the screen
# It has nothing to do with the joysticks, just outputting the
# information.
class TextPrint:
def __init__(self):
self.reset()
self.font = pygame.font.Font(None, 20)
def print(self, screen, textString):
textBitmap = self.font.render(textString, True, BLACK)
screen.blit(textBitmap, [self.x, self.y])
self.y += self.line_height
def reset(self):
self.x = 10
self.y = 10
self.line_height = 15
def indent(self):
self.x += 10
def unindent(self):
self.x -= 10
pygame.init()
# Set the width and height of the screen [width,height]
size = [500, 700]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
#Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Initialize the joysticks
pygame.joystick.init()
# Get ready to print
textPrint = TextPrint()
# -------- Main Program Loop -----------
while done==False:
# EVENT PROCESSING STEP
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
# Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
if event.type == pygame.JOYBUTTONDOWN:
print("Joystick button pressed.")
if event.type == pygame.JOYBUTTONUP:
print("Joystick button released.")
print('EVENT')
# DRAWING STEP
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(WHITE)
textPrint.reset()
# Get count of joysticks
joystick_count = pygame.joystick.get_count()
textPrint.print(screen, "Number of joysticks: {}".format(joystick_count) )
textPrint.indent()
# For each joystick:
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
textPrint.print(screen, "Joystick {}".format(i) )
textPrint.indent()
# Get the name from the OS for the controller/joystick
name = joystick.get_name()
textPrint.print(screen, "Joystick name: {}".format(name) )
# Usually axis run in pairs, up/down for one, and left/right for
# the other.
axes = joystick.get_numaxes()
textPrint.print(screen, "Number of axes: {}".format(axes) )
textPrint.indent()
for i in range( axes ):
axis = joystick.get_axis( i )
textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )
textPrint.unindent()
buttons = joystick.get_numbuttons()
textPrint.print(screen, "Number of buttons: {}".format(buttons) )
textPrint.indent()
for i in range( buttons ):
button = joystick.get_button( i )
textPrint.print(screen, "Button {:>2} value: {}".format(i,button) )
textPrint.unindent()
# Hat switch. All or nothing for direction, not like joysticks.
# Value comes back in an array.
hats = joystick.get_numhats()
textPrint.print(screen, "Number of hats: {}".format(hats) )
textPrint.indent()
for i in range( hats ):
hat = joystick.get_hat( i )
textPrint.print(screen, "Hat {} value: {}".format(i, str(hat)) )
textPrint.unindent()
textPrint.unindent()
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 20 frames per second
clock.tick(20)
# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit ()
Here is the code I used to test my joystick: here
Sorry, I had to make it a drive document.
The code is initialising the joysticks every update-loop. It's only necessary to initialise it once. I think it's best to move all your initialisation code into a single function. I suspect the constant re-initialisation of the joystick is interfering its proper functioning.
def initialiseJoysticks():
"""Initialise all joysticks, returning a list of pygame.joystick.Joystick"""
joysticks = [] # for returning
# Initialise the Joystick sub-module
pygame.joystick.init()
# Get count of joysticks
joystick_count = pygame.joystick.get_count()
# For each joystick:
for i in range( joystick_count ):
joystick = pygame.joystick.Joystick( i )
joystick.init()
# NOTE: Some examples discard joysticks where the button-count
# is zero. Maybe this is a common problem.
joysticks.append( joystick )
# TODO: Print all the statistics about the joysticks
if ( len( joysticks ) == 0 ):
print( "No joysticks found" )
else:
for i,joystk in enumerate( joysticks ):
print("Joystick %d is named [%s]" % ( i, joystk.get_name() ) )
# etc.
return joysticks
Then in your main code, call this initialiser once, outside the loop.
done = False
all_joysticks = initialiseJoysticks()
# -------- Main Program Loop -----------
while not done:
# EVENT PROCESSING STEP
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
# Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
elif event.type == pygame.JOYAXISMOTION:
axis = [ 'X', 'Y' ]
print( "joystick: %d, movement: %4.2f in the %s-axis" % ( event.joy, event.value, axis[event.axis] ) )
elif event.type == pygame.JOYBUTTONDOWN:
#print( "Joystick button pressed." )
pass
elif event.type == pygame.JOYBUTTONUP:
print( 'joystick: %d, button: %d' % ( event.joy, event.button ) )
# DRAWING STEP
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill( WHITE )
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 20 frames per second
clock.tick( 20 )
# exit
pygame.quit()

drawing the moving objects all at once instead of drawing one then moving onto the next one

this code draws the basics of my orbit simulator but as soon as it has done one orbit with a planet it moves onto the next one in the list, how do i make it so it does all of the different orbits at the same time.
#import the library
import pygame,math
#classes
class planet():
def __init__(self,name,colour,distance,eccentricity,radius,x,y,angle):
self.screen = screen
self.name = name
self.colour = colour
self.distance = distance
self.eccentricity = eccentricity
self.radius = radius
self.x = x
self.y = y
self.angle = angle
def draw(self):
pygame.draw.circle(self.screen,self.colour,(self.x,self.y),self.radius,)
def draw_orbit(screen,colour,x,y,r):
screen.fill(Black)
int(r)
pygame.draw.circle(screen,colour,[x,y],r)
pygame.display.flip
orbit()
also i can make it so there is only one item in the list but it never does more than one rotation so, if i add planet.angle+360 instead of just the 360 it does the first one but never moves of it.
def orbit(planet):
while planet.angle <= 360:
a = planet.distance*(1.496*10**8)
e = planet.eccentricity
angle_radians = math.radians(planet.angle)
r = a*(1-(e*math.cos(angle_radians)))
planet.x = int(math.cos(angle_radians)*r/10**6)
planet.y = int(math.sin(angle_radians)*r/10**6)
planet.angle +=1
## print(planet.angle)
## print(planet.x,planet.y)
planet.x +=800
planet.y +=400
screen.fill(Black)
pygame.draw.circle(screen,Red,center,10)
## pygame.draw.circle(screen,White,center,r,1)
pygame.draw.circle(screen,planet.colour,[planet.x,planet.y],planet.radius)
pygame.display.flip()
#define colours
Black = (0,0,0)
White = (255,255,255)
Green = (0,255,0)
Red = (255,0,0)
Blue = (0,0,255)
#initialise the engine
pygame.init()
#Opening a window
size = (1600,800)
screen = pygame.display.set_mode(size)
center = [800,400]
planets =[]
planet_draw =[]
# screen,name,colour,distance,eccentricity,radius,x,y
planet_list = [
['Mercury',White,0.387,0.2056,5,0,0,120],
['Venus',Green,0.723,0.0068,10,0,0,60],
['Earth',Blue,1,0.0167,10,0,0,0],
['Mars',White,1.524,0.0934,10,0,0,150],
['Jupiter',Green,5.203,0.0484,30,0,0,330],
## [screen,'Saturn',Red,9.537,0.0542,10,0,0],
## [screen,'Uranus',Red,19.191,0.0472,10,0,0],
## [screen,'Neptune',Green,30.069,0.0086,10,0,0]
]
for i in planet_list:
planet_draw.append(planet(i[0],i[1],i[2],i[3],i[4],i[5],i[6],i[7]))
#set window title
pygame.display.set_caption("Orbit Simulator")
#loop unti the user clicks the close button
done = False
#used to manage how fast the screen updates
clock = pygame.time.Clock()
#------ Main program Loop ------
while not done:
#--- Main event loop
for event in pygame.event.get(): #user did something
if event.type == pygame.QUIT: #if user clicked close
done = True #flag that we are done and exit the loop
#------ Game logic should go here ------
for planet in planet_draw:
orbit(planet)
#------ Drawing code should go here -------
#first, clear the screen to white. Don't put other drawing commands above this or they will be erased with this command.
#update the screen
pygame.display.flip()
#------ Limit to 60 frames per second ------
clock.tick(60)
#------ When the loop ends, quit ------
pygame.quit()
The problem is your orbit() function. It's clearing and repainting the entire screen, each time a new planet is drawn.
The function only needs to draw the planet, the clearing of the screen and flipping should be done elsewhere.
Some pseudocode ~
Update Orbits (just the positions)
Clear screen
Draw N planets
Page flip
Wait for timer tick
Giving Code:
def orbit(planet):
while planet.angle <= 360:
a = planet.distance*(1.496*10**8)
e = planet.eccentricity
angle_radians = math.radians(planet.angle)
r = a*(1-(e*math.cos(angle_radians)))
planet.x = int(math.cos(angle_radians)*r/10**6)
planet.y = int(math.sin(angle_radians)*r/10**6)
planet.angle +=1
# Note: Don't paint, Don't offset for screen size
while not done:
#--- Main event loop
for event in pygame.event.get(): #user did something
if event.type == pygame.QUIT: #if user clicked close
done = True #flag that we are done and exit the loop
#------ Game logic should go here ------
# ---- move the planets -----
for planet in planet_draw:
orbit(planet)
# ------ Re-paint the current state of the screen ------
screen.fill(Black)
for planet in planet_draw:
planet.draw()
pygame.display.flip()
#------ Limit to 60 frames per second ------
clock.tick(60)
It might work out easier to modify your planet object such that given the time-tick (or some counter), it re-calculates the orbit co-ordinates at this time. This could give you code like:
while ( True ):
frame_counter = pygame.get_ticks()
screen.fill(Black)
for planet in planet_draw:
planet.calcuateOrbitAt( frame_counter )
planet.draw()
pygame.display.flip()
And it handles jumping orbits at really slow frame rates.

Pygame Xbox One Controller

I am trying to run some code that will allow the user to control with an Xbox Controller. I have it working with the Xbox 360 controller using Pygame. Then when I try to use the Xbox one controller and it is able to read the as "connected" but it doesn't read the actual button presses.
I tried running the joystick analyzer found on the Pygame website and it shows it connected again but no button input is taken.
The code for this can be found at the bottom of this documentation page:
https://www.pygame.org/docs/ref/joystick.html
import pygame
# Define some colors.
BLACK = pygame.Color('black')
WHITE = pygame.Color('white')
# This is a simple class that will help us print to the screen.
# It has nothing to do with the joysticks, just outputting the
# information.
class TextPrint(object):
def __init__(self):
self.reset()
self.font = pygame.font.Font(None, 20)
def tprint(self, screen, textString):
textBitmap = self.font.render(textString, True, BLACK)
screen.blit(textBitmap, (self.x, self.y))
self.y += self.line_height
def reset(self):
self.x = 10
self.y = 10
self.line_height = 15
def indent(self):
self.x += 10
def unindent(self):
self.x -= 10
pygame.init()
# Set the width and height of the screen (width, height).
screen = pygame.display.set_mode((500, 700))
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates.
clock = pygame.time.Clock()
# Initialize the joysticks.
pygame.joystick.init()
# Get ready to print.
textPrint = TextPrint()
# -------- Main Program Loop -----------
while not done:
#
# EVENT PROCESSING STEP
#
# Possible joystick actions: JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN,
# JOYBUTTONUP, JOYHATMOTION
for event in pygame.event.get(): # User did something.
if event.type == pygame.QUIT: # If user clicked close.
done = True # Flag that we are done so we exit this loop.
elif event.type == pygame.JOYBUTTONDOWN:
print("Joystick button pressed.")
elif event.type == pygame.JOYBUTTONUP:
print("Joystick button released.")
#
# DRAWING STEP
#
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(WHITE)
textPrint.reset()
# Get count of joysticks.
joystick_count = pygame.joystick.get_count()
textPrint.tprint(screen, "Number of joysticks: {}".format(joystick_count))
textPrint.indent()
# For each joystick:
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
try:
jid = joystick.get_instance_id()
except AttributeError:
# get_instance_id() is an SDL2 method
jid = joystick.get_id()
textPrint.tprint(screen, "Joystick {}".format(jid))
textPrint.indent()
# Get the name from the OS for the controller/joystick.
name = joystick.get_name()
textPrint.tprint(screen, "Joystick name: {}".format(name))
try:
guid = joystick.get_guid()
except AttributeError:
# get_guid() is an SDL2 method
pass
else:
textPrint.tprint(screen, "GUID: {}".format(guid))
# Usually axis run in pairs, up/down for one, and left/right for
# the other.
axes = joystick.get_numaxes()
textPrint.tprint(screen, "Number of axes: {}".format(axes))
textPrint.indent()
for i in range(axes):
axis = joystick.get_axis(i)
textPrint.tprint(screen, "Axis {} value: {:>6.3f}".format(i, axis))
textPrint.unindent()
buttons = joystick.get_numbuttons()
textPrint.tprint(screen, "Number of buttons: {}".format(buttons))
textPrint.indent()
for i in range(buttons):
button = joystick.get_button(i)
textPrint.tprint(screen,
"Button {:>2} value: {}".format(i, button))
textPrint.unindent()
hats = joystick.get_numhats()
textPrint.tprint(screen, "Number of hats: {}".format(hats))
textPrint.indent()
# Hat position. All or nothing for direction, not a float like
# get_axis(). Position is a tuple of int values (x, y).
for i in range(hats):
hat = joystick.get_hat(i)
textPrint.tprint(screen, "Hat {} value: {}".format(i, str(hat)))
textPrint.unindent()
textPrint.unindent()
#
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
#
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 20 frames per second.
clock.tick(20)
# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit()
Does anyone have any insight into why this is?
Bluetooth may not be enabled yet try enabling it or checking the controllers batteries!
I have tried this same script with an Xbox One Series 2 Controller and can confirm that it works flawlessly. I connected the controller to the PC with the charging cable, not wirelessly (because I have an Xbox in the same room).
You should try the same first and be able to open the Xbox Game Bar by holding down the button, otherwise check your Xbox settings on the PC and update your drivers from the device manager (while wired).
Also, make sure that you have the last Pygame version, I tried with 2.1.2 on Windows 10.
Hope this give you a hint.
try running a controller testing tool if it doesn't work there then it is probably a problem with the controller also try reinstalling pygame and checking if you have drivers correctly installed

Python 3: cx_Freeze freezes a working program into a NOT working program

Yes, it looks like it's a duplicate question (already asked here), however, I have a problem with a Pygame app, not a Console app. It works fine when launching it from IDLE or Python Code Executer (just double-clicking the file :) ), but crashes with no tracebacks. It just keeps crashing (looks like it crashes on the drawing step, I don't know) every time I launch the EXE. The full code is here:
import pygame
# Define some colors
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
# This is a simple class that will help us print to the screen
# It has nothing to do with the joysticks, just outputing the
# information.
class TextPrint:
def __init__(self):
self.reset()
self.font = pygame.font.Font(None, 20)
def print(self, screen, textString):
textBitmap = self.font.render(textString, True, BLACK)
screen.blit(textBitmap, [self.x, self.y])
self.y += self.line_height
def reset(self):
self.x = 10
self.y = 10
self.line_height = 15
def indent(self):
self.x += 10
def unindent(self):
self.x -= 10
pygame.init()
# Set the width and height of the screen [width,height]
size = [500, 700]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("JoyMonitor V.1.1")
#pygame.display.set_icon("icon.ico")
# Get ready to print
textPrint = TextPrint()
#Loop until the user clicks the close button.
nondone = True
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Initialize the joysticks
pygame.joystick.init()
# -------- Main Program Loop -----------
while nondone:
# EVENT PROCESSING STEP
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
nondone = False # Flag that we are done so we exit this loop
# Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION
if event.type == pygame.JOYBUTTONDOWN:
print("Joystick button pressed.")
if event.type == pygame.JOYBUTTONUP:
print("Joystick button released.")
# DRAWING STEP
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(WHITE)
textPrint.reset()
textPrint.print(screen, "JoyMonitor: Joysticks, Gamepads & Steering Wheels")
textPrint.print(screen, "Connecting/disconnecting devices requires restart!")
# Get count of joysticks
joystick_count = pygame.joystick.get_count()
textPrint.print(screen, "Number of game input devices: {}".format(joystick_count) )
textPrint.indent()
# For each joystick:
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
textPrint.print(screen, "Device {}".format(i) )
textPrint.indent()
# Get the name from the OS for the controller/joystick
name = joystick.get_name()
textPrint.print(screen, "Device name: {}".format(name) )
# Usually axis run in pairs, up/down for one, and left/right for
# the other.
axes = joystick.get_numaxes()
textPrint.print(screen, "Number of axes: {}".format(axes) )
textPrint.indent()
for i in range( axes ):
axis = joystick.get_axis( i )
textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )
textPrint.unindent()
buttons = joystick.get_numbuttons()
textPrint.print(screen, "Number of buttons: {}".format(buttons) )
textPrint.indent()
for i in range( buttons ):
button = joystick.get_button( i )
textPrint.print(screen, "Button {:>2} value: {}".format(i,button) )
textPrint.unindent()
# Hat switch. All or nothing for direction, not like joysticks.
# Value comes back in an array.
hats = joystick.get_numhats()
textPrint.print(screen, "Number of POVs: {}".format(hats) )
textPrint.indent()
for i in range( hats ):
hat = joystick.get_hat( i )
textPrint.print(screen, "POV {} value: {}".format(i, str(hat)) )
textPrint.unindent()
balls = joystick.get_numballs()
textPrint.print(screen, "Number of trackballs: {}".format(balls) )
textPrint.indent()
for i in range( balls ):
ball = joystick.get_ball( i )
textPrint.print(screen, "Trackball {} value: {}".format(i, str(ball)) )
textPrint.unindent()
textPrint.unindent()
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit ()
According to Making an .exe for pygame with cx-freeze, you need to use a system font if you're not going to include the default font of pygame.font.Font(None,20)
One solution is to replace:
self.font = pygame.font.Font(None, 20)
to:
self.font = pygame.font.SysFont("arial", 20) #or you can use any other system font
Or, you can include the ttf file of the default Font font in your setup.py, which you can get using pygame.font.get_defaultfont()

Categories