from typing import Any import pygame as pg from .settings import * class App: def __init__(self) -> None: from .tetris import Tetris # TODO: dynamic timeout self.fall_timeout: Generator[int, Any, Any] = FALL_TIMEOUT_GENERATOR self.paused = False pg.init() pg.display.set_caption(CAPTION) self.init_event_timer() self.screen = pg.display.set_mode(FIELD_RES) self.clock = pg.time.Clock() self.tetris = Tetris(self) def init_event_timer(self): # when timeout, set trigger to true to make tetromino fall self.fall_trigger = False self.fall_event = pg.USEREVENT pg.time.set_timer(self.fall_event, next(self.fall_timeout)) def update(self): self.tetris.update() self.clock.tick(FPS) def draw(self): ''' main app frame drawer. This method only run once. draw app background color draw tetris grids ''' self.screen.fill(color=FIELD_COLOR, rect=(0, 0, *FIELD_RES)) self.tetris.draw() # draw grid pg.display.flip() def check_events(self): ''' Main event loop. ''' self.fall_trigger = False # fall_event set in set_event_timer for event in pg.event.get(): if event.type == pg.QUIT or ( event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE or event.type == pg.KEYDOWN and event.key == pg.K_c and pg.key.get_mods() & pg.KMOD_CTRL ): # handle ctrl+c, https://stackoverflow.com/a/46506753/20419707 pg.quit() exit() elif event.type == pg.KEYDOWN: if event.key == pg.K_p: self.paused = not self.paused elif not self.paused: self.tetris.control(event.key) elif event.type == self.fall_event and not self.paused: self.fall_trigger = True pg.time.set_timer(self.fall_event, next(self.fall_timeout)) def run(self): ''' Main loop. ''' while True: self.check_events() self.update() self.draw()