I've seen other solutions to this problem say that you either need to call the pygame.event.pump() or initialize the joystick outside of the while loop. However, even with these solutions, I'm getting 0's for the joystick axes values.
If I uncomment just the pygame.display.set_mode((1, 1)), then the code works as expected, and the values are output to the console.
Is there a way to still get the axes values without having to create the extra window?
Also, I am running python 3.6 on Windows 10.
import pygame
FRAMES_PER_SECOND = 20
pygame.init()
pygame.joystick.init()
# pygame.display.set_mode((1,1))
# Used to manage how fast the screen updates.
clock = pygame.time.Clock()
xboxController = pygame.joystick.Joystick(0)
xboxController.init()
# Loop until the user presses menu button
done = False
print('Found controller\nStarting loop...')
while not done:
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.JOYBUTTONDOWN and event.button == 7:
print(f'Exiting controller loop')
done = True
for i in range(xboxController.get_numaxes()):
print(f'Axis {i}: {xboxController.get_axis(i)}')
# pygame.display.flip()
clock.tick(FRAMES_PER_SECOND)
Output:
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Found controller
Starting loop...
Axis 0: 0.0
Axis 1: 0.0
Axis 2: 0.0
Axis 3: 0.0
Axis 4: 0.0
.
.
.
I would probably move away from Pygame unless you need the whole underlaying GL features, as the library is meant for 2D/3D game development. Although it might be possible to use it for these purposes, issues down the line is more or less unavoidable. A perhaps simpler approach would be to go with python's input library, which can handle gamepads (joysticks).
from inputs import get_gamepad
while True:
events = get_gamepad()
for event in events:
if event.ev_type == 'Absolute':
if event.code == 'ABS_X':
print(f'Left joystick x: {event.state}')
elif event.code == 'ABS_Y':
print(f'Left joystick y: {event.state}')
elif event.code == 'ABS_RX':
print(f'Right joystick x: {event.state}')
elif event.code == 'ABS_RY':
print(f'Right joystick y: {event.state}')
Alright found the answer 5 minutes after I posted this. The problem was that I was using pygame 1.9.6 instead of 2.0.0.dev8. After updating, I'm getting the console output without the display window.
Related
I'm currently working on a game in Pygame, and I've been trying to think of a way to have a music track that loops at a point that isn't the beginning of the track. So essentially, it plays an introduction, then moves onto another section that repeats without revisiting that introduction.
I've thought of a couple of ways that almost worked, but they have problems.
The first was to have two separate audio files for the introduction and the looping section, then to use pygame.music.set_endevent(), and just load the second audio file once the first is finished. This left quite an obvious gap and click though.
The second was to also use two audio files but to queue in the second as the first is loaded. The problem with this is that it seems like you can't change the play mode from 0 (play once) to -1 (looping) for the new queued track...
I feel like there has to be a way of doing this, I'd really appreciate any help.
In the example below, PyGame's sound channels are used for multiple tracks. Here an event is created, such that after 1500 milliseconds, a second sound in played (at the same time as the looping track).
For your suggested use-case, the code could play the intro-music at start, but also set an event-timer for /intro-length/ milliseconds in the future. When that timer-event is received, the looping-part of your music could play continuously, as the intro should have just stopped. Using multiple channels, it should not matter if the two sounds overlap by a few milliseconds (of silence/fadeout), as long as the user does not perceive it of course! Maybe it will be tricky to get the timing 100% correct on vastly different systems, but it should get you close.
Note that in the example, the sounds are already initialised into PyGame Sound objects, I expect this would cut-down on startup latency.
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
DARK_BLUE = ( 3, 5, 54)
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
pygame.display.set_caption("Multi Sound with Timer")
### sound
# create separate Channel objects for simultaneous playback
channel1 = pygame.mixer.Channel(0) # argument must be int
channel2 = pygame.mixer.Channel(1)
# Rain sound from: https://www.freesoundslibrary.com/sound-of-rain-falling-mp3/ (CC BY 4.0)
rain_sound = pygame.mixer.Sound( 'rain-falling.ogg' )
channel1.play( rain_sound, -1 ) # loop the rain sound forever
# Car Horn sound from: https://www.freesoundslibrary.com/car-horn-sound-effect/ (CC BY 4.0)
horn_sound = pygame.mixer.Sound( 'car-horn.ogg' )
# Create a timer, which will (after the delay-time) post an event to the main loop
pygame.time.set_timer( pygame.USEREVENT, 1500 ) # play the horn in 1500 milliseconds
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.USEREVENT ):
# Timer expired, play the sound
channel2.play( horn_sound )
# Movement keys
#keys = pygame.key.get_pressed()
#if ( keys[pygame.K_UP] ):
# print("up")
# Update the window, but not more than 60fps
window.fill( DARK_BLUE )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(60)
pygame.quit()
The built in pygame function: pygame.mouse.get_pos() returns the X and Y coordinates in a tuple when I am moving the mouse, but if I stop moving the mouse, the function returns None.
But, I want the computer to keep returning the current coordinates over and over again.
How do I do that?
What I am trying to do is write a function that makes it easier to get the mouse coordinates.
I want to be able to do following:
Xpos, Ypos = mouse_pos()
What I have right now is:
def mouse_pos():
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if pos != None:
x=a[0]
y=a[1]
return x, y
else:
#here I want code that says: if pos is NoneType, x=(latest x-value) and y=(latest y-value)
So, how can i get pygame to not return None (and return current coordinates) even if mouse is stationary?
Thanks in advance!
You are using the API wrong, the fact that there are events doesn't mean any of them is a mouse event, and pygame fills the mouse position on mouse events.
The function get_pos shouldn't be calle to find out where the mouse is but rather to update your knowledge when it is changed.
The correct way to keep track of mouse position will be to have the following in you main game loop:
mouse_position = (0, 0) # initial value
while game_is_running: # your main game loop
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
mouse_position = pygame.mouse.get_pos()
Remove your function. Just use pygame.mouse.get_pos().
It's not pygame.mouse.get_pos() that returns None, it's your own function.
It will only set pos if there's an event in the event queue. If not, pos will be None.
But even worse is that every time you call your mouse_pos function, the event queue will be cleared. That will lead to events getting lost.
Pygame has a constant for example for the exclamation mark, !. The constant is called pygame.K_EXCLAIM. However, in my standard US keyboard layout, the exclamation mark is produced by pressing shift and the key 1. Consider the following two snippets:
# snippet 1
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_EXCLAIM:
print('!')
elif event.key == pygame.K_1:
print('1')
# snippet 2
pressed = pygame.key.get_pressed()
if pressed[pygame.K_EXCLAIM]:
print('!')
if pressed[pygame.K_1]:
print('1')
In both cases, when I press Shift+1, which would produce a exclamation mark, pygame does not recognize the combination and simply says the shift key and the 1 key are pressed, printing the value "1". This concerns me a little bit because while I can hardcode such combinations, they are dependent of the keyboard's layout.
Can I make pygame produce combinations constants (such as K_EXCLAIM or K_AMPERSAND) in a keyboard layout-aware manner?
What you want is the event.unicode attribute:
if event.unicode == "!":
print("!")
Lets say I have a list called my_list and a function called my_function and my_function appends items to my_list based on which portion of the surface gameDisplay was clicked on. However whenever you hold down the mouse for more than one frame, it appends more than one of that item to my_list. This is not the result I am going for. I was wondering if there was a way you could do this without appending more than one of each item to my_list
Thanks for your help
You didn't show code but I guess you use pygame.mouse.get_pressed() which gives True all the time when you keep button pressed. And this can be your problem.
You can do one of two things:
use event.MOUSEBUTTONDOWN which is created only once - when button change state from not-pressed into pressed.
Or:
use extra variable which will remeber pygame.mouse.get_pressed() from previous frame. And then compare if now button is pressed but in previous frame was not-pressed then add element to list.
EDIT: old code from different question which use event.MOUSEBUTTONDOWN to change color.
#!/usr/bin/env python
# http://stackoverflow.com/questions/33856739/how-to-cycle-3-images-on-a-rect-button
import pygame
# - init -
pygame.init()
screen = pygame.display.set_mode((300,200))
# - objects -
# create three images with different colors
images = [
pygame.Surface((100,100)),
pygame.Surface((100,100)),
pygame.Surface((100,100)),
]
images[0].fill((255,0,0))
images[1].fill((0,255,0))
images[2].fill((0,0,255))
images_rect = images[0].get_rect()
# choose first image
index = 0
# - mainloop -
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and images_rect.collidepoint(event.pos):
# cycle index
index = (index+1) % 3
# - draws -
screen.blit(images[index], images_rect)
pygame.display.flip()
# - end -
pygame.quit()
GitHub: furas/python-examples/pygame/button-click-cycle-color
I'm writing a code that reads the value of a joystick axis and then sends this value to an arduino. It works, however I do not want it constantly print 0 to the LXTerminal when nothing is being pressed.
The code prints: SDL_JoystickGetAxis value:0: repeatably when the axis is not being pressed.
It then prints:
SDL_JoystickGetAxis value:-32768:
SDL_JoystickGetAxis value:0:
SDL_JoystickGetAxis value:-32768:
The left drive is
-1.0
Repeatably when the axis is being pulled all the way down, or a number between -1 and 1 depending where the joystick is.
I only want it to print The left drive is <leftDrive> when the left axis is being pressed, and then nothing when it is not. How do I achieve this?
Here is my code:
import pygame
pygame.init()
pygame.joystick.init()
joystick = pygame.joystick.Joystick(0)
joystick.init()
leftDrive = 0
rightDrive = 0
while True:
try:
pygame.event.pump()
joyCheckLeft = joystick.get_axis(1)
joyCheckRight = joystick.get_axis(2)
if joyCheckLeft != 0:
pygame.event.pump()
leftDrive = joystick.get_axis(axisLeftDrive)
print 'The left drive is'
print leftDrive
writeNumber(int(2+(leftDrive*-10)))
pygame.event.pump()
time.sleep(0.1)
except KeyboardInterrupt:
quit()
Note: The code doesn't work without pygame.event.pump(). This is needed so that "get_axis()" actually returns the value of the axis.
This is related to this question Disable the Pygame console Output and the thread: http://archives.seul.org/pygame/users/Aug-2009/msg00110.html This seems to have been fixed in the bitbucket source https://bitbucket.org/pygame/pygame/downloads you could try downloading the version from there.