Reputation: 41
I'm learning to program Python by making a game using Kivy, but I'm having trouble implementing sounds for different events (eg. shield_on.play() when shield-item is picked up.) because the game update loop appears to halt for a short while until the sound has finished playing. I've made a short version of the relevant code here...
shield_on = soundLoader('shield_on.wav')
class game(Widget):
#...loads of other stuff...
def update_loop(foo):
self.player_one.update()
self.player_two.update()
self.player_item_collision_detector()
if "game_file_says_player_one's_shields_are on":
self.player_one.drawShield()
shield_on.play()
Presently, I simply load my sounds globally. I know that's bad, but they're also my only globals. Then there is a Widget containing the game itself which has a lot of stuff and an update loop... it updates the player positions, checks for collisions with items - and on collision the item, here the shield, is registered as "on" in a game-file. Then the update-loop checks that game-file for the status of "shields", sees they are on and should play the sound.
The sound plays just fine, however the loop appears to halt until its finished playing the sound. Essentially, the players stop for a microsecond. How can I make the update loop not wait for the sounds to finish...?
Upvotes: 1
Views: 828
Reputation: 41
The cause of the problem is explained here: github.com/kivy/kivy/issues/2728 Essentially, the SoundLoader.load() function should return the class most suited to play the soundfile you pass it. It ends up not doing exactly that, and as I understand it the fault doesn't lie with Kivy but with GStreamer. This causes a significant temporary framerate drop for the app - regardless of where you call the .play() method.
Two possible solutions to this is offerend in the github-thread; 1) Either ensure a suitable class is returned directly - using SoundSDL2 2) Use PyGame instead
I implemented the latter, and it works fine.
# Initialize files and PyGame mixer:
import pygame
pygame.init()
pygame.mixer.pre_init(44100, 16, 2, 4096) # Frequency, size, channels and buffersize
shield_on = pygame.mixer.Sound("shield_on.wav")
class game(Widget):
...
def update_loop(self):
...
if "game_file_says_shield_is_on":
shield_on.play()
Hopefully this is of some help to others!
I'd like to say the above answer was useful as well because it enabled me to identify the real problem. I'd give it a vote, but I don't have the reputation here yet.
Upvotes: 3
Reputation: 1714
The sound plays just fine, however the loop appears to halt until its finished playing the sound.
Multithreading could be your solution here.
import threading
...
class foo(something):
...
def update_loop(self,foo):
...
if "game_file_says_player_one's_shields_are on":
#starting new thread, which will run parallely with the main loop
threading.Thread(target=self.first_thread).start()
def first_thread(self):
self.player_one.drawShield()
shield_on.play()
Upvotes: 0