This commit is contained in:
adrienmalin 2019-09-28 05:06:59 +02:00
parent 30e5bf30c3
commit 9ca1233027
2 changed files with 118 additions and 86 deletions

View File

@ -13,7 +13,7 @@ python -m pip install --user arcade
"""
)
from tetris import Tetris, Status
from tetris import Tetris, Status, Scheduler
# Constants
@ -35,6 +35,10 @@ TEXT_MARGIN = 40
FONT_SIZE = 10
HIGHLIGHT_TEXT_FONT_SIZE = 20
TEXT_HEIGHT = 13.2
START_TEXT = """PRESS
[ENTER]
TO
START"""
STATS_TEXT = """SCORE
HIGH SCORE
TIME
@ -89,14 +93,40 @@ GHOST_ALPHA = 50
MATRIX_SRITE_ALPHA = 100
class ArcadeScheduler(Scheduler):
def __init__(self):
self._tasks = {}
def start(self, task, period):
def _task(delta_time):
task()
self._tasks[task] = _task
arcade.schedule(_task, period)
def stop(self, task):
try:
_task = self._tasks[task]
except KeyError:
pass
else:
arcade.unschedule(_task)
del self._tasks[task]
class TetrArcade(Tetris, arcade.Window):
scheduler = ArcadeScheduler()
def __init__(self):
super().__init__()
locale.setlocale(locale.LC_ALL, '')
self.actions = {
Status.STARTING: {
arcade.key.ENTER: self.new_game
},
Status.PLAYING: {
arcade.key.LEFT: self.move_left,
arcade.key.NUM_4: self.move_left,
@ -171,7 +201,7 @@ class TetrArcade(Tetris, arcade.Window):
self.reload_matrix()
if self.pressed_actions:
self.stop_autorepeat()
arcade.schedule(self.repeat_action, AUTOREPEAT_DELAY)
self.scheduler.start(self.repeat_action, AUTOREPEAT_DELAY)
def lock(self, _=0):
super().lock()
@ -191,7 +221,7 @@ class TetrArcade(Tetris, arcade.Window):
def game_over(self):
super().game_over()
self.unschedule(self.repeat_action)
self.scheduler.stop(self.repeat_action)
def on_key_press(self, key, modifiers):
for key_or_modifier in (key, modifiers):
@ -204,7 +234,7 @@ class TetrArcade(Tetris, arcade.Window):
if action in self.autorepeatable_actions:
self.stop_autorepeat()
self.pressed_actions.append(action)
arcade.schedule(self.repeat_action, AUTOREPEAT_DELAY)
self.scheduler.start(self.repeat_action, AUTOREPEAT_DELAY)
def on_key_release(self, key, modifiers):
try:
@ -220,31 +250,32 @@ class TetrArcade(Tetris, arcade.Window):
else:
if not self.pressed_actions:
self.stop_autorepeat()
arcade.schedule(self.repeat_action, AUTOREPEAT_DELAY)
self.scheduler.start(self.repeat_action, AUTOREPEAT_DELAY)
def repeat_action(self, delta_time=0):
def repeat_action(self, _=0):
if self.pressed_actions:
self.pressed_actions[-1]()
if not self.auto_repeat:
self.auto_repeat = True
arcade.unschedule(self.repeat_action)
arcade.schedule(self.repeat_action, AUTOREPEAT_INTERVAL)
self.scheduler.stop(self.repeat_action)
self.scheduler.start(self.repeat_action, AUTOREPEAT_INTERVAL)
else:
self.auto_repeat = False
arcade.unschedule(self.repeat_action)
self.scheduler.stop(self.repeat_action)
def stop_autorepeat(self):
self.auto_repeat = False
self.unschedule(self.repeat_action)
self.scheduler.stop(self.repeat_action)
def show_text(self, text):
self.highlight_texts.append(text)
self.schedule(self.del_highlight_text, HIGHLIGHT_TEXT_DISPLAY_DELAY)
self.scheduler.start(self.del_highlight_text, HIGHLIGHT_TEXT_DISPLAY_DELAY)
def del_highlight_text(self, _=0):
self.highlight_texts.pop(0)
if not self.highlight_texts:
self.unschedule(self.del_highlight_text)
def del_highlight_text(self):
if self.highlight_texts:
self.highlight_texts.pop(0)
else:
self.scheduler.stop(self.del_highlight_text)
def reload_piece(self, piece):
piece_sprites = arcade.SpriteList()
@ -296,8 +327,9 @@ class TetrArcade(Tetris, arcade.Window):
def on_draw(self):
arcade.start_render()
self.bg_sprite.draw()
self.matrix_sprite.draw()
if not self.status == Status.PAUSED:
if self.status in (Status.PLAYING, Status.OVER):
self.matrix_sprite.draw()
self.matrix_minoes_sprites.draw()
self.update_piece(self.held_piece, self.held_piece_sprites)
@ -324,34 +356,36 @@ class TetrArcade(Tetris, arcade.Window):
mino_sprite.bottom = self.matrix_sprite.bottom + mino_position.y*(mino_sprite.height-1)
self.next_pieces_sprites.draw()
arcade.render_text(
self.general_text,
self.matrix_sprite.left - TEXT_MARGIN,
self.matrix_sprite.bottom
)
t = time.localtime(self.time)
for y, text in enumerate(
(
"{:n}".format(self.nb_lines),
"{:n}".format(self.goal),
"{:n}".format(self.level),
"{:02d}:{:02d}:{:02d}".format(t.tm_hour-1, t.tm_min, t.tm_sec),
"{:n}".format(self.high_score),
"{:n}".format(self.score)
),
start=14
):
arcade.draw_text(
text = text,
start_x = self.matrix_sprite.left - TEXT_MARGIN,
start_y = self.matrix_sprite.bottom + y*TEXT_HEIGHT,
color = TEXT_COLOR,
font_size = FONT_SIZE,
align = 'right',
font_name = FONT_NAME,
anchor_x = 'right'
arcade.render_text(
self.general_text,
self.matrix_sprite.left - TEXT_MARGIN,
self.matrix_sprite.bottom
)
t = time.localtime(self.time)
for y, text in enumerate(
(
"{:n}".format(self.nb_lines),
"{:n}".format(self.goal),
"{:n}".format(self.level),
"{:02d}:{:02d}:{:02d}".format(t.tm_hour-1, t.tm_min, t.tm_sec),
"{:n}".format(self.high_score),
"{:n}".format(self.score)
),
start=14
):
arcade.draw_text(
text = text,
start_x = self.matrix_sprite.left - TEXT_MARGIN,
start_y = self.matrix_sprite.bottom + y*TEXT_HEIGHT,
color = TEXT_COLOR,
font_size = FONT_SIZE,
align = 'right',
font_name = FONT_NAME,
anchor_x = 'right'
)
highlight_text = {
Status.STARTING: START_TEXT,
Status.PLAYING: self.highlight_texts[0] if self.highlight_texts else "",
Status.PAUSED: PAUSE_TEXT,
Status.OVER: GAME_OVER_TEXT
@ -380,16 +414,9 @@ class TetrArcade(Tetris, arcade.Window):
self.matrix_sprite.top = int(self.matrix_sprite.top)
self.reload_matrix()
def schedule(self, task, period):
arcade.schedule(task, period)
def unschedule(self, task):
arcade.unschedule(task)
def main():
tetrarcade = TetrArcade()
tetrarcade.new_game()
TetrArcade()
arcade.run()
if __name__ == "__main__":

View File

@ -25,10 +25,10 @@ class Coord:
# Piece init position
MATRIX_PIECE_INIT_POSITION = Coord(4, NB_LINES)
NEXT_PIECES_POSITIONS = [
Coord(NB_COLS+3, NB_LINES-4*n-3)
Coord(NB_COLS+6, NB_LINES-4*n-3)
for n in range(NB_NEXT_PIECES)
]
HELD_PIECE_POSITION = Coord(-4, NB_LINES-3)
HELD_PIECE_POSITION = Coord(-7, NB_LINES-3)
HELD_I_POSITION = Coord(-5, NB_LINES-3)
@ -167,8 +167,18 @@ class Tetromino:
return cls.random_bag.pop()()
class Scheduler:
def start(task, period):
raise NotImplementedError
def stop(self, task):
raise NotImplementedError
class Tetris():
T_SLOT = (Coord(-1, 1), Coord(1, 1), Coord(1, -1), Coord(-1, -1))
SCORES = (
{"name": "", T_Spin.NO_T_SPIN: 0, T_Spin.MINI_T_SPIN: 1, T_Spin.T_SPIN: 4},
@ -177,6 +187,7 @@ class Tetris():
{"name": "TRIPLE", T_Spin.NO_T_SPIN: 5, T_Spin.T_SPIN: 16},
{"name": "TETRIS", T_Spin.NO_T_SPIN: 8}
)
scheduler = Scheduler()
def __init__(self):
self.high_score = 0
@ -205,7 +216,7 @@ class Tetris():
self.current_piece = None
self.held_piece = None
self.status = Status.PLAYING
self.schedule(self.clock, 1)
self.scheduler.start(self.clock, 1)
self.new_level()
def new_level(self):
@ -216,7 +227,7 @@ class Tetris():
if self.level > 15:
self.lock_delay = 0.5 * pow(0.9, self.level-15)
self.show_text("Level\n{:n}".format(self.level))
self.schedule(self.drop, self.fall_delay)
self.scheduler.start(self.drop, self.fall_delay)
self.new_current_piece()
def new_current_piece(self):
@ -250,8 +261,8 @@ class Tetris():
potential_position = self.current_piece.position + movement
if self.can_move(potential_position, self.current_piece.minoes_positions):
if self.current_piece.prelocked:
self.unschedule(self.lock)
self.schedule(self.lock, self.lock_delay)
self.scheduler.stop(self.lock)
self.scheduler.start(self.lock, self.lock_delay)
self.current_piece.position = potential_position
self.current_piece.last_rotation_point_used = None
self.move_ghost()
@ -262,13 +273,13 @@ class Tetris():
and movement == Movement.DOWN
):
self.current_piece.prelocked = True
self.schedule(self.lock, self.lock_delay)
self.scheduler.start(self.lock, self.lock_delay)
return False
def move_left(self, delta_time=0):
def move_left(self):
self.move(Movement.LEFT)
def move_right(self, delta_time=0):
def move_right(self):
self.move(Movement.RIGHT)
def rotate(self, direction):
@ -283,8 +294,8 @@ class Tetris():
potential_position = self.current_piece.position + liberty_degree
if self.can_move(potential_position, rotated_minoes_positions):
if self.current_piece.prelocked:
self.unschedule(self.lock)
self.schedule(self.lock, self.lock_delay)
self.scheduler.stop(self.lock)
self.scheduler.start(self.lock, self.lock_delay)
self.current_piece.position = potential_position
self.current_piece.minoes_positions = rotated_minoes_positions
self.current_piece.orientation = (
@ -296,10 +307,10 @@ class Tetris():
else:
return False
def rotate_counterclockwise(self, delta_time=0):
def rotate_counterclockwise(self):
self.rotate(Rotation.COUNTERCLOCKWISE)
def rotate_clockwise(self, delta_time=0):
def rotate_clockwise(self):
self.rotate(Rotation.CLOCKWISE)
def move_ghost(self):
@ -311,7 +322,7 @@ class Tetris():
):
self.ghost_piece.position += Movement.DOWN
def drop(self, _=0):
def drop(self):
self.move(Movement.DOWN)
def add_to_score(self, ds):
@ -335,6 +346,9 @@ class Tetris():
if self.move(Movement.DOWN):
return
self.current_piece.prelocked = False
self.scheduler.stop(self.lock)
if all(
(mino_position + self.current_piece.position).y >= NB_LINES
for mino_position in self.current_piece.minoes_positions
@ -342,8 +356,6 @@ class Tetris():
self.game_over()
return
self.unschedule(self.lock)
for mino_position in self.current_piece.minoes_positions:
position = mino_position + self.current_piece.position
if position.y <= NB_LINES+3:
@ -409,7 +421,7 @@ class Tetris():
self.add_to_score(lock_score)
if self.goal <= 0:
self.unschedule(self.drop)
self.scheduler.stop(self.drop)
self.new_level()
else:
self.new_current_piece()
@ -418,7 +430,7 @@ class Tetris():
if self.current_piece.hold_enabled:
self.current_piece.hold_enabled = False
self.current_piece.prelocked = False
self.unschedule(self.lock)
self.scheduler.stop(self.lock)
self.current_piece, self.held_piece = self.held_piece, self.current_piece
if self.held_piece.__class__ == Tetromino.I:
self.held_piece.position = HELD_I_POSITION
@ -432,35 +444,28 @@ class Tetris():
else:
self.new_current_piece()
def pause(self, _=0):
def pause(self):
self.status = Status.PAUSED
self.unschedule(self.drop)
self.unschedule(self.lock)
self.unschedule(self.clock)
self.scheduler.stop(self.drop)
self.scheduler.stop(self.lock)
self.scheduler.stop(self.clock)
self.pressed_actions = []
self.stop_autorepeat()
def resume(self, delta_time=0):
def resume(self):
self.status = Status.PLAYING
self.schedule(self.drop, self.fall_delay)
self.scheduler.start(self.drop, self.fall_delay)
if self.current_piece.prelocked:
self.schedule(self.lock, self.lock_delay)
self.schedule(self.clock, 1)
self.scheduler.start(self.lock, self.lock_delay)
self.scheduler.start(self.clock, 1)
def clock(self, delta_time=1):
self.time += delta_time
def game_over(self):
self.status = Status.OVER
self.unschedule(self.lock)
self.unschedule(self.drop)
self.unschedule(self.clock)
def schedule(task, period):
raise NotImplementedError
def unschedule(self, task):
raise NotImplementedError
self.scheduler.stop(self.drop)
self.scheduler.stop(self.clock)
def show_text(self, text):
print(text)