import sys from typing import Text import pygame from pygame import mixer from tetris.util import ConfigurationManager from tetris.util import TextGenerator from tetris.util import Controller from tetris.entity import PieceGenerator from tetris.entity import Well from tetris.entity import Stack # 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.main_music = None self.current_piece = None self.well = None self.stack = None def initialize(self) -> None: pygame.init() TextGenerator.load(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: # TODO write not initialized exception elapsed_time = self.clock.tick(self.fps) if self.current_piece: self.current_piece.update(elapsed_time, self) else: self.current_piece = PieceGenerator.get_piece((360, 100)) # TODO calculate spawn position if self.stack and self.current_piece.collide(self.stack): # TODO game over redo pygame.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() sys.exit() def draw(self) -> None: # TODO write not initialized exception # draw window bg bg_color = pygame.Color(ConfigurationManager.get("color", "window-bg")) self.screen.fill(bg_color) # draw all game objects 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