Check whether a song has finished playing in pygame - python

Is there any way to tell whether a song has finished playing in pygame?
Here's the code:
from tkinter import *
import pygame
root = Tk()
pygame.init()
def play():
pygame.mixer.music.load("test.ogg")
pygame.mixer.music.play(loops = 0)
def pause():
global paused
if paused == False:
pygame.mixer.music.pause()
paused = True
elif paused:
pygame.mixer.music.unpause()
paused = False
def check_if_finished():
if pygame.mixer.music.get_busy():
print("Song is not finished")
else:
print("Song is finshed")
paused = False
play_button = Button(root , text = "Play Song" , command = play)
play_button.grid(row = 0 , column = 0)
pause_button = Button(root , text = "Pause Song" , command = pause)
pause_button.grid(row = 1 , column = 0 , pady = 15)
check_button = Button(root , text = "Check" , command = check_if_finished)
check_button.grid(row = 2 , column = 0)
mainloop()
Here, I used the pygame.mixer.music.get_busy() function to check whether the song has finished, but the problem is that the check_if_finished() function is not giving me the expected output when I pause the song. What I want is to not print "The song is finished" when I pause the song.
Is there any way to achieve this in pygame?
It would be great if anyone could help me out.

What I want is to not print "The song is finished" when I pause the song.
You are right. See pygame.mixer.music.get_busy():
Returns True when the music stream is actively playing. When the music is idle this returns False. In pygame 2.0.1 and above this function returns False when the music is paused.
You can deal with this by simply adding an additional condition:
def check_if_finished():
if paused or pygame.mixer.music.get_busy():
print("Song is not finished")
else:
print("Song is finshed")`

Related

Code beyond the Onclick and Listen doesn't get executed

this is my first time posting here.
I'm trying to make a Title Screen before getting the user in my game. When I hit enter, I want to break out of the While loop into a the main game loop, or go into the next section of the While loop. However, when I hit enter and the onkey use my Enter function which sets the In_title to False, it doesn't seem to respond with anything. (this is in python with turtle, also I'm working using replit.)
I've created a variable named in_title = True.
I've tried breaking out of the while loop using if in_title == false then break.
import turtle
import random
import math
import time
#set up for the screen title.
screen_size = [500,500]
screen_color = "#1a2645"
t = turtle.Turtle()
screen = t.getscreen()
screen.setup(screen_size[0],screen_size[1])
screen.bgcolor(screen_color)
screen.tracer(0)
t.ht()
game_state = 1 #to see if the game is still runninng. #0, 1 are no, yes.
in_title = True #to see if the game is in title or not.
select = turtle.Turtle()
select.color("yellow")
select.speed(0)
select.up()
select.setx(-80) #putting it in the middle of the text.
select.sety(30)
#all of the entity here:
player = {"p": turtle.Turtle(), "lives": 3, "color": "white", "rad": 15}
player["p"].ht()
harm = {"color": "red", "rad": 10}
num_harm = 10
good = {"g": turtle.Turtle(), "color": "white", "rad": 8}
good["g"].ht()
#universal movement function.
def moving_harm(h,rad): #function to move the harm objects.
if h.ycor() == (250 + rad/2):
h.up()
h.setx(random.randrange(-250,250))
h.sety(h.ycor() - 5)
screen.update()
if (h.ycor() != 250 + rad/2) and (h.ycor() != -250 - rad/2):
h.sety(h.ycor() - 5)
if (h.ycor() == (-250 - rad/2)):
h.sety(250 + rad/2)
screen.update()
def up():
if game_state == 1:
select.sety(30) #hard coded the number so it's in the middle.
print(select.ycor())
screen.update()
# def down():
# def left():
# def right():
def enter():
global in_title
if (game_state == 1):
if(select.ycor() == 30):
select.down()
select.forward(150)
select.setheading(180)
select.color("white")
select.forward(150)
screen.update()
time.sleep(0.2)
screen.clear()
screen.update()
time.sleep(0.1)
screen.setup(screen_size[0],screen_size[1])
screen.bgcolor(screen_color)
in_title = False
#main menu operation:
def main_game():
global game_state
#writing out the tittle screen.
menu = turtle.Turtle()
menu.up()
menu.sety(150)
menu.color("white")
menu.write("Sorta a Side Scroller Game", align="center", font=("Arial", 22, "normal"))
menu.sety(100)
menu.write("By Silver", align="center", font=("Arial", 15, "normal"))
menu.ht()
menu.sety(25)
menu.write("Start game", align="center", font=("Arial", 15, "normal"))
#create all the harm turtles:
for i in range(num_harm):
h = "h"+str(i+1)
harm[str(h)] = turtle.Turtle()
harm[str(h)].up()
harm[str(h)].ht()
#handle control at the title screen.
screen.onkey(enter, "Enter")
if in_title == False:
print("got passed that")
main_game()
screen.listen()
screen.update()
screen.mainloop()
no error message where given.
The way you have it, main_game() only is called once, right before screen's main loop begins. That means that this fragment
if in_title == False:
print("got passed that")
happens once and then control flow leaves main_game() forever, and the screen main loop begins.
Since the fragment only exists in main_game(), and main_game() isn't set to be called on any button press or called from anywhere else in the code, that fragment will never be called ever again. So, the if in_title == False: will never be encountered and print("got passed that") will never happen, even when in_title is False.
In this case, there is a place you already know is going to have control flow when in_title == False, and that is at the end of enter. So, you could put the code you have in mind there. This is the solution I suggested in the comments:
def enter():
global in_title
if (game_state == 1):
if(select.ycor() == 30):
# ...
in_title = False
print("got passed that")
#main menu operation:
def main_game():
# ...
screen.onkey(enter, "Enter")

pygame game not starting on key press

I am making a game that shows game over on screen at the end of the game and if the player presses any key, the game starts again.
Game over screen is displayed but the problem is that when I am pressing any key, the game is not starting. I suspect function gameOverScreen() is not returning out of while loop, I could not understand why.
This function is called when the game is over, and it's continuously running until the player press any key:
def gameOverScreen():
textFont = pygame.font.Font('freesansbold.ttf',90)
while True:
overSurf = textFont.render('GAME OVER',True,RED)
overRect = overSurf.get_rect()
overRect.center = (WINDOWWIDTH/2,WINDOWHEIGHT/2)
DISPLAYSURF.blit(overSurf,overRect)
drawPressKeyMessage()
checkForKeyPress()
if checkForKeyPress():
pygame.event.get() #clear event queue
return
pygame.display.update()
FPSCLOCK.tick(FPS)
Function to check key press is:
def checkForKeyPress():
if len(pygame.event.get(QUIT)) > 0:
terminate()
keyUpEvents = pygame.event.get(KEYUP)
if len(keyUpEvents) == 0:
return None
else:
return keyUpEvents[0].key
Main function which call all functions is:
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
pygame.display.set_caption('Wormy')
showStartScreen()
while True:
runGame()
showGameOverScreen()
Your keypress handler is called twice.
checkForKeyPress()
if checkForKeyPress():
The first call strips the event queue of kedown events so the second time it is called there is no keypress, so the loop cannot terminate.
There are two solutions:
either: remove the first call - take away the first of these lines:
checkForKeyPress() -- delete this line
if checkForKeyPress():
or: Store the result in a variable and use the variable in the if statement:
keyPress = checkForKeyPress()
if keyPress:
...

Troubleshooting playing of audio files in pygame

I am experiencing crashing and not playing of my audio files in pygame. I get this error when trying to trigger my audio file: RESTART: /Users/matthewmacy/Desktop/WORKING platupdate PROJECT_HELPED/main.py
SELFTRACKS!!! 4 In my code I generate a random number between 1 and 5 (self.tracks = random.randint(1,5)) which is suppose to determine the track played at random. I can successfully play a track for the initial splash screen but then the subsequent game music does not play. I thought a potential problem might be that I am cutting the splash screen audio when I am turning on the game audio. I thought that having a timer to start the music after 5 seconds would make for enough time between audio start/stop. If anyone know a fix for this please fill me in.
def show_start_screen(self):
# game splash/start screen
pg.mixer.music.load('beautiful_reverb.wav')
pg.mixer.music.play(-1)
bg = pg.image.load("1366X768EDITEDflag.png")
self.screen.blit(bg,(0,0))
pg.display.flip()
self.wait_for_key()
#Go to controls Screen and cut music when clicked
controls = pg.image.load("1366X768ControlsFINAL.png")
self.screen.blit(controls,(0,0))
pg.display.flip()
self.wait_for_key()
pg.mixer.music.stop()
self.PlayMusic()
def PlayMusic(self):
now = pg.time.get_ticks()
if now - self.last_update3 > 5000:
self.last_update3 = now
self.tracks = random.randint(1,5)
print("SELFTRACKS!!!", self.tracks)
if self.tracks == 1:
pg.mixer.music.load('1GOODPARTS1.wav')
pg.mixer.music.play(-1)
if self.tracks == 2:
pg.mixer.music.load('2FminorScale.wav')
pg.mixer.music.play(-1)
if self.tracks == 3:
pg.mixer.music.load('3GOODfunnyTRumpdance3.wav')
pg.mixer.music.play(-1)
if self.tracks == 4:
pg.mixer.music.load('4GOODfunnyTrumpdance4.wav')
pg.mixer.music.play(-1)
if self.tracks == 5:
pg.mixer.music.load('5OLDschoolVideogame.wav')
pg.mixer.music.play(-1)
Here's a simple tutorial. Especially the 'Doing Something When a Song Ends:' paragraph is interesting for you. Define an event type, call pg.mixer.music.set_endevent(SONG_END) and in the event loop just check if this event was in the event queue, pick a random song and play it.
import sys
import random
import pygame as pg
pg.mixer.pre_init(44100, -16, 2, 2048)
pg.init()
screen = pg.display.set_mode((640, 480))
SONGS = ['song1.wav', 'song2.wav', 'song3.wav']
# Here we create a custom event type (it's just an int).
SONG_END = pg.USEREVENT + 1
# When a song is finished, pygame will add the
# SONG_END event to the event queue.
pg.mixer.music.set_endevent(SONG_END)
# Load and play the first song.
pg.mixer.music.load('song1.wav')
pg.mixer.music.play(0)
def main():
clock = pg.time.Clock()
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
# If the SONG_END event gets emitted, just
# pick a random song and play it.
if event.type == SONG_END:
print('The song ended. Playing random song.')
pg.mixer.music.load(random.choice(SONGS))
pg.mixer.music.play(0)
screen.fill((30, 60, 80))
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
sys.exit()

Game timer in pygame

I'm trying to implement a game timer for a word memory game. The game has a start screen, so the time should be calculated from when the user presses "play", paused when the user presses "pause" mid game and continued when the user presses "continue" on the pause screen.
I understand that the correct implementation of this should be independent(ish) of the ticks as i'm using that to control fps. Also it is suggested to use pygame.time.set_times(), which in most examples takes (USEREVENT+1, 1000) as arguments. What is USEREVENT? I can't grasp the documentation for this function.
Below is my implementation. It starts measuring time at pygame.init(), not whhen i call my game loop although the function call for timer() is in the game loop, and can't be paused. How do i rewrite it in order to be able to control the start/stop state of the timer?
Thanks!
def timer():
#isOn =True
#while isOn:
second=round((pygame.time.get_ticks())/1000)
minute=0
hour=0
minute, second=divmod(second, 60)
hour, minute=divmod(minute, 60)
#text=smallfont.render("Elapsed time: "+str(getSeconds), True, WHITE)
text=smallfont.render("Elapsed time: "+str("%d" %hour + " : "+"%d" %minute + " : "+"%d" %second), True, WHITE)
gameDisplay.blit(text, [0+MARGIN,350])
return time
Create your own timer class. Use time.time() (from the regular python time module).
import time
class MyTimer:
def __init__(self):
self.elapsed = 0.0
self.running = False
self.last_start_time = None
def start(self):
if not self.running:
self.running = True
self.last_start_time = time.time()
def pause(self):
if self.running:
self.running = False
self.elapsed += time.time() - self.last_start_time
def get_elapsed(self):
elapsed = self.elapsed
if self.running:
elapsed += time.time() - self.last_start_time
return elapsed

Pygame music pause/unpause toggle

Okay here's my code:
def toggleMusic():
if pygame.mixer.music.get_busy():
pygame.mixer.music.pause()
else:
pygame.mixer.music.unpause()
---event handling---
if pressed 'm' it should toggle whether the music is paused and not paused
toggleMusic()
It can pause the music but not unpause, any explanation?
Had the same problem. For others' reference, my solution was to use a simple class.
class Pause(object):
def __init__(self):
self.paused = pygame.mixer.music.get_busy()
def toggle(self):
if self.paused:
pygame.mixer.music.unpause()
if not self.paused:
pygame.mixer.music.pause()
self.paused = not self.paused
# Instantiate.
PAUSE = Pause()
# Detect a key. Call toggle method.
PAUSE.toggle()
It doesn't unpause the music because pygame.mixer.music.pause() doesn't affect the state of pygame.mixer.music.get_busy().
To get the behavior you are looking for you will need to your maintain your own variable which keeps track of the paused/unpaused state. You can do this in a class:
class mixerWrapper():
def __init__(self):
self.IsPaused = False
def toggleMusic(self):
if self.IsPaused:
pygame.mixer.music.unpause()
self.IsPaused = False
else:
pygame.mixer.music.pause()
self.IsPaused = True
this one is good, i use it for games
source https://youtu.be/kzTloDq1FiQ
is_paused = False
def toggle_pause():
global is_paused
if is_paused == True:
is_paused = False
else:
is_paused = True
wn.listen()
wn.onkeypress(toggle_pause, " ")
while True:
if not is_paused:
bob.fd(1)
bob.lt(1)
else:
wn.update()

Categories

Resources