Mar-24-2022, 10:35 AM
Dear community,
I've got a problem with game development/tkinter...
I generated a form which let the user choose some tracks.
These tracks should be played randomly in the game loop.
I printed playlist after function "ischecked" is processed - and it contains, as expected,
the randomly sorted values of "listl".
But in main() the list "playlist" is emtpy...
What I am doing wrong?
Thanks a lot for your help!
I've got a problem with game development/tkinter...
I generated a form which let the user choose some tracks.
These tracks should be played randomly in the game loop.
I printed playlist after function "ischecked" is processed - and it contains, as expected,
the randomly sorted values of "listl".
But in main() the list "playlist" is emtpy...
What I am doing wrong?
Thanks a lot for your help!
import random, math, pygame, tkinter from tkinter import * from PIL import Image from itertools import product #from PyQt6.QtWidgets import QLabel, QRadioButton, QVBoxLayout, QApplication, QWidget #from PyQt6.QtGui import * pygame.init() pygame.mixer.init() pygame.mixer.music.set_volume(0.7) master = Tk() master.geometry('500x400') # Define colors used by the game. TEXT_COLOR = (255, 255, 255) FOREGROUND = (0, 0, 0) # Recolor image pixels that are this color TRANSPARENT = (255, 255, 255) # Make image pixels this color transparent BALL_COLOR = (255, 255, 255) PADDLE_COLOR = (255, 255, 255) BRICK_COLORS = ((255, 0, 0), (255, 50, 0), (255, 100, 0), (255, 150, 0), (255, 200, 0), (255, 255, 0)) BRICK_COORDS = [ (32, 32), (64, 32), (96, 32), (160, 32), (288, 32), (320, 32), (352, 32), (416, 32), (448, 32), (480, 32), (576, 32), (608, 32), (640, 32), (32, 64), (160, 64), (288, 64), (352, 64), (416, 64), (480, 64), (576, 64), (640, 64), (32, 96), (160, 96), (288, 96), (352, 96), (416, 96), (480, 96), (576, 96), (640, 96), (32, 128), (64, 128), (96, 128), (160, 128), (288, 128), (352, 128), (416, 128), (448, 128), (480, 128), (576, 128), (608, 128), (640, 128), (32, 160), (160, 160), (288, 160), (352, 160), (416, 160), (448, 160), (576, 160), (640, 160), (32, 192), (160, 192), (288, 192), (352, 192), (416, 192), (480, 192), (576, 192), (640, 192), (32, 224), (160, 224), (192, 224), (224, 224), (288, 224), (320, 224), (352, 224), (416, 224), (512, 224), (576, 224), (640, 224)] # Define some image files. These are not your files BALL_IMAGE = "ball.png" PADDLE_IMAGE = "paddle.png" BRICK_FILES = (("brick0.png", "brick1.png", "brick2.png"), ("bbrick0.png", "bbrick1.png", "bbrick2.png")) BACKGROUND_IMAGE = pygame.image.load("Hintergrund.png") SCREEN_WIDTH = 800 SCREEN_HEIGHT = 578 SCORE_POSITION = (SCREEN_WIDTH - 150, SCREEN_HEIGHT - 30) listl = [] playlist = [] def insert_into_listl(listl, track): # Adding songs file in our listl listl.append(track) def isChecked(): if cb1.get() is True: insert_into_listl(listl, "1.mp3") if cb2.get() is True: insert_into_listl(listl, "2.mp3") if cb3.get() is True: insert_into_listl(listl, "3.mp3") if cb4.get() is True: insert_into_listl(listl, "4.mp3") if cb5.get() is True: insert_into_listl(listl, "5.mp3") if cb6.get() is True: insert_into_listl(listl, "6.mp3") if cb7.get() is True: insert_into_listl(listl, "7.mp3") if cb8.get() is True: insert_into_listl(listl, "8.mp3") if cb9.get() is True: insert_into_listl(listl, "9.mp3") if cb10.get() is True: insert_into_listl(listl, "10.mp3") playlist = random.sample(listl, len(listl)) return playlist def play(bnr): if bnr == 1: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 2: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 3: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 4: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 5: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 6: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 7: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 8: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 9: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() elif bnr == 10: pygame.mixer.music.load(str(bnr) + ".mp3") pygame.mixer.music.play() l = Label(master, text="Welche tracks sollen zufällig gespielt werden (mit playlist)?", font=('arial', 12, 'bold', 'italic')) l.place(x=0, y=0) button1 = tkinter.Button(master, text="reinhören", command=lambda: play(1)) button1.place(x=0, y=25) button2 = tkinter.Button(master, text="reinhören", command=lambda: play(2)) button2.place(x=0, y=50) button3 = tkinter.Button(master, text="reinhören", command=lambda: play(3)) button3.place(x=0, y=75) button4 = tkinter.Button(master, text="reinhören", command=lambda: play(4)) button4.place(x=0, y=100) button5 = tkinter.Button(master, text="reinhören", command=lambda: play(5)) button5.place(x=0, y=125) button6 = tkinter.Button(master, text="reinhören", command=lambda: play(6)) button6.place(x=0, y=150) button7 = tkinter.Button(master, text="reinhören", command=lambda: play(7)) button7.place(x=0, y=175) button8 = tkinter.Button(master, text="reinhören", command=lambda: play(8)) button8.place(x=0, y=200) button9 = tkinter.Button(master, text="reinhören", command=lambda: play(9)) button9.place(x=0, y=225) button10 = tkinter.Button(master, text="reinhören", command=lambda: play(10)) button10.place(x=0, y=250) cb1=BooleanVar() cb2=BooleanVar() cb3=BooleanVar() cb4=BooleanVar() cb5=BooleanVar() cb6=BooleanVar() cb7=BooleanVar() cb8=BooleanVar() cb9=BooleanVar() cb10=BooleanVar() Checkbutton1 = Checkbutton(master, text="Adeline Yeo (HP) - Kite Fly High", variable=cb1) Checkbutton1.place(x=75, y=25) Checkbutton2 = Checkbutton(master, text="Nul Tiel Records - Fireflies", variable=cb2) Checkbutton2.place(x=75, y=50) Checkbutton3 = Checkbutton(master, text="cryptic scenery - Endzeit Endlos", variable=cb3) Checkbutton3.place(x=75, y=75) Checkbutton4 = Checkbutton(master, text="cryptic scenery - Helix Spire", variable=cb4) Checkbutton4.place(x=75, y=100) Checkbutton5 = Checkbutton(master, text="cryptic scenery - Minsk Metro", variable=cb5) Checkbutton5.place(x=75, y=125) Checkbutton6 = Checkbutton(master, text="cryptic scenery - Stazione Termini", variable=cb6) Checkbutton6.place(x=75, y=150) Checkbutton7 = Checkbutton(master, text="cryptic scenery - The Future was Japanese", variable=cb7) Checkbutton7.place(x=75, y=175) Checkbutton8 = Checkbutton(master, text="Ketsa - Holding The Line", variable=cb8) Checkbutton8.place(x=75, y=200) Checkbutton9 = Checkbutton(master, text="Maarten Schellekens - Salt Lake Swerve", variable=cb9) Checkbutton9.place(x=75, y=225) Checkbutton10 = Checkbutton(master, text="Strobotone - Dance Track", variable=cb10) Checkbutton10.place(x=75, y=250) button11 = tkinter.Button(master, text="ausgewählte tracks zu playlist hinzufügen", command=isChecked) button11.place(x=75, y=275) def create_image(file, color=None): """ Create image from a file. If color is specified, replace all FOREGROUND pixels with color pixels. Modify image so TRANSPARENT colored pixels are transparent. """ if color: # Recolor the image image = Image.open(file).convert("RGB") for xy in product(range(image.width), range(image.height)): if image.getpixel(xy) == FOREGROUND: image.putpixel(xy, color) image = pygame.image.fromstring(image.tobytes(), image.size, "RGB") else: image = pygame.image.load(file) image.set_colorkey(TRANSPARENT) return image.convert() class EnhancedSprite(pygame.sprite.Sprite): """ Sprite with image and rectangle. I expose some of my rectangle's properties. """ def __init__(self, image, group=None, **kwargs): super().__init__(**kwargs) self.image = image self.rect = image.get_rect() if group is not None: group.add(self) def at(self, x, y): """Convenience method for setting my position""" self.x = x self.y = y return self # Properties below expose properties of my rectangle so you can use # self.x = 10 or self.centery = 30 instead of self.rect.x = 10 @property def x(self): return self.rect.x @x.setter def x(self, value): self.rect.x = value @property def y(self): return self.rect.y @y.setter def y(self, value): self.rect.y = value @property def centerx(self): return self.rect.centerx @centerx.setter def centerx(self, value): self.rect.centerx = value @property def centery(self): return self.rect.centery @centery.setter def centery(self, value): self.rect.centery = value @property def right(self): return self.rect.right @right.setter def right(self, value): self.rect.right = value @property def bottom(self): return self.rect.bottom @bottom.setter def bottom(self, value): self.rect.bottom = value class Brick(EnhancedSprite): """ A target for the ball. After I take some number of hits I die. Number of hits I can take is in range 1 to 3. Hits is randomly selected if not specified. Specify brick color using (R, G, B) format. If color not specified a color is selected based on the row. """ group = pygame.sprite.Group() def __init__(self, x, y, image_files=None, color=None, hits=None): color = color or random.choice(BRICK_COLORS) hits = hits or random.choice((1, 1, 1, 2, 2, 3)) self.value = self.hits = max(1, min(3, hits)) image_files = image_files or random.choice(BRICK_FILES) self.images = [create_image(file, color) for file in image_files] super().__init__(self.images[self.hits - 1], self.group) self.at(x, y) def __len__(self): """Return how many bricks remaining""" return len(self.group) def hit(self, score): """ I was hit! Update my appearance or die based on my hit total. Return my value if I was killed. """ self.hits -= 1 if self.hits > 0: self.image = self.images[self.hits - 1] return 0 self.kill() return self.value class Paddle(EnhancedSprite): """The sprite the player moves around to redirect the ball""" group = pygame.sprite.Group() def __init__(self, bottom): super().__init__(create_image(PADDLE_IMAGE, PADDLE_COLOR), self.group) self.bottom = bottom self.xmin = self.rect.width // 2 # Compute paddle x range. self.xmax = SCREEN_WIDTH - self.xmin def move(self, x): """Move to follow the cursor. Clamp to window bounds""" self.centerx = max(self.xmin, min(self.xmax, x)) class LifeCounter(): """Keep track of lives count. Display lives remaining using ball image""" def __init__(self, x, y, count=5): self.x, self.y = x, y self.image = create_image(BALL_IMAGE, BALL_COLOR) self.spacing = self.image.get_width() + 5 self.group = pygame.sprite.Group() self.reset(count) def reset(self, count): """Reset number of lives""" self.count = count for c in range(count - 1): EnhancedSprite(self.image, self.group).at(self.x + c * self.spacing, self.y) def __len__(self): """Return number of lives remaining""" return self.count def kill(self): """Reduce number of lives""" if self.count > 1: self.group.sprites()[-1].kill() self.count = max(0, self.count - 1) class Ball(EnhancedSprite): """Ball bounces around colliding with walls, paddles and bricks""" group = pygame.sprite.Group() def __init__(self, paddle, lives, speed=5): super().__init__(create_image(BALL_IMAGE, BALL_COLOR), self.group) self.paddle = paddle self.lives = lives self.speed = speed self.dx = self.dy = 0 self.xmax = SCREEN_WIDTH - self.rect.width self.ymax = paddle.bottom - self.rect.height self.reset(0) def reset(self, score=None): """Reset for a new game""" self.active = False if score is not None: self.score = score def start(self): """Start moving the ball in a random direction""" angle = random.random() - 0.5 # Launch angle limited to about +/-60 degrees self.dx = int(self.speed * math.sin(angle)) self.dy = -int(self.speed * math.cos(angle)) self.active = True def move(self): """Update the ball position. Check for collisions with bricks, walls and the paddle""" if not self.active: # Sit on top of the paddle self.centerx = self.paddle.centerx self.bottom = self.paddle.y - 2 return self # Did I hit some bricks? Update the bricks and the score x1, y1 = self.x, self.y x2, y2 = x1 + self.dx, y1 + self.dy if (xhits := pygame.sprite.spritecollide(self.at(x2, y1), Brick.group, False)): self.dx = -self.dx if (yhits := pygame.sprite.spritecollide(self.at(x1, y2), Brick.group, False)): self.dy = -self.dy if (hits := set(xhits) or set(yhits)): for brick in hits: self.score += brick.hit(self.score) # Did I hit a wall? if x2 <= 0 or x2 >= self.xmax: self.dx = -self.dx hits = True if y2 <= 0: self.dy = abs(self.dy) hits = True # Did I hit or get past the paddle? if y2 >= self.paddle.y: # Did it get past the paddle? if self.x > self.paddle.right or self.right < self.paddle.x: self.lives.kill() self.active = False else: # I hit the paddle. Compute angle of reflection bangle = math.atan2(-self.dx, self.dy) # Ball angle of approach pangle = math.atan2(self.centerx - self.paddle.centerx, 30) # Paddle angle rangle = (pangle - bangle) / 2 # Angle of reflection self.dx = math.sin(rangle) * self.speed self.dy = -math.cos(rangle) * self.speed hits = True if hits: self.at(x1, y1) else: self.at(x2, y2) def start_playlist(playlist): # Loading first audio file into our player pygame.mixer.music.load(playlist[0]) # Playing our music pygame.mixer.music.play() if len(playlist) > 1: playlist.pop(0) pygame.mixer.music.queue(playlist[0]) # setting up an end event which host an event # after the end of every song pygame.mixer.music.set_endevent(pygame.USEREVENT) # checking if any event has been # hosted at time of playing for event in pygame.event.get(): # A event will be hosted # after the end of every song if event.type == pygame.USEREVENT: if len(playlist) > 0: pygame.mixer.music.queue(playlist[0]) playlist.pop(0) if not pygame.mixer.music.get_busy(): break def main(playlist): """Play game until out of lives or out of bricks""" def displayText(text, font, pos=None, color=TEXT_COLOR): text = font.render(text, 1, color) if pos is None: pos = ((SCREEN_WIDTH - text.get_width()) // 2, (SCREEN_HEIGHT - text.get_height()) // 2) screen.blit(text, pos) screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("Breakout") clock = pygame.time.Clock() allsprites = pygame.sprite.Group() score_font = pygame.font.Font(None, 34) try: level = 1 lives = LifeCounter(10, SCREEN_HEIGHT - 30) paddle = Paddle(bottom=SCREEN_HEIGHT - 40) ball = Ball(paddle, lives) allsprites.add(paddle.group, lives.group, ball.group) while len(lives) > 0: # Start new board. Could have different layouts for each level for coord in BRICK_COORDS: Brick(*coord) allsprites.add(Brick.group) # Play until out of bricks or lives while len(lives) > 0 and len(Brick.group): print(playlist) start_playlist(playlist) clock.tick(60) for event in pygame.event.get(): if event.type == pygame.QUIT: raise SystemExit elif event.type == pygame.MOUSEMOTION: paddle.move(event.pos[0]) elif event.type == pygame.MOUSEBUTTONUP: if not ball.active: ball.start() ball.move() screen.blit(BACKGROUND_IMAGE, (0, 0)) displayText(f"Score: {ball.score}", font=score_font, pos=SCORE_POSITION) allsprites.draw(screen) pygame.display.flip() # Display results if len(lives) == 0: displayText("Game over", font=pygame.font.Font(None, 74)) elif len(Brick.group) == 0: level += 1 displayText(f"Level {level}", font=pygame.font.Font(None, 74)) ball.speed *= 1.25 ball.reset(ball.score) pygame.display.flip() pygame.time.wait(3000) finally: pygame.quit() if __name__ == "__main__": mainloop() main(playlist)