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()
Related
In my pygame script, I have a function to work with some images that I have to use in a while loop. The problem is that I only want to run the function once for each image. So, I want to run self.convert_img(self.img_one) once, then proceed to self.convert_img(self.img_two) and so on, untill all images are processed. Afterwards, I would like the function to stop, such that I can change the scene.
Here is a mock of my code right now:
import pygame
class Main:
def __init__(self):
pygame.init()
self.window = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
self.clock = pygame.time.Clock()
self.count = 5
# Load Images
self.img_one = pygame.image.load(os.path.join("images", "img_one.png"))
self.img_two = pygame.image.load(os.path.join("images", "img_two.png"))
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
img_one_transorm = self.convert_img(self.img_one)
img_two_transorm = self.convert_img(self.img_two)
## img three transform
self.clock.tick(30)
def convert_img(self, arg1):
self.window.blit(arg1, convert_img_rect)
pygame.display.update()
if self.count > 0:
## convert image function
create a count that increases by one then a bunch of if statements
like:
if count == 1:
img_one_transorm=self.convert_img(self.img_one)
count+=1
elif count == 2:
img_two_transorm=self.convert_img(self.img_two)
count+=1
did i understand this correctly?
I’m trying to use pyttsx3 in a game where speech is said in response to events within the game, however I can’t figure out how to execute speech commands without pausing the game loop until the audio finishes. Using runAndWait() is no good for this reason, and I can’t get the example in the docs using iterate() to work as I need it to either. See the code below:
import pyttsx3
import pygame as pg
def onStart(name):
print('start')
def onWord(name, location, length):
print('word', name, location, length)
def onEnd(name, completed):
print('end')
def speak(*args, **kwargs):
engine.connect('started-utterance', onStart)
engine.connect('started-word', onWord)
engine.connect('finished-utterance', onEnd)
engine.say(*args, **kwargs)
def main():
engine.startLoop(False)
n = 0
while True:
n += 1
print(n)
if n == 3:
speak('The first utterance.')
elif n == 6:
speak('Another utterance.')
engine.iterate()
clock.tick(1)
if __name__ == '__main__':
pg.init()
engine = pyttsx3.init()
clock = pg.time.Clock()
main()
pg.quit()
sys.exit()
In this example, the first statement is triggered at the right time, but it seems like pyttsx3 stops processing at that point - no further say commands produce any sound, and only the first started-utterance event fires - the started-word and finished-utterance commands never fire. I’ve tried this every way I can think of and still can’t get it to work. Any ideas?
I'm not familiar with pyttx3, but I've created an example that incorporates a pygame event loop. The colour changes with every mouse click event and the name of the colour is spoken.
import random
import pygame
import pyttsx3
WIDTH = 640
HEIGHT = 480
FPS = 120
simple_colors = [
"red",
"orange",
"yellow",
"green",
"blue",
"violet",
"purple",
"black",
"white",
"brown",
]
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# TTS Setup
engine = pyttsx3.init()
engine.startLoop(False) # have to call iterate in the main loop
# set a random color
current_color = random.choice(simple_colors)
# create a centered rectangle to fill with color
color_rect = pygame.Rect(10, 10, WIDTH - 20, HEIGHT - 20)
frames = 0
paused = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONUP:
current_color = random.choice(simple_colors)
engine.stop() # interrupt current speech?
engine.say(f"The next color is {current_color}")
# update game elements
pygame.display.set_caption(
f"Color: {current_color:10} Frame: {frames:10} FPS: {clock.get_fps():.1f}"
)
# draw surface - fill background
window.fill(pygame.color.Color("grey"))
## draw image
window.fill(pygame.color.Color(current_color), color_rect)
# show surface
pygame.display.update()
# call TTS Engine
engine.iterate()
# limit frames
clock.tick(FPS)
frames += 1
pygame.quit()
engine.endLoop()
If you run this you'll see a repetition of the problem you described, the game loop pausing, indicated by the frame count in the title bar. I used a longer sentence rather than just the colour name to exacerbate the issue. Perhaps someone with a better understanding of pyttx3 will understand where we've both gone wrong. In any case we can get around this by running the Text to Speech engine in a different thread.
import random
import threading
import queue
import pygame
import pyttsx3
# Thread for Text to Speech Engine
class TTSThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
self.daemon = True
self.start()
def run(self):
tts_engine = pyttsx3.init()
tts_engine.startLoop(False)
t_running = True
while t_running:
if self.queue.empty():
tts_engine.iterate()
else:
data = self.queue.get()
if data == "exit":
t_running = False
else:
tts_engine.say(data)
tts_engine.endLoop()
WIDTH = 640
HEIGHT = 480
FPS = 120
simple_colors = [
"red",
"orange",
"yellow",
"green",
"blue",
"violet",
"purple",
"black",
"white",
"brown",
]
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# create a queue to send commands from the main thread
q = queue.Queue()
tts_thread = TTSThread(q) # note: thread is auto-starting
# set a random color
current_color = random.choice(simple_colors)
# Initial voice message
q.put(f"The first color is {current_color}")
# create a centered rectangle to fill with color
color_rect = pygame.Rect(10, 10, WIDTH - 20, HEIGHT - 20)
frames = 0
paused = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
q.put("exit")
elif event.type == pygame.MOUSEBUTTONUP:
current_color = random.choice(simple_colors)
q.put(f"The next color is {current_color}")
# update game elements
pygame.display.set_caption(
f"Color: {current_color:10} Frame: {frames:10} FPS: {clock.get_fps():.1f}"
)
# draw surface - fill background
window.fill(pygame.color.Color("grey"))
## draw image
window.fill(pygame.color.Color(current_color), color_rect)
# show surface
pygame.display.update()
# limit frames
clock.tick(FPS)
frames += 1
pygame.quit()
In this case, we're using a queue to send the text to the thread which will perform the text-to-speech, so the frame counter does not pause. Unfortunately we can't interrupt the speech, but that might not be a problem for your application.
Let me know if you need any further explanation of what's going on, I've tried to keep it simple.
EDIT: Looking at this issue recorded on github it seems that speech interruption on Windows is not working, the work-around in that discussion is to run the text-to-speech engine in a separate process which is terminated. I think that might incur an unacceptable start-up cost for process and engine re-initialisation every time an interruption is desired. It may work for your usage.
as a premice i would like to say that i'm totally new to programming and i'm not a computer science student so i'm sorry if my code makes you cringe, i recently had some python classes and enjoyed them so i wanted to deepen a little so i figured that a simple chess game would be fun to do.
As you can imagine i am using pygame.
As for now i "drew" a chessboard and i blitted the pieces in place, my idea is that i would get the coordinates of every click, if the coordinates are the same (or in range) of the blitted image the variable would update with the second click, how can i make it so that the system recognizes a "first" and "second" click.
import pygame as pg
import sys
pg.init()
schermo = pg.display.set_mode((640,540))
def coordinate():
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.MOUSEBUTTONUP:
mx1, my1 = pg.mouse.get_pos()
print (mx1,my1)
return mx1,my1
pg.display.update()
this is how i get the coords
ctorrensx = (53,53)
[...omissis]
def move():
result = coordinate()
global ctorrensx
if result == ctorrensx:
ctorrensx = (200,200)
this was my first idea for the moving function, ctorrensx is an example i wanted to try on, they are the coords of the left black rook, once i would click on it i wanted it to move to the coords (200,200) but it's not happening.
this is my first time using stack overflow so i hope that i didn't create too much confusion on my question.
thank you all.
You can set a flag to determine whether the click is a first or second.
For example:
firstClick = True
while True:
for event in pg.event.get():
if event.type == pg.MOUSEBUTTONDOWN:
if(firstClick):
firstClick = False
#Code for first click
else:
#code for second click
firstClick = True #resets the flag
I need to kb input onto a pygame screen
at the moment it appears on the idle shell
any advice would be appreciated.
This code is extracted from a larger program
mostly screen based but i need to input some
data (numeric) from the kb at times
import sys
import pygame
from pygame.locals import *
pygame.init()
N= ''
screen = pygame.display.set_mode((600,600))
font= pygame.font.Font(None,40)
screen.fill((255,255,255))
pygame.display.flip
pygame.display.update()
def score(C,y):
SetWnd = font.render( C,True,(0,0,255))
screen.blit(SetWnd, (15, 100+y))
pygame.display.update()
def start():
while True:
name=''
for evt in pygame.event.get():
if evt.type == KEYDOWN:
if evt.unicode.isalnum(): # unicode
name+=evt.unicode
print name,
elif evt.key == K_BACKSPACE:
name = name[:-1]
print name,
elif evt.key == K_RETURN:
return N
elif evt.type == QUIT:
pygame.quit()
sys.exit()
def Pchange(c,y):
block = font.render(N, True, (0,0,0))
rect = block.get_rect()
rect.move_ip(75,100 + y)
screen.blit(block,rect)
pygame.display.flip()
score('wind', 0)
score('elev',20)
N = start()
Pchange(N,0)
Pchange(N,20)
Firstly you draw the score twice, which i assume works well.
The problem lies in you start function.
You are not calling any draw or update function in your while loop.
In your event foreach, you add a digit to name, and exit the while loop when enter is pressed. Then you draw twice with Pchange, but you are the function does not use the right parameters. You have:
def Pchange(c,y):
block = font.render(N, True, (0,0,0))
you are using the global N which is ''. So to fix that, you need to change N to c.
The next problem is that the game quits right after pressing enter. Since you pasted only a part of the program, this might not be the case. If it is, make another while loop, and just wait for the ESC key to call pygame.quit() and sys.exit()
My question is kinda complicated as I run it through my head but I will try to explain it as best I can. I have 2 python codes, one that I created with Python for a Mastermind game and then the other in Pygame for a Mastermind board to play it on. My question is simply this: How can I combine both of these codes into 1 to have it play from Pygame and not the command prompt window I usually get?
I'm sorry if this sounds all gibberishy, but thats my question. I merely want to take my Python code and implement it into the Pygame code and have the game run like it's supposed to.
Heres the code for the game:
import random
class InvalidMove(Exception):pass
class Game:
def __init__(self):
self.colors=('r','g','b','y')
self.to_guess=[random.choice(self.colors) for i in range(4)]
def match_guess(self,guess):
if len(guess)!=len(self.to_guess) or [g for g in guess if g not in self.colors]:
raise InvalidMove()
ret=[0,0]
usedindexes=[]
for i,g in enumerate(guess):
if g==self.to_guess[i]:
ret[0]+=1
usedindexes.append(i)
for i,g in enumerate(guess):
if i in usedindexes: continue
for j,c in enumerate(self.to_guess):
if c==g and j not in usedindexes:
ret[1]+=1
usedindexes.append(j)
return ret
class UI:
def make_move(self):
guess=raw_input("Guess: ")
return guess.split()
def main(self):
print("The game begins...")
print("Possible colors (enter first letter): [r]ed [g]reen [b]lue [y]ellow")
print("Enter your guess like: r g b y")
g=Game()
while True:
guess=self.make_move()
try:
bp,wp=g.match_guess(guess)
except InvalidMove:
print("Invalid guess, try again")
continue
print("Black pegs %s"%bp)
print("White pegs %s"%wp)
if bp==4:
print("You won!")
if __name__=="__main__":
u=UI()
u.main()
And here's the code for the board I made in Pygame:
import pygame
from pygame.locals import *
def draw_current(men, turn, spacing, corner):
current = len(men) - 1
pos = corner[0] + current * spacing[0], turn * spacing[1] + corner[1]
screen.blit(images[men[-1]], pos)
images = { K_r: pygame.image.load('red.png'), K_g: pygame.image.load('green.png'),
K_b: pygame.image.load('blue.png'), K_y: pygame.image.load('yellow.png'),
K_SPACE: pygame.image.load('empty.png') }
pygame.init()
SCREEN_SIZE = (640, 480)
background_image_filename = 'mastermind_board.jpg'
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
background = pygame.image.load(background_image_filename).convert()
screen.blit(background, (0, 0))
pygame.display.update()
men = []
margin = 5, 3
spacing = [x + m for m, x in zip(margin, images[K_r].get_size())]
corner = 74, 74
turn = 0
quit = False
while not quit:
for event in pygame.event.get():
if event.type == QUIT:
quit = True
break
if event.type == KEYUP:
if event.key in images:
#print event.key
men.append(event.key)
# update
draw_current(men,turn, spacing, corner)
if len(men) == 4:
turn += 1
men = []
pygame.display.update()
elif event.key in (K_q, K_ESCAPE):
quit = True
break
pygame.quit()
Any and all help/suggestions would be more than greatly appreciated.
As I'm sure you know, you can't just put it all in one file and have it run. You need to encapsulate the Mastermind game so you can run/update it from the pygame loop. It'd be cleaner if you keep the Mastermind game logic in a separate file and just import it, but it's not required.
Here's some semi-psuedocode:
import pygame
class Mastermind(object):
def update(self, *args):
pass #do stuff
pygame.init()
while not quit:
if event:
if event == "quit":
quit = True
else:
#update the game
Mastermind.update(args)
#update the board
pygame.display.update()
pygame.quit()
Of course, this won't work for you exactly, but I hope the idea that I'm explaining comes through.
Step 1. Fix your board so that it's a proper class definition.
Step 2. Write a third file that import the board and the game.
They're now "combined".
Now you have to do the hard work of fixing the Game to use the new, fancy Board you built.