import sys import pygame from pygame import mixer from tetris.util import ConfigurationManager from tetris.util import TextGenerator from tetris.entity import PieceGenerator from tetris.entity import Well from tetris.entity import Stack from tetris.online import MultiplayerService from tetris.scene import TitleScene # TODO improve game assets https://www.spriters-resource.com/nes/tetris/ # TODO should be a singleton and refactor the whole file? class Game: def __init__(self): self.fps = -1 self.tile_size = -1 self.screen = None self.clock = None self.current_scene = TitleScene() # In Game # self.current_piece = None self.next_piece = None self.well = None self.stack = None self.main_music = None def initialize(self) -> None: pygame.init() TextGenerator.init(ConfigurationManager.get("image", "font"), (20, 20)) win_width = ConfigurationManager.get("window", "width") win_height = ConfigurationManager.get("window", "height") win_title = ConfigurationManager.get("window", "title") win_icon = ConfigurationManager.get("image", "window-icon") self.fps = ConfigurationManager.get("engine", "fps") self.tile_size = ConfigurationManager.get("engine", "tile-size") self.screen = pygame.display.set_mode((win_width, win_height)) self.clock = pygame.time.Clock() self.main_music = mixer.Channel(0) self.well = Well((280, 80), ConfigurationManager.get("color", "well-1"), ConfigurationManager.get("color", "well-border-1")) # TODO calculate position later and redo color config for well self.stack = Stack(ConfigurationManager.get("color", "stack-1"), ConfigurationManager.get("color", "stack-border-1")) self.score = 0 loaded_icon = pygame.image.load(win_icon) pygame.display.set_caption(win_title) pygame.display.set_icon(loaded_icon) main_music_file = ConfigurationManager.get("sound", "main-music") self.main_music.set_volume(0.7) # TODO add volume to the config self.main_music.play(mixer.Sound(main_music_file), -1) # gets called from the games main loop def update(self) -> None: if self.current_scene: self.current_scene.update() else: # TODO write not initialized exception elapsed_time = self.clock.tick(self.fps) if not self.next_piece: self.next_piece = PieceGenerator.get_piece((620, 160)) if self.current_piece: self.current_piece.update(elapsed_time, self) else: self.current_piece = self.next_piece self.current_piece.move((360 - 620, 100 - 160)) # TODO calculate spawn position correctly self.next_piece = PieceGenerator.get_piece((620, 160)) # (360, 100) if self.stack and self.current_piece.collide(self.stack): # TODO game over redo pygame.quit() MultiplayerService.quit() sys.exit() if self.stack: self.stack.update(elapsed_time, self) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() MultiplayerService.quit() sys.exit() def draw(self) -> None: # TODO write not initialized exception if self.current_scene: self.current_scene.draw(self.screen) else: # draw window bg bg_color = pygame.Color(ConfigurationManager.get("color", "window-bg")) self.screen.fill(bg_color) # draw all game objects if self.next_piece: self.next_piece.draw(self.screen) if self.well: self.well.draw(self.screen) if self.stack: self.stack.draw(self.screen) if self.current_piece: self.current_piece.draw(self.screen, self.well, self.stack) score = str(self.score).zfill(6) lines = str(self.stack.lines_completed_count).zfill(4) level = str(self.get_level()).zfill(2) TextGenerator.draw("Top", (80, 120), self.screen) TextGenerator.draw("000000", (80, 140), self.screen) TextGenerator.draw("Score", (80, 180), self.screen) TextGenerator.draw(score, (80, 200), self.screen) TextGenerator.draw("Lines " + lines, (300, 40), self.screen) TextGenerator.draw("Next", (600, 120), self.screen) TextGenerator.draw("LVL " + level, (600, 220), self.screen) # update display pygame.display.update() def get_level(self) -> int: lines_per_level = ConfigurationManager.get("engine", "lines-per-level") return 0 if not self.stack else self.stack.lines_completed_count // lines_per_level