3 Commits
0.2 ... 0.3

Author SHA1 Message Date
5b3e6ec931 fix setup.py 2019-10-03 21:34:55 +02:00
0970e1f6df V0.3 Release
New musics
Piece lock optimize
2019-10-03 21:33:39 +02:00
f48f1fc000 redefine consts in TetrArcade.py 2019-10-03 18:14:07 +02:00
16 changed files with 123 additions and 70 deletions

View File

@ -1,26 +1,42 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys import sys
import locale
import time
import os
import configparser
try: try:
import arcade import arcade
except ImportError as e: except ImportError as e:
sys.exit( sys.exit(
str(e) str(e) + """
+ """
This game require arcade library. This game require arcade library.
You can install it with: You can install it with:
python -m pip install --user arcade""" python -m pip install --user arcade"""
) )
import pyglet
from tetrislogic import TetrisLogic, Color, State import locale
import time
import os
import itertools
import configparser
from tetrislogic import TetrisLogic, Color, State, Coord
# Constants # Constants
# Matrix
NB_LINES = 20
NB_COLS = 10
NB_NEXT = 5
# Delays (seconds)
LOCK_DELAY = 0.5
FALL_DELAY = 1
AUTOREPEAT_DELAY = 0.300
AUTOREPEAT_PERIOD = 0.010
# Piece init coord
MATRIX_PIECE_COORD = Coord(4, NB_LINES)
NEXT_PIECE_COORDS = [Coord(NB_COLS + 4, NB_LINES - 4 * n - 3) for n in range(NB_NEXT)]
HELD_PIECE_COORD = Coord(-5, NB_LINES - 3)
# Window # Window
WINDOW_WIDTH = 800 WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600 WINDOW_HEIGHT = 600
@ -45,19 +61,19 @@ MINO_SPRITE_SIZE = 21
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
# The application is frozen # The application is frozen
DATA_DIR = os.path.dirname(sys.executable) PROGRAM_DIR = os.path.dirname(sys.executable)
else: else:
# The application is not frozen # The application is not frozen
# Change this bit to match where you store your data files: PROGRAM_DIR = os.path.dirname(__file__)
DATA_DIR = os.path.dirname(__file__) RESOURCES_DIR = os.path.join(PROGRAM_DIR, "resources")
DATA_DIR = os.path.join(DATA_DIR, "res")
# Sprites # Sprites
WINDOW_BG_PATH = os.path.join(DATA_DIR, "bg.jpg") IMAGES_DIR = os.path.join(RESOURCES_DIR, "images")
MATRIX_BG_PATH = os.path.join(DATA_DIR, "matrix.png") WINDOW_BG_PATH = os.path.join(IMAGES_DIR, "bg.jpg")
HELD_BG_PATH = os.path.join(DATA_DIR, "held.png") MATRIX_BG_PATH = os.path.join(IMAGES_DIR, "matrix.png")
NEXT_BG_PATH = os.path.join(DATA_DIR, "next.png") HELD_BG_PATH = os.path.join(IMAGES_DIR, "held.png")
MINOES_SPRITES_PATH = os.path.join(DATA_DIR, "minoes.png") NEXT_BG_PATH = os.path.join(IMAGES_DIR, "next.png")
MINOES_SPRITES_PATH = os.path.join(IMAGES_DIR, "minoes.png")
Color.PRELOCKED = 7 Color.PRELOCKED = 7
MINOES_COLOR_ID = { MINOES_COLOR_ID = {
Color.BLUE: 0, Color.BLUE: 0,
@ -74,6 +90,19 @@ TEXTURES = arcade.load_textures(
) )
TEXTURES = {color: TEXTURES[i] for color, i in MINOES_COLOR_ID.items()} TEXTURES = {color: TEXTURES[i] for color, i in MINOES_COLOR_ID.items()}
# Music
MUSIC_DIR = os.path.join(RESOURCES_DIR, "musics")
MUSICS_PATHS = (entry.path for entry in os.scandir(MUSIC_DIR))
# Text
TEXT_COLOR = arcade.color.BUBBLES
FONT_NAME = os.path.join(RESOURCES_DIR, "fonts/joystix monospace.ttf")
STATS_TEXT_MARGIN = 40
STATS_TEXT_SIZE = 14
STATS_TEXT_WIDTH = 150
HIGHLIGHT_TEXT_COLOR = arcade.color.BUBBLES
HIGHLIGHT_TEXT_SIZE = 20
# User profile path # User profile path
if sys.platform == "win32": if sys.platform == "win32":
USER_PROFILE_DIR = os.environ.get("appdata", os.path.expanduser("~\Appdata\Roaming")) USER_PROFILE_DIR = os.environ.get("appdata", os.path.expanduser("~\Appdata\Roaming"))
@ -83,20 +112,9 @@ USER_PROFILE_DIR = os.path.join(USER_PROFILE_DIR, "TetrArcade")
HIGH_SCORE_PATH = os.path.join(USER_PROFILE_DIR, ".high_score") HIGH_SCORE_PATH = os.path.join(USER_PROFILE_DIR, ".high_score")
CONF_PATH = os.path.join(USER_PROFILE_DIR, "TetrArcade.ini") CONF_PATH = os.path.join(USER_PROFILE_DIR, "TetrArcade.ini")
# Text
TEXT_COLOR = arcade.color.BUBBLES
FONT_NAME = os.path.join(DATA_DIR, "joystix monospace.ttf")
STATS_TEXT_MARGIN = 40
STATS_TEXT_SIZE = 14
STATS_TEXT_WIDTH = 150
HIGHLIGHT_TEXT_COLOR = arcade.color.BUBBLES
HIGHLIGHT_TEXT_SIZE = 20
# Music
MUSIC_PATH = os.path.join(DATA_DIR, "Tetris - Song A.mp3")
class MinoSprite(arcade.Sprite): class MinoSprite(arcade.Sprite):
def __init__(self, mino, window, alpha): def __init__(self, mino, window, alpha):
super().__init__() super().__init__()
self.alpha = alpha self.alpha = alpha
@ -114,6 +132,7 @@ class MinoSprite(arcade.Sprite):
class MinoesSprites(arcade.SpriteList): class MinoesSprites(arcade.SpriteList):
def resize(self, scale): def resize(self, scale):
for sprite in self: for sprite in self:
sprite.scale = scale sprite.scale = scale
@ -121,6 +140,7 @@ class MinoesSprites(arcade.SpriteList):
class TetrominoSprites(MinoesSprites): class TetrominoSprites(MinoesSprites):
def __init__(self, tetromino, window, alpha=NORMAL_ALPHA): def __init__(self, tetromino, window, alpha=NORMAL_ALPHA):
super().__init__() super().__init__()
self.tetromino = tetromino self.tetromino = tetromino
@ -136,6 +156,7 @@ class TetrominoSprites(MinoesSprites):
class MatrixSprites(MinoesSprites): class MatrixSprites(MinoesSprites):
def __init__(self, matrix): def __init__(self, matrix):
super().__init__() super().__init__()
self.matrix = matrix self.matrix = matrix
@ -146,10 +167,26 @@ class MatrixSprites(MinoesSprites):
for x, mino in enumerate(line): for x, mino in enumerate(line):
if mino: if mino:
mino.sprite.refresh(x, y) mino.sprite.refresh(x, y)
self.append(mino.sprite)
def remove_line(self, y):
for mino in self.matrix[y]:
if mino:
self.remove(mino.sprite)
class TetrArcade(TetrisLogic, arcade.Window): class TetrArcade(TetrisLogic, arcade.Window):
NB_LINES = NB_LINES
NB_COLS = NB_COLS
NB_NEXT = NB_NEXT
LOCK_DELAY = LOCK_DELAY
FALL_DELAY = FALL_DELAY
AUTOREPEAT_DELAY = AUTOREPEAT_DELAY
AUTOREPEAT_PERIOD = AUTOREPEAT_PERIOD
MATRIX_PIECE_COORD = MATRIX_PIECE_COORD
NEXT_PIECE_COORDS = NEXT_PIECE_COORDS
HELD_PIECE_COORD = HELD_PIECE_COORD
def __init__(self): def __init__(self):
locale.setlocale(locale.LC_ALL, "") locale.setlocale(locale.LC_ALL, "")
self.highlight_texts = [] self.highlight_texts = []
@ -188,9 +225,14 @@ class TetrArcade(TetrisLogic, arcade.Window):
self.next.bg.alpha = BAR_ALPHA self.next.bg.alpha = BAR_ALPHA
self.matrix.sprites = MatrixSprites(self.matrix) self.matrix.sprites = MatrixSprites(self.matrix)
self.on_resize(self.init_width, self.init_height) self.on_resize(self.init_width, self.init_height)
if self.play_music: if self.play_music:
self.music = arcade.Sound(MUSIC_PATH) self.music = pyglet.media.Player()
self.music_player = None playlist = itertools.cycle(
pyglet.media.load(path)
for path in MUSICS_PATHS
)
self.music.queue(playlist)
def new_conf(self): def new_conf(self):
self.conf["WINDOW"] = {"width": WINDOW_WIDTH, "height": WINDOW_HEIGHT, "fullscreen": False} self.conf["WINDOW"] = {"width": WINDOW_WIDTH, "height": WINDOW_HEIGHT, "fullscreen": False}
@ -277,13 +319,10 @@ AGAIN""".format(
def new_game(self): def new_game(self):
self.highlight_texts = [] self.highlight_texts = []
super().new_game() super().new_game()
self.matrix.sprites = MatrixSprites(self.matrix)
if self.play_music: if self.play_music:
if self.music_player: self.music.seek(0)
self.music_player.seek(0) self.music.play()
self.music_player.play()
else:
self.music_player = self.music.player.play()
self.music_player.loop = True
def new_tetromino(self): def new_tetromino(self):
tetromino = super().new_tetromino() tetromino = super().new_tetromino()
@ -291,7 +330,6 @@ AGAIN""".format(
return tetromino return tetromino
def new_matrix_piece(self): def new_matrix_piece(self):
self.matrix.sprites = MatrixSprites(self.matrix)
super().new_matrix_piece() super().new_matrix_piece()
self.matrix.ghost.sprites = TetrominoSprites(self.matrix.ghost, self, GHOST_ALPHA) self.matrix.ghost.sprites = TetrominoSprites(self.matrix.ghost, self, GHOST_ALPHA)
for tetromino in [self.matrix.piece, self.matrix.ghost] + self.next.pieces: for tetromino in [self.matrix.piece, self.matrix.ghost] + self.next.pieces:
@ -322,21 +360,31 @@ AGAIN""".format(
self.matrix.piece.prelocked = False self.matrix.piece.prelocked = False
self.matrix.piece.sprites.refresh() self.matrix.piece.sprites.refresh()
super().lock() super().lock()
self.matrix.sprites.refresh()
def enter_the_matrix(self):
super().enter_the_matrix()
for mino in self.matrix.piece:
self.matrix.sprites.append(mino.sprite)
def remove_line(self, y):
self.matrix.sprites.remove_line(y)
super().remove_line(y)
def pause(self): def pause(self):
super().pause() super().pause()
if self.play_music: if self.play_music:
self.music_player.pause() self.music.pause()
def resume(self): def resume(self):
super().resume() super().resume()
if self.play_music: if self.play_music:
self.music_player.play() self.music.play()
def game_over(self): def game_over(self):
super().game_over() super().game_over()
if self.play_music: if self.play_music:
self.music_player.pause() self.music.pause()
def on_key_press(self, key, modifiers): def on_key_press(self, key, modifiers):
for key_or_modifier in (key, modifiers): for key_or_modifier in (key, modifiers):
@ -521,7 +569,7 @@ High score could not be saved:
def on_close(self): def on_close(self):
self.save_high_score() self.save_high_score()
if self.play_music: if self.play_music:
self.music_player.pause() self.music.pause()
super().on_close() super().on_close()

View File

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 153 KiB

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 389 B

After

Width:  |  Height:  |  Size: 389 B

View File

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 475 B

BIN
resources/musics/2-!!!.mp3 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -29,13 +29,13 @@ options = {
"build_exe": { "build_exe": {
"packages": ["arcade", "pyglet"], "packages": ["arcade", "pyglet"],
"excludes": excludes, "excludes": excludes,
"include_files": "res", "include_files": "resources",
"silent": True "silent": True
} }
} }
setup( setup(
name = "TetrArcade", name = "TetrArcade",
version = "0.2", version = "0.3",
description = "Tetris clone", description = "Tetris clone",
author = "AdrienMalin", author = "AdrienMalin",
executables = [executable], executables = [executable],

View File

@ -11,6 +11,7 @@ game.rotate_clockwise()
game.rotate_counter() game.rotate_counter()
for i in range(12): for i in range(12):
game.soft_drop() game.soft_drop()
game.matrix.sprites.refresh()
game.on_draw() game.on_draw()
while game.state != State.OVER: while game.state != State.OVER:
game.hard_drop() game.hard_drop()

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .consts import NB_LINES, NB_COLS, NB_NEXT from .consts import NB_LINES, NB_COLS, NB_NEXT
from .utils import Movement, Rotation, Color from .utils import Movement, Rotation, Color, Coord
from .tetromino import Mino, Tetromino from .tetromino import Mino, Tetromino
from .tetrislogic import TetrisLogic, State, Matrix from .tetrislogic import TetrisLogic, State, Matrix

View File

@ -10,11 +10,10 @@ NB_NEXT = 5
# Delays (seconds) # Delays (seconds)
LOCK_DELAY = 0.5 LOCK_DELAY = 0.5
FALL_DELAY = 1 FALL_DELAY = 1
AUTOREPEAT_DELAY = 0.200 # Official : 0.300 AUTOREPEAT_DELAY = 0.300 # Official : 0.300 s
AUTOREPEAT_PERIOD = 0.010 # Official : 0.010 AUTOREPEAT_PERIOD = 0.010 # Official : 0.010 s
# Piece init coord # Piece init coord
CURRENT_COORD = Coord(4, NB_LINES) MATRIX_PIECE_COORD = Coord(4, NB_LINES)
NEXT_COORDS = [Coord(NB_COLS + 4, NB_LINES - 4 * n - 3) for n in range(NB_NEXT)] NEXT_PIECE_COORDS = [Coord(NB_COLS + 4, NB_LINES - 4 * n - 3) for n in range(NB_NEXT)]
HELD_COORD = Coord(-5, NB_LINES - 3) HELD_PIECE_COORD = Coord(-5, NB_LINES - 3)

View File

@ -12,9 +12,9 @@ from .consts import (
FALL_DELAY, FALL_DELAY,
AUTOREPEAT_DELAY, AUTOREPEAT_DELAY,
AUTOREPEAT_PERIOD, AUTOREPEAT_PERIOD,
CURRENT_COORD, MATRIX_PIECE_COORD,
NEXT_COORDS, NEXT_PIECE_COORDS,
HELD_COORD, HELD_PIECE_COORD,
) )
@ -66,9 +66,9 @@ class TetrisLogic:
FALL_DELAY = FALL_DELAY FALL_DELAY = FALL_DELAY
AUTOREPEAT_DELAY = AUTOREPEAT_DELAY AUTOREPEAT_DELAY = AUTOREPEAT_DELAY
AUTOREPEAT_PERIOD = AUTOREPEAT_PERIOD AUTOREPEAT_PERIOD = AUTOREPEAT_PERIOD
CURRENT_COORD = CURRENT_COORD MATRIX_PIECE_COORD = MATRIX_PIECE_COORD
NEXT_COORDS = NEXT_COORDS NEXT_PIECE_COORDS = NEXT_PIECE_COORDS
HELD_COORD = HELD_COORD HELD_PIECE_COORD = HELD_PIECE_COORD
random_bag = [] random_bag = []
def __init__(self): def __init__(self):
@ -138,12 +138,12 @@ class TetrisLogic:
def new_matrix_piece(self): def new_matrix_piece(self):
self.matrix.piece = self.next.pieces.pop(0) self.matrix.piece = self.next.pieces.pop(0)
self.matrix.piece.coord = self.CURRENT_COORD self.matrix.piece.coord = self.MATRIX_PIECE_COORD
self.matrix.ghost = self.matrix.piece.ghost() self.matrix.ghost = self.matrix.piece.ghost()
self.move_ghost() self.move_ghost()
self.next.pieces.append(self.new_tetromino()) self.next.pieces.append(self.new_tetromino())
self.next.pieces[-1].coord = self.NEXT_COORDS[-1] self.next.pieces[-1].coord = self.NEXT_PIECE_COORDS[-1]
for tetromino, coord in zip(self.next.pieces, self.NEXT_COORDS): for tetromino, coord in zip(self.next.pieces, self.NEXT_PIECE_COORDS):
tetromino.coord = coord tetromino.coord = coord
if not self.can_move(self.matrix.piece.coord, (mino.coord for mino in self.matrix.piece)): if not self.can_move(self.matrix.piece.coord, (mino.coord for mino in self.matrix.piece)):
@ -255,18 +255,14 @@ class TetrisLogic:
else: else:
t_spin = T_Spin.NONE t_spin = T_Spin.NONE
for mino in self.matrix.piece: self.enter_the_matrix()
coord = mino.coord + self.matrix.piece.coord
del mino.coord
if coord.y <= self.NB_LINES + 3:
self.matrix[coord.y][coord.x] = mino
# Clear complete lines # Clear complete lines
nb_lines_cleared = 0 nb_lines_cleared = 0
for y, line in reversed(list(enumerate(self.matrix))): for y, line in reversed(list(enumerate(self.matrix))):
if all(mino for mino in line): if all(mino for mino in line):
nb_lines_cleared += 1 nb_lines_cleared += 1
self.matrix.pop(y) self.remove_line(y)
self.append_new_line_to_matrix() self.append_new_line_to_matrix()
if nb_lines_cleared: if nb_lines_cleared:
self.nb_lines_cleared += nb_lines_cleared self.nb_lines_cleared += nb_lines_cleared
@ -303,6 +299,15 @@ class TetrisLogic:
else: else:
self.new_matrix_piece() self.new_matrix_piece()
def enter_the_matrix(self):
for mino in self.matrix.piece:
coord = mino.coord + self.matrix.piece.coord
if coord.y <= self.NB_LINES + 3:
self.matrix[coord.y][coord.x] = mino
def remove_line(self, y):
self.matrix.pop(y)
def can_move(self, potential_coord, minoes_coords): def can_move(self, potential_coord, minoes_coords):
return all(self.matrix.cell_is_free(potential_coord + mino_coord) for mino_coord in minoes_coords) return all(self.matrix.cell_is_free(potential_coord + mino_coord) for mino_coord in minoes_coords)
@ -318,14 +323,14 @@ class TetrisLogic:
self.matrix.piece.prelocked = False self.matrix.piece.prelocked = False
self.stop(self.lock) self.stop(self.lock)
self.matrix.piece, self.held.piece = self.held.piece, self.matrix.piece self.matrix.piece, self.held.piece = self.held.piece, self.matrix.piece
self.held.piece.coord = self.HELD_COORD self.held.piece.coord = self.HELD_PIECE_COORD
if type(self.held.piece) == I_Tetrimino: if type(self.held.piece) == I_Tetrimino:
self.held.piece.coord += Movement.LEFT self.held.piece.coord += Movement.LEFT
for mino, coord in zip(self.held.piece, self.held.piece.MINOES_COORDS): for mino, coord in zip(self.held.piece, self.held.piece.MINOES_COORDS):
mino.coord = coord mino.coord = coord
if self.matrix.piece: if self.matrix.piece:
self.matrix.piece.coord = self.CURRENT_COORD self.matrix.piece.coord = self.MATRIX_PIECE_COORD
self.matrix.ghost = self.matrix.piece.ghost() self.matrix.ghost = self.matrix.piece.ghost()
self.move_ghost() self.move_ghost()
else: else: