Pygame: music do not play instantly on loop - python

First, sorry for my poor English.
I'm writing a game with Python 3.4 and Pygame. Game includes scenes what provide view of screen, and music, etc, parsed from XML scripts.
I expect music plays instantly, but not plays at next scene.
and cannot find similar problem on web.
how can I rewrite code to play music scene-instantly?
I wrote code like it:
(graphic part removed)
xml file is here : https://pastebin.com/bSBiv1jX
import pygame
import xml.etree.ElementTree as ET
class Script():
def __init__(self, name, filename):
self.name = name
self.parsed = ET.parse(filename)
self.root = self.parsed.getroot()
self.scene_list = self.root.findall("scene")
self.flag_list = str(self.root.findtext("flags")).split(",")
for flag in self.flag_list:
setattr(self, flag, False)
def music_play(self, number):
scene = self.scene_list[number]
if scene.findtext("music") == 'stop':
pygame.mixer.music.stop()
elif scene.findtext("music") != '':
pygame.mixer.music.load(scene.findtext("music"))
pygame.mixer.music.play(-1, 0.0)
def goto(self, number):
string = self.scene_list[number].findtext("goto")
if string == '':
return number
elif isNumber(string) == True:
return int(string)
elif isNumber(string) == False:
return string
def if_goto(self, string, number):
iflist = string.split(', ')
if getattr(self, iflist[0]) == True
return int(iflist[1])
else:
return number + 1
def isNumber(s):
try:
float(s)
return True
except ValueError:
return False
def runGame():
pygame.init()
windowSurface = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
run = True
scene_number = 0
script = Script('dummy', 'scenario/dummy.xml')
while run:
# 입력 처리
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if scene_number == script.goto(scene_number):
scene_number += 1
elif scene_number != script.goto(scene_number):
if isNumber(script.goto(scene_number)):
scene_number = script.goto(scene_number)
else:
scene_number = script.if_goto(script.goto(scene_number), scene_number)
script.music_play(scene_number)
pygame.display.update()
clock.tick(30)
pygame.quit()
def main():
runGame()
if __name__ == "__main__":
main()

https://www.pygame.org/docs/ref/music.html#pygame.mixer.music.load
If a music stream is already playing it will be stopped
https://www.pygame.org/docs/ref/music.html#pygame.mixer.music.play
If the music is already playing it will be restarted.
At every iteration of your game loop you call music_play and restart the music. You should only start the music if it's not already running.
You could, for instance, only call this when a scene changes.

Related

Pygame: run a function only one time even if it is in a while loop

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?

algorithm writer of tkinter

I'm writing an algorithm that provides a tkinter program as output (I hope I explained myself) the program works by dragging the combobox, the text ... into a space and memorizing the coordinates.
I decided to do it with pygame, (I took the skeleton of the program from the internet and then modified it).
I have encountered several problems:
I have a problem inserting multiple images (for now I have only
inserted one),
I can't memorize the coordinates, I tried with print (event) but it doesn't work,
I can not insert the image in a specific point of the root.
here is my code:
import os,sys
import pygame as pg
pg.init()
a=0
b=0
c=200
d=200
event = pg.event.poll()
Sfondo = pg.image.load("Sfondo.jpg")
def DisegnaBackground (a,b):
Screen.blit(Sfondo,(a,b))
class Character:
def __init__(self,rect):
self.rect = pg.Rect(rect)
self.click = False
self.image = pg.image.load("ComboBox.png").convert()
Screen.blit(self.image, (c,d))
def update(self,surface):
if self.click:
self.rect.center = pg.mouse.get_pos()
surface.blit(self.image,self.rect)
def main(Surface,Player):
game_event_loop(Player)
DisegnaBackground (a,b)
Player.update(Surface)
def game_event_loop(Player):
for event in pg.event.get():
if event.type == pg.MOUSEBUTTONDOWN:
if Player.rect.collidepoint(event.pos):
Player.click = True
elif event.type == pg.MOUSEBUTTONUP:
Player.click = False
elif event.type == pg.QUIT:
pg.quit(); sys.exit()
if __name__ == "__main__":
os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
Screen = pg.display.set_mode((1500,800))
MyClock = pg.time.Clock()
MyPlayer = Character((0,0,200,24))
MyPlayer.rect.center = Screen.get_rect().center
while 1:
main(Screen,MyPlayer)
pg.display.update()
MyClock.tick(60)
print(event)
There are a number of problems. First, try to make sure not to mix global and local variables. Try re-writing the function like this:
def DisegnaBackground (surface, a, b):
surface.blit(Sfondo, (a, b))
For this to work, you have to update your main too:
def main(Surface,Player):
game_event_loop(Player)
DisegnaBackground (Surface, a, b)
Player.update(Surface)
Finally, you do not need to display your character immediately after the creation, so you can leave the init function as
def __init__(self,rect):
self.rect = pg.Rect(rect)
self.click = False
self.image = pg.image.load("ComboBox.png").convert()
I hope it helps.

Python/Pygame: draw phase drawing too many cards

I am making a card game, and there is a draw phase which is coded as such:
def drawPhase():
drawHand = hand
drawDeck = deck
oppDrawHand = oppHand
oppDrawDeck = oppDeck
drawHand.append(drawDeck[0])
oppDrawHand.append(oppDrawDeck[0])
for cards in range(2):
del drawDeck[0]
del oppDrawDeck[0]
return drawHand, drawDeck, oppDrawHand, oppDrawDeck
I have it appending the list for each hand only once, but for some reason it seems to be drawing four cards for each player and I can't figure it out. The other parts of the code don't seem relevant for drawing cards but I can post the gameloop if the problem isn't apparent int he function shown earlier. Thanks!
edit: here is the game loop:
while True:
# defining image indexes
currentHandImageIndex = None
endButtonIndex = None
mouse_pos = pygame.mouse.get_pos()
#game loop variables
hand = playerHand
oppHand = oppGetHand
deck = playerDeck
oppDeck = oppGetDeck
benchHand = []
oppBench = []
postHand = []
oppPost = []
perimeterHand = []
oppPerimet = []
showHand = displayHand(hand, oppHand)
handImages = updateHandImages()
#stage variables
step = defStep
isDrawPhase = False
#text_prompt_choose_for_bench.draw_text()
endButtonPressed = False
mouseClick = False
#text drawing
if len(step) == 1:
isDrawPhase = True
text_prompt_enter_draw_phase.draw_text()
if len(step) == 2:
isBenchPhase = True
text_prompt_choose_for_bench.draw_text()
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYUP:
if event.key == K_ESCAPE:
terminate()
if event.type == MOUSEBUTTONUP:
mouseClick = True
for i, rect in enumerate(HAND_RECTS):
if rect.collidepoint(mouse_pos):
currentHandImageIndex = i
break
for i, rect in enumerate(END_RECT):
if rect.collidepoint(mouse_pos):
endButtonIndex = i
break
if mouseClick == True:
if endButtonIndex is not None:
endButtonPressed = True
if currentHandImageIndex is not None:
if currentHandImageIndex <= len(hand)-1:
DISPLAYSURF.blit(handImages[currentHandImageIndex], (925,200))
if isDrawPhase == True:
if endButtonPressed == True:
hand, deck = drawPhase()[0], drawPhase()[1]
oppHand, oppDeck = drawPhase()[2], drawPhase()[3]
endButtonPressed = False
isDrawPhase = False
step.append(1)
drawPlayMat()
drawHand.append(drawDeck[0])
oppDrawHand.append(oppDrawDeck[0])
for cards in range(2):
del drawDeck[0]
del oppDrawDeck[0]
This code adds one card to your hand but removes two cards from your deck, and the same with your opponent's hand and deck. This doesn't seem right.

Can I save the keyboard input in a list?

I have a code, where pressing a key reproduces a sound generated by the computer, my concern is, how can I store the keys in the order they were pressed in a list and print it?
Here is the code:
from array import array
import pygame
from pygame.mixer import Sound, get_init, pre_init
class Note(pygame.mixer.Sound):
def __init__(self, frequency, volume=.1):
self.frequency = frequency
Sound.__init__(self, self.build_samples())
self.set_volume(volume)
def build_samples(self):
period = int(round(get_init()[0] / self.frequency))
samples = array("h", [0] * period)
amplitude = 2 ** (abs(get_init()[1]) - 1) - 1
for time in range(period):
if time < period / 2:
samples[time] = amplitude
else:
samples[time] = -amplitude
return samples
pre_init(44100, -16, 1, 1024)
pygame.init()
screen = pygame.display.set_mode([640, 480], 0)
sounds = {}
keymap = {pygame.K_p: 880, pygame.K_r: 440}
while True:
key_pressed=[]
evt = pygame.event.wait()
if evt.type == pygame.QUIT:
break
elif evt.type == pygame.KEYDOWN:
if evt.key in keymap:
note = Note(keymap[evt.key])
note.play(-1)
sounds[evt.key] = note
key_pressed.append(note)
elif evt.type == pygame.KEYUP:
if evt.key in sounds:
sounds.pop(evt.key).stop()
Here is the problem !!!
while True:
key_pressed=[]
and here is the solution :
key_pressed_list = key_pressed
print(key_pressed_list)

Combining Code from two programs in Python

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.

Categories

Resources