diff --git a/pyproject.toml b/pyproject.toml index 32e3346..1a05182 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ module = 'slacker_game' author = 'Nguyễn Gia Phong' author-email = 'mcsinyx@disroot.org' home-page = 'https://git.disroot.org/McSinyx/slacker-game' -requires = ['pygame'] +requires = ['pygame>=2.0.0.dev8'] description-file = 'README.rst' classifiers = [ 'Development Status :: 4 - Beta', diff --git a/slacker_game/__init__.py b/slacker_game/__init__.py index ad65717..2d06f48 100644 --- a/slacker_game/__init__.py +++ b/slacker_game/__init__.py @@ -25,12 +25,14 @@ from importlib.resources import path from io import StringIO from math import cos, pi from random import randrange +from typing import List, Optional with redirect_stdout(StringIO()): import pygame from pygame import (K_0, K_1, K_9, K_ESCAPE, K_SPACE, KEYDOWN, QUIT, K_q, Rect, draw, event, image) from pygame.display import flip, set_caption, set_icon, set_mode from pygame.font import Font +from pygame.surface import Surface from pygame.time import get_ticks TANGO = {'Butter': ((252, 233, 79), (237, 212, 0), (196, 160, 0)), @@ -66,7 +68,9 @@ class SlackerTile: Slacker object for storing tiles. """ - def __init__(self, screen, x, y, state=1, missed_time=None): + def __init__(self, screen: Surface, + x: float, y: float, state: int = PLAYING, + missed_time: Optional[int] = None) -> None: self.screen, self.x, self.y = screen, x, y if state == LOSE: self.dim = 1 @@ -77,23 +81,23 @@ class SlackerTile: self.missed_time = missed_time self.wiggle = state in (INTRO, WIN) - def get_xoffset(self, maxoffset, duration=820): + def get_xoffset(self, maxoffset: float, duration: int = 820) -> float: """Return the offset on x-axis to make the tile complete an cycle of wiggling oscillation in given duration (in milliseconds). """ if not self.wiggle: return 0 return maxoffset * cos((get_ticks()/duration+self.y/BOARD_HEIGHT)*pi) - def get_yoffset(self): + def get_yoffset(self) -> float: """Return the offset on y-axis when the tile is falling.""" if self.missed_time is None: return 0 - return (get_ticks() - self.missed_time)**2 / 25000 + return (get_ticks()-self.missed_time)**2 / 25000 - def isfallen(self): + def isfallen(self) -> bool: """Return if the tile has fallen off the screen.""" return self.y + self.get_yoffset() > BOARD_HEIGHT - def draw(self, max_x_offset=2): + def draw(self, max_x_offset: float = 2.0) -> None: """Draw the tile.""" if self.y < MAJOR: color = COLOR_MAJOR @@ -103,7 +107,7 @@ class SlackerTile: (self.y+self.get_yoffset())*TILE_SIZE, TILE_SIZE, TILE_SIZE) draw.rect(self.screen, color[self.dim], rect) - draw.rect(self.screen, BG_COLOR, rect, TILE_SIZE // 11) + draw.rect(self.screen, BG_COLOR, rect, TILE_SIZE//11) class Slacker: @@ -111,42 +115,41 @@ class Slacker: the popular arcade game Stacker. """ - def __init__(self, restart=False): + def __init__(self, restart: bool = False) -> None: self.exit_stack = ExitStack() self.font = self.data('VT323-Regular.ttf') - self.board = [[False]*BOARD_WIDTH - for _ in range(BOARD_HEIGHT)] + self.board = [[False]*BOARD_WIDTH for h in range(BOARD_HEIGHT)] self.game_state = PLAYING if restart else INTRO - self.falling_tiles = [] + self.falling_tiles: List[SlackerTile] = [] self.speed = INIT_SPEED + randrange(5) self.speed_ratio = 1.0 self.width = MAX_WIDTH[-1] self.y = BOARD_HEIGHT - 1 - def __enter__(self): + def __enter__(self) -> Slacker: pygame.init() set_caption('Slacker') set_icon(image.load(self.data('icon.png'))) self.screen = set_mode(SCREEN_SIZE) return self - def __exit__(self, *exc): + def __exit__(self, *exc) -> None: pygame.quit() self.exit_stack.close() - def data(self, resource): + def data(self, resource: str) -> str: """Return a true filesystem path for specified resource.""" return str(self.exit_stack.enter_context( path('slacker_game', resource))) - def draw_text(self, string, height): + def draw_text(self, string: str, height: float): """Width-fit the string in the screen on the given height.""" font = Font(self.font, int(SCREEN_WIDTH*2.5/(len(string)+1))) text = font.render(string, False, COLOR_MINOR[0]) self.screen.blit(text, ((SCREEN_WIDTH - text.get_width()) // 2, int(SCREEN_HEIGHT * height))) - def intro(self): + def intro(self) -> None: """Draw the intro screen.""" for i in [(2, 2), (3, 2), (4, 2), (1.5, 3), (4.5, 3), (1.5, 4), (2, 5), (3, 5), (4, 5), (4.5, 6), @@ -155,7 +158,7 @@ class Slacker: if get_ticks() // 820 % 2: self.draw_text('Press Spacebar', 0.75) - def draw_board(self): + def draw_board(self) -> None: """Draw the board and the tiles inside.""" for y, row in enumerate(self.board): for x, block in enumerate(row): @@ -169,7 +172,7 @@ class Slacker: else: ft.draw() - def update_screen(self): + def update_screen(self) -> None: """Draw the whole screen and everything inside.""" self.screen.fill(BG_COLOR) if self.game_state == INTRO: @@ -178,7 +181,7 @@ class Slacker: self.draw_board() flip() - def update_movement(self): + def update_movement(self) -> None: """Update the direction the blocks are moving in.""" speed = self.speed * self.speed_ratio positions = BOARD_WIDTH + self.width - 2 @@ -187,7 +190,7 @@ class Slacker: self.board[self.y] = [0 <= x - self.x < self.width for x in range(BOARD_WIDTH)] - def key_hit(self): + def key_hit(self) -> None: """Process the current position of the blocks relatively to the ones underneath when user hit the switch, then decide if the user will win, lose or go to the next level of the tower. @@ -212,7 +215,7 @@ class Slacker: self.width = min(self.width, MAX_WIDTH[self.y]) self.speed = MAX_SPEED + self.y*SPEED_DIFF + randrange(5) - def handle_intro(self): + def handle_intro(self) -> bool: """Handle events in intro.""" for e in event.get(): if e.type == QUIT: return False @@ -221,7 +224,7 @@ class Slacker: if e.key == K_SPACE: self.game_state = PLAYING return True - def handle_playing(self): + def handle_playing(self) -> bool: """Handle events in game.""" for e in event.get(): if e.type == QUIT: return False @@ -229,7 +232,7 @@ class Slacker: if e.key == K_SPACE: self.key_hit() elif e.key in (K_ESCAPE, K_q): - self.__init__() + Slacker.__init__(self) # Yes, these are cheats. elif e.key == K_0: self.width += self.width < BOARD_WIDTH @@ -238,14 +241,14 @@ class Slacker: self.update_movement() return True - def handle_ending(self): + def handle_ending(self) -> bool: """Handle events in ending screens.""" for e in event.get(): if e.type == QUIT: return False - if e.type == KEYDOWN: self.__init__(restart=True) + if e.type == KEYDOWN: Slacker.__init__(self, restart=True) return True - def handle_events(self): + def handle_events(self) -> bool: """Handle queued events.""" if self.game_state == INTRO: return self.handle_intro() if self.game_state == PLAYING: return self.handle_playing() diff --git a/slacker_game/__main__.py b/slacker_game/__main__.py index 2754e31..e53776c 100644 --- a/slacker_game/__main__.py +++ b/slacker_game/__main__.py @@ -1,7 +1,7 @@ from slacker_game import Slacker -def main(): +def main() -> None: """Run game.""" with Slacker() as slacker: for i in iter(slacker.handle_events, False): diff --git a/tox.ini b/tox.ini index 8c37921..d000d25 100644 --- a/tox.ini +++ b/tox.ini @@ -7,9 +7,11 @@ isolated_build = True deps = flake8-builtins isort + mypy commands = flake8 isort . --check --diff + mypy slacker_game [flake8] ignore = E226, E701, E704, W503