Tryb nocny
Rezultat i kod źródłowy gry imitującej Tetrisa
Ta część strony została oznaczona, jakoby była w trakcie konstrukcji. To oznacza, że treść w miejscu tego komunikatu zostanie uzupełniona w najbliższym czasie.
python
from enum import Enum
import random
import copy
class TetrisTileKind(Enum):
EMPTY = ' '
RED = 'R'
YELLOW = 'Y'
GREEN = 'G'
class TetrisTile:
def __init__(self):
self.kind = TetrisTileKind.EMPTY
class TetrisStructureKind(Enum):
L1 = [[True, False],
[True, False],
[True, True]]
L2 = [
[False, False, True],
[True, True, True]]
L3 = [
[True, True],
[False, True],
[False, True]]
L4 = [
[True, True, True],
[True, False, False]]
I1 = [[True, True, True]]
I2 = [[True], [True], [True]]
Sq = [[True, True],
[True, True]]
class TetrisBoard:
def __init__(self):
self.width = 8
self.height = 12
self.resetState()
def resetState(self):
self.state = [[TetrisTile()
for _ in range(self.width)] for _ in range(self.height)]
def is_empty_at(self, row, column):
return row < 0 or column < 0 or row >= self.height or column >= self.width or self.state[row][column].kind.name == "EMPTY"
class TetrisStructure:
def __init__(self, **kwargs):
board_width = kwargs["board_width"]
self.kind = random.choice(list(TetrisTileKind)[1:])
self.structure_kind = random.choice(list(TetrisStructureKind))
self.pos_row = self.height() * (-1)
self.pos_col = int(board_width / 2) - \
int(self.width() / 2)
def is_overlap(self, board, offset_row_col=(0, 0)):
shape = self.structure_kind.value
for i in range(len(shape)):
for j in range(len(shape[0])):
if shape[i][j] and not board.is_empty_at(i+offset_row_col[0]+self.pos_row, j+offset_row_col[1]+self.pos_col):
return True
return False
def is_colliding_bottom(self, board):
return self.pos_row >= board.height-len(self.structure_kind.value) or self.is_overlap(board, (1, 0))
def is_colliding_left(self, board):
return self.pos_col <= 0 or self.is_overlap(board, (0, -1))
def is_colliding_right(self, board):
return self.pos_col >= board.width - len(self.structure_kind.value[0]) or self.is_overlap(board, (0, 1))
def write_to_board(self, board):
shape = self.structure_kind.value
for i in range(len(shape)):
for j in range(len(shape[0])):
if shape[i][j] and (i+self.pos_row) >= 0:
board.state[i+self.pos_row][j +
self.pos_col].kind = self.kind
def width(self):
return len(self.structure_kind.value[0])
def height(self):
return len(self.structure_kind.value)
kindRotationMap = {
"L1": "L2",
"L2": "L3",
"L3": "L4",
"L4": "L1",
"Sq": "Sq",
"I1": "I2",
"I2": "I1"
}
class TetrisEventKind(Enum):
Void = 0
Updated = 1
LevelFinished = 2
def is_row_filled(row):
for col in row:
if col.kind.name == "EMPTY":
return False
return True
class Tetris:
def __init__(self):
# Wypełniamy bufor board pustymi blokami
self.board = TetrisBoard()
self.dropping_structure = None
self.update_task_check_winning = False
self.is_finished = False
self.score = 0
def update(self):
if self.is_finished:
return
if self.update_task_check_winning:
self.delete_winning_rows()
self.update_task_check_winning = False
return
if self.dropping_structure is None:
self.dropping_structure = TetrisStructure(
board_width=self.board.width)
if self.dropping_structure.is_overlap(self.board) or self.dropping_structure.is_colliding_bottom(self.board):
self.is_finished = True
return
self.go_down()
self.check_and_write_dropping_structure()
def check_and_write_dropping_structure(self):
if self.dropping_structure is not None and self.dropping_structure.is_colliding_bottom(self.board):
self.dropping_structure.write_to_board(self.board)
self.dropping_structure = None
self.update_task_check_winning = True
if random.choice([True, False]):
self.score += 1
elif random.choice([True, False]):
self.score += 2
def delete_winning_rows(self):
rows = self.board.state
i = 1
if is_row_filled(rows[0]):
return
# logika grawitacji
while i < len(rows):
if is_row_filled(rows[i]):
if random.choice([True, False]):
self.score = int(self.score * 1.25 + 15)
else:
self.score = int(self.score * 1.25 + 10)
i2 = i
while i2 > 0:
rows[i2] = rows[i2-1]
i2 -= 1
rows[0] = []
for m in range(self.board.width):
rows[0].append(TetrisTile())
i += 1
def go_left(self):
if self.dropping_structure is None or self.dropping_structure.is_colliding_left(self.board):
return
self.dropping_structure.pos_col -= 1
def go_right(self):
if self.dropping_structure is None or self.dropping_structure.is_colliding_right(self.board):
return
self.dropping_structure.pos_col += 1
def go_down(self):
if self.dropping_structure is not None and not self.dropping_structure.is_colliding_bottom(self.board):
self.dropping_structure.pos_row += 1
def go_rotate(self):
if self.dropping_structure is None:
return
target = copy.deepcopy(self.dropping_structure)
target.structure_kind = TetrisStructureKind[
TetrisStructure.kindRotationMap[target.structure_kind.name]]
offset_bottom_board = self.board.height - target.pos_row - target.height() + 1
if offset_bottom_board < 0:
target.pos_row += offset_bottom_board
offset_right = self.board.width - target.pos_col - target.width()
if offset_right < 0:
target.pos_col += offset_right
offset_left = target.pos_col
if offset_left < 0:
target.pos_col -= offset_left
if self.dropping_structure.is_overlap(self.board):
return
self.dropping_structure = target
from enum import Enum
import random
import copy
class TetrisTileKind(Enum):
EMPTY = ' '
RED = 'R'
YELLOW = 'Y'
GREEN = 'G'
class TetrisTile:
def __init__(self):
self.kind = TetrisTileKind.EMPTY
class TetrisStructureKind(Enum):
L1 = [[True, False],
[True, False],
[True, True]]
L2 = [
[False, False, True],
[True, True, True]]
L3 = [
[True, True],
[False, True],
[False, True]]
L4 = [
[True, True, True],
[True, False, False]]
I1 = [[True, True, True]]
I2 = [[True], [True], [True]]
Sq = [[True, True],
[True, True]]
class TetrisBoard:
def __init__(self):
self.width = 8
self.height = 12
self.resetState()
def resetState(self):
self.state = [[TetrisTile()
for _ in range(self.width)] for _ in range(self.height)]
def is_empty_at(self, row, column):
return row < 0 or column < 0 or row >= self.height or column >= self.width or self.state[row][column].kind.name == "EMPTY"
class TetrisStructure:
def __init__(self, **kwargs):
board_width = kwargs["board_width"]
self.kind = random.choice(list(TetrisTileKind)[1:])
self.structure_kind = random.choice(list(TetrisStructureKind))
self.pos_row = self.height() * (-1)
self.pos_col = int(board_width / 2) - \
int(self.width() / 2)
def is_overlap(self, board, offset_row_col=(0, 0)):
shape = self.structure_kind.value
for i in range(len(shape)):
for j in range(len(shape[0])):
if shape[i][j] and not board.is_empty_at(i+offset_row_col[0]+self.pos_row, j+offset_row_col[1]+self.pos_col):
return True
return False
def is_colliding_bottom(self, board):
return self.pos_row >= board.height-len(self.structure_kind.value) or self.is_overlap(board, (1, 0))
def is_colliding_left(self, board):
return self.pos_col <= 0 or self.is_overlap(board, (0, -1))
def is_colliding_right(self, board):
return self.pos_col >= board.width - len(self.structure_kind.value[0]) or self.is_overlap(board, (0, 1))
def write_to_board(self, board):
shape = self.structure_kind.value
for i in range(len(shape)):
for j in range(len(shape[0])):
if shape[i][j] and (i+self.pos_row) >= 0:
board.state[i+self.pos_row][j +
self.pos_col].kind = self.kind
def width(self):
return len(self.structure_kind.value[0])
def height(self):
return len(self.structure_kind.value)
kindRotationMap = {
"L1": "L2",
"L2": "L3",
"L3": "L4",
"L4": "L1",
"Sq": "Sq",
"I1": "I2",
"I2": "I1"
}
class TetrisEventKind(Enum):
Void = 0
Updated = 1
LevelFinished = 2
def is_row_filled(row):
for col in row:
if col.kind.name == "EMPTY":
return False
return True
class Tetris:
def __init__(self):
# Wypełniamy bufor board pustymi blokami
self.board = TetrisBoard()
self.dropping_structure = None
self.update_task_check_winning = False
self.is_finished = False
self.score = 0
def update(self):
if self.is_finished:
return
if self.update_task_check_winning:
self.delete_winning_rows()
self.update_task_check_winning = False
return
if self.dropping_structure is None:
self.dropping_structure = TetrisStructure(
board_width=self.board.width)
if self.dropping_structure.is_overlap(self.board) or self.dropping_structure.is_colliding_bottom(self.board):
self.is_finished = True
return
self.go_down()
self.check_and_write_dropping_structure()
def check_and_write_dropping_structure(self):
if self.dropping_structure is not None and self.dropping_structure.is_colliding_bottom(self.board):
self.dropping_structure.write_to_board(self.board)
self.dropping_structure = None
self.update_task_check_winning = True
if random.choice([True, False]):
self.score += 1
elif random.choice([True, False]):
self.score += 2
def delete_winning_rows(self):
rows = self.board.state
i = 1
if is_row_filled(rows[0]):
return
# logika grawitacji
while i < len(rows):
if is_row_filled(rows[i]):
if random.choice([True, False]):
self.score = int(self.score * 1.25 + 15)
else:
self.score = int(self.score * 1.25 + 10)
i2 = i
while i2 > 0:
rows[i2] = rows[i2-1]
i2 -= 1
rows[0] = []
for m in range(self.board.width):
rows[0].append(TetrisTile())
i += 1
def go_left(self):
if self.dropping_structure is None or self.dropping_structure.is_colliding_left(self.board):
return
self.dropping_structure.pos_col -= 1
def go_right(self):
if self.dropping_structure is None or self.dropping_structure.is_colliding_right(self.board):
return
self.dropping_structure.pos_col += 1
def go_down(self):
if self.dropping_structure is not None and not self.dropping_structure.is_colliding_bottom(self.board):
self.dropping_structure.pos_row += 1
def go_rotate(self):
if self.dropping_structure is None:
return
target = copy.deepcopy(self.dropping_structure)
target.structure_kind = TetrisStructureKind[
TetrisStructure.kindRotationMap[target.structure_kind.name]]
offset_bottom_board = self.board.height - target.pos_row - target.height() + 1
if offset_bottom_board < 0:
target.pos_row += offset_bottom_board
offset_right = self.board.width - target.pos_col - target.width()
if offset_right < 0:
target.pos_col += offset_right
offset_left = target.pos_col
if offset_left < 0:
target.pos_col -= offset_left
if self.dropping_structure.is_overlap(self.board):
return
self.dropping_structure = target
python
import random
import pygame
import sys
import datetime
from pygame.locals import *
from tetris import *
TileKindToColorMap = {
' ': (50, 50, 70),
'R': (220, 30, 90),
'Y': (220, 220, 30),
'G': (50, 220, 70),
}
class GameScene:
def __init__(self, **kwargs):
self.full_score = 0
pass
def resetState(self, globalState):
self.globalState = globalState
# ustawienie początkowego stanu gry
self.tetris = Tetris()
self.tileSize = 30
self.boardOffset = (int((self.globalState.window_width -
self.tileSize*self.tetris.board.width)/2), int((self.globalState.window_height - self.tileSize*self.tetris.board.height)/2))
self.font = pygame.font.SysFont(
self.globalState.default_font_name, 24)
self.frame_freeze_count = 0
self.key_repeat_frame = 0
self.is_score_recorded = False
self.best_scores_text = None
def onEvent(self, event):
if event.type == pygame.KEYUP and self.tetris.is_finished:
self.resetState(self.globalState)
if event.type == pygame.KEYUP:
self.key_repeat_frame = 0
def save_tetris_score(self):
with open('wyniki.txt', 'a') as f:
f.write(str(self.tetris.score*10) + ';' +
datetime.datetime.now().strftime("%B %d, %Y %H:%M") + '\n')
def read_tetris_scores(self):
scores = []
with open('wyniki.txt', 'r') as f:
for line in f:
line = line.strip()
columns = line.split(';')
scores.append({
"wynik": columns[0],
"data": columns[1],
})
return scores
def tetris_scores_text(self):
text = "Najlepsze wyniki:\n"
items = sorted(self.read_tetris_scores(),
key=lambda i: int(i["wynik"]), reverse=True)
for i, item in enumerate(items[:4]):
text += str(i+1) + ". Wynik " + \
item["wynik"] + " punktów (" + item["data"] + ")\n"
return text
def onFrame(self):
if self.tetris.is_finished and not self.is_score_recorded:
self.is_score_recorded = True
self.save_tetris_score()
if self.tetris.is_finished:
return
# logika odbioru zdarzenia wciśnięcia przycisku klawiatury i jego powtarzania
keys = pygame.key.get_pressed()
key_handled = False
if self.key_repeat_frame == 0:
if keys[pygame.K_LEFT]:
self.tetris.go_left()
if keys[pygame.K_RIGHT]:
self.tetris.go_right()
if keys[pygame.K_DOWN]:
self.tetris.go_down()
if keys[pygame.K_UP]:
self.tetris.go_rotate()
elif self.key_repeat_frame > 1:
self.key_repeat_frame = -1
if keys[pygame.K_LEFT] or keys[pygame.K_RIGHT] or keys[pygame.K_DOWN] or keys[pygame.K_UP]:
self.key_repeat_frame += 1
# logika aktualizacji stanu gry
if self.frame_freeze_count > self.globalState.fps:
self.frame_freeze_count = 0
self.tetris.update()
self.frame_freeze_count += 1
def draw(self, surface):
board = self.tetris.board
if self.tetris.is_finished:
surface.fill((60, 30, 40))
if self.best_scores_text is None:
self.best_scores_text = self.tetris_scores_text()
text = self.best_scores_text
for i, line in enumerate(text.splitlines()):
obj_message_left = self.font.render(
line, True, self.globalState.color_fg)
obj_message_left_rect = obj_message_left.get_rect()
obj_message_left_rect.topleft = (
25, int((self.globalState.window_height-100) - (obj_message_left_rect.height / 2) + (obj_message_left_rect.height + 3)*i))
surface.blit(obj_message_left, obj_message_left_rect)
obj_message = self.font.render(
'Punkty: ' + str(self.tetris.score*10), True, self.globalState.color_fg)
obj_message_rect = obj_message.get_rect()
obj_message_rect.topleft = (
self.globalState.window_width - obj_message_rect.width - 20, self.globalState.window_height - obj_message_rect.height - 10)
surface.blit(obj_message, obj_message_rect)
self.draw_board(surface)
if self.tetris.dropping_structure is not None:
self.draw_dropping_structure(surface)
obj_message = self.font.render(
'Punkty: ' + str(self.tetris.score*10), True, self.globalState.color_fg)
obj_message_rect = obj_message.get_rect()
obj_message_rect.topleft = (
self.globalState.window_width - obj_message_rect.width - 20, self.globalState.window_height - obj_message_rect.height - 10)
surface.blit(obj_message, obj_message_rect)
def draw_tile(self, surface, tile, position):
color = TileKindToColorMap[tile.kind.value]
if self.tetris.is_finished and tile.kind.name == "EMPTY":
color = (90, 50, 60)
pygame.draw.rect(surface, color,
pygame.Rect(position[0]+2, position[1]+2, self.tileSize-4, self.tileSize-4))
def draw_tile_alt(self, surface, tile, position):
pygame.draw.rect(surface, TileKindToColorMap[tile.kind.value],
pygame.Rect(position[0]+2, position[1]+2, self.tileSize-4, self.tileSize-4))
pygame.draw.rect(surface, self.globalState.color_bg,
pygame.Rect(position[0]+4, position[1]+4, self.tileSize-8, self.tileSize-8))
def draw_board(self, surface):
tetrisBoard = self.tetris.board
for i, row in enumerate(tetrisBoard.state):
for j, tile in enumerate(row):
self.draw_tile(
surface, tile, (j*self.tileSize+self.boardOffset[0], i*self.tileSize+self.boardOffset[1]))
def draw_dropping_structure(self, surface):
dropping_structure = self.tetris.dropping_structure
pos_col = dropping_structure.pos_col
pos_row = dropping_structure.pos_row
for i, row in enumerate(dropping_structure.structure_kind.value):
for j, value in enumerate(row):
if value:
self.draw_tile_alt(
surface, dropping_structure, ((j-dropping_structure.width()-1)*self.tileSize+self.boardOffset[0], (i+1)*self.tileSize+self.boardOffset[1]))
if j+pos_col >= 0 and i+pos_row >= 0 and value:
self.draw_tile(
surface, dropping_structure, ((j+pos_col)*self.tileSize+self.boardOffset[0], (i+pos_row)*self.tileSize+self.boardOffset[1]))
import random
import pygame
import sys
import datetime
from pygame.locals import *
from tetris import *
TileKindToColorMap = {
' ': (50, 50, 70),
'R': (220, 30, 90),
'Y': (220, 220, 30),
'G': (50, 220, 70),
}
class GameScene:
def __init__(self, **kwargs):
self.full_score = 0
pass
def resetState(self, globalState):
self.globalState = globalState
# ustawienie początkowego stanu gry
self.tetris = Tetris()
self.tileSize = 30
self.boardOffset = (int((self.globalState.window_width -
self.tileSize*self.tetris.board.width)/2), int((self.globalState.window_height - self.tileSize*self.tetris.board.height)/2))
self.font = pygame.font.SysFont(
self.globalState.default_font_name, 24)
self.frame_freeze_count = 0
self.key_repeat_frame = 0
self.is_score_recorded = False
self.best_scores_text = None
def onEvent(self, event):
if event.type == pygame.KEYUP and self.tetris.is_finished:
self.resetState(self.globalState)
if event.type == pygame.KEYUP:
self.key_repeat_frame = 0
def save_tetris_score(self):
with open('wyniki.txt', 'a') as f:
f.write(str(self.tetris.score*10) + ';' +
datetime.datetime.now().strftime("%B %d, %Y %H:%M") + '\n')
def read_tetris_scores(self):
scores = []
with open('wyniki.txt', 'r') as f:
for line in f:
line = line.strip()
columns = line.split(';')
scores.append({
"wynik": columns[0],
"data": columns[1],
})
return scores
def tetris_scores_text(self):
text = "Najlepsze wyniki:\n"
items = sorted(self.read_tetris_scores(),
key=lambda i: int(i["wynik"]), reverse=True)
for i, item in enumerate(items[:4]):
text += str(i+1) + ". Wynik " + \
item["wynik"] + " punktów (" + item["data"] + ")\n"
return text
def onFrame(self):
if self.tetris.is_finished and not self.is_score_recorded:
self.is_score_recorded = True
self.save_tetris_score()
if self.tetris.is_finished:
return
# logika odbioru zdarzenia wciśnięcia przycisku klawiatury i jego powtarzania
keys = pygame.key.get_pressed()
key_handled = False
if self.key_repeat_frame == 0:
if keys[pygame.K_LEFT]:
self.tetris.go_left()
if keys[pygame.K_RIGHT]:
self.tetris.go_right()
if keys[pygame.K_DOWN]:
self.tetris.go_down()
if keys[pygame.K_UP]:
self.tetris.go_rotate()
elif self.key_repeat_frame > 1:
self.key_repeat_frame = -1
if keys[pygame.K_LEFT] or keys[pygame.K_RIGHT] or keys[pygame.K_DOWN] or keys[pygame.K_UP]:
self.key_repeat_frame += 1
# logika aktualizacji stanu gry
if self.frame_freeze_count > self.globalState.fps:
self.frame_freeze_count = 0
self.tetris.update()
self.frame_freeze_count += 1
def draw(self, surface):
board = self.tetris.board
if self.tetris.is_finished:
surface.fill((60, 30, 40))
if self.best_scores_text is None:
self.best_scores_text = self.tetris_scores_text()
text = self.best_scores_text
for i, line in enumerate(text.splitlines()):
obj_message_left = self.font.render(
line, True, self.globalState.color_fg)
obj_message_left_rect = obj_message_left.get_rect()
obj_message_left_rect.topleft = (
25, int((self.globalState.window_height-100) - (obj_message_left_rect.height / 2) + (obj_message_left_rect.height + 3)*i))
surface.blit(obj_message_left, obj_message_left_rect)
obj_message = self.font.render(
'Punkty: ' + str(self.tetris.score*10), True, self.globalState.color_fg)
obj_message_rect = obj_message.get_rect()
obj_message_rect.topleft = (
self.globalState.window_width - obj_message_rect.width - 20, self.globalState.window_height - obj_message_rect.height - 10)
surface.blit(obj_message, obj_message_rect)
self.draw_board(surface)
if self.tetris.dropping_structure is not None:
self.draw_dropping_structure(surface)
obj_message = self.font.render(
'Punkty: ' + str(self.tetris.score*10), True, self.globalState.color_fg)
obj_message_rect = obj_message.get_rect()
obj_message_rect.topleft = (
self.globalState.window_width - obj_message_rect.width - 20, self.globalState.window_height - obj_message_rect.height - 10)
surface.blit(obj_message, obj_message_rect)
def draw_tile(self, surface, tile, position):
color = TileKindToColorMap[tile.kind.value]
if self.tetris.is_finished and tile.kind.name == "EMPTY":
color = (90, 50, 60)
pygame.draw.rect(surface, color,
pygame.Rect(position[0]+2, position[1]+2, self.tileSize-4, self.tileSize-4))
def draw_tile_alt(self, surface, tile, position):
pygame.draw.rect(surface, TileKindToColorMap[tile.kind.value],
pygame.Rect(position[0]+2, position[1]+2, self.tileSize-4, self.tileSize-4))
pygame.draw.rect(surface, self.globalState.color_bg,
pygame.Rect(position[0]+4, position[1]+4, self.tileSize-8, self.tileSize-8))
def draw_board(self, surface):
tetrisBoard = self.tetris.board
for i, row in enumerate(tetrisBoard.state):
for j, tile in enumerate(row):
self.draw_tile(
surface, tile, (j*self.tileSize+self.boardOffset[0], i*self.tileSize+self.boardOffset[1]))
def draw_dropping_structure(self, surface):
dropping_structure = self.tetris.dropping_structure
pos_col = dropping_structure.pos_col
pos_row = dropping_structure.pos_row
for i, row in enumerate(dropping_structure.structure_kind.value):
for j, value in enumerate(row):
if value:
self.draw_tile_alt(
surface, dropping_structure, ((j-dropping_structure.width()-1)*self.tileSize+self.boardOffset[0], (i+1)*self.tileSize+self.boardOffset[1]))
if j+pos_col >= 0 and i+pos_row >= 0 and value:
self.draw_tile(
surface, dropping_structure, ((j+pos_col)*self.tileSize+self.boardOffset[0], (i+pos_row)*self.tileSize+self.boardOffset[1]))
python
import random
import pygame
import sys
from pygame.locals import *
from game import *
from dataclasses import dataclass
pygame.init()
@dataclass
class GlobalState:
window_width: int = 800
window_height: int = 600
color_bg: tuple = (30, 30, 35)
color_fg: tuple = (230, 230, 240)
default_font_name: str = "sans-serif"
fps: int = 60
display: object = object()
extra: object = object()
class SimpleTitleScene:
def __init__(self, **kwargs):
self.next_scene = kwargs["next_scene"] if "next_scene" in kwargs else None
self.title_message = kwargs["title_message"] if "title_message" in kwargs else None
self.message = kwargs["message"] if "message" in kwargs else None
def resetState(self, globalState):
self.globalState = globalState
self.font = pygame.font.SysFont(self.globalState.default_font_name, 24)
self.title_font = pygame.font.SysFont(
self.globalState.default_font_name, 90)
self.go_to_next_scene = False
self.next_scene.resetState(globalState)
def onEvent(self, event):
if event.type == pygame.KEYUP or event.type == pygame.MOUSEBUTTONUP:
self.go_to_next_scene = True
def onFrame(self):
if self.go_to_next_scene and self.next_scene is not None:
self.globalState.display.scene = self.next_scene
def draw(self, surface):
self.obj_message = self.font.render(
'Nacisnąć dowolny przycisk', True, self.globalState.color_fg)
self.obj_message_rect = self.obj_message.get_rect()
self.obj_message_rect.topleft = (
self.globalState.window_width - self.obj_message_rect.width - 20, self.globalState.window_height - self.obj_message_rect.height - 10)
surface.blit(self.obj_message, self.obj_message_rect)
if self.title_message:
obj_message_title = self.title_font.render(
self.title_message, True, self.globalState.color_fg)
obj_message_title_rect = obj_message_title.get_rect()
obj_message_title_rect.topleft = (
int((self.globalState.window_width/2) - (obj_message_title_rect.width / 2)), int((self.globalState.window_height/2) - (obj_message_title_rect.height / 2)))
surface.blit(obj_message_title, obj_message_title_rect)
if self.message:
for i, line in enumerate(self.message.splitlines()):
obj_message_left = self.font.render(
line, True, self.globalState.color_fg)
obj_message_left_rect = obj_message_left.get_rect()
obj_message_left_rect.topleft = (
25, int((self.globalState.window_height*0.75) - (obj_message_left_rect.height / 2) + (obj_message_left_rect.height + 3)*i))
surface.blit(obj_message_left, obj_message_left_rect)
class Display:
def __init__(self, **kwargs):
self.globalState = kwargs["global_state"] in kwargs if "global_state" in kwargs else GlobalState(
)
self.globalState.display = self
self.scene = kwargs["scene"] if "scene" in kwargs else SimpleTitleScene(
next_scene=None,
)
self.scene.resetState(self.globalState)
self.clock = pygame.time.Clock()
self.surface = pygame.display.set_mode(
(self.globalState.window_width, self.globalState.window_height))
def frame(self):
# Zbieramy zdarzenia użytkownika
for event in pygame.event.get():
if event.type == QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
sys.exit(0)
# Wywołujemy odbiorcę zdarzeń
self.scene.onEvent(event)
self.surface.fill(self.globalState.color_bg)
# Wywołujemy funkcję w każdej klatce
self.scene.onFrame()
# Wywołujemy rysowanie klatki
self.scene.draw(self.surface)
pygame.display.update()
self.clock.tick(self.globalState.fps)
import random
import pygame
import sys
from pygame.locals import *
from game import *
from dataclasses import dataclass
pygame.init()
@dataclass
class GlobalState:
window_width: int = 800
window_height: int = 600
color_bg: tuple = (30, 30, 35)
color_fg: tuple = (230, 230, 240)
default_font_name: str = "sans-serif"
fps: int = 60
display: object = object()
extra: object = object()
class SimpleTitleScene:
def __init__(self, **kwargs):
self.next_scene = kwargs["next_scene"] if "next_scene" in kwargs else None
self.title_message = kwargs["title_message"] if "title_message" in kwargs else None
self.message = kwargs["message"] if "message" in kwargs else None
def resetState(self, globalState):
self.globalState = globalState
self.font = pygame.font.SysFont(self.globalState.default_font_name, 24)
self.title_font = pygame.font.SysFont(
self.globalState.default_font_name, 90)
self.go_to_next_scene = False
self.next_scene.resetState(globalState)
def onEvent(self, event):
if event.type == pygame.KEYUP or event.type == pygame.MOUSEBUTTONUP:
self.go_to_next_scene = True
def onFrame(self):
if self.go_to_next_scene and self.next_scene is not None:
self.globalState.display.scene = self.next_scene
def draw(self, surface):
self.obj_message = self.font.render(
'Nacisnąć dowolny przycisk', True, self.globalState.color_fg)
self.obj_message_rect = self.obj_message.get_rect()
self.obj_message_rect.topleft = (
self.globalState.window_width - self.obj_message_rect.width - 20, self.globalState.window_height - self.obj_message_rect.height - 10)
surface.blit(self.obj_message, self.obj_message_rect)
if self.title_message:
obj_message_title = self.title_font.render(
self.title_message, True, self.globalState.color_fg)
obj_message_title_rect = obj_message_title.get_rect()
obj_message_title_rect.topleft = (
int((self.globalState.window_width/2) - (obj_message_title_rect.width / 2)), int((self.globalState.window_height/2) - (obj_message_title_rect.height / 2)))
surface.blit(obj_message_title, obj_message_title_rect)
if self.message:
for i, line in enumerate(self.message.splitlines()):
obj_message_left = self.font.render(
line, True, self.globalState.color_fg)
obj_message_left_rect = obj_message_left.get_rect()
obj_message_left_rect.topleft = (
25, int((self.globalState.window_height*0.75) - (obj_message_left_rect.height / 2) + (obj_message_left_rect.height + 3)*i))
surface.blit(obj_message_left, obj_message_left_rect)
class Display:
def __init__(self, **kwargs):
self.globalState = kwargs["global_state"] in kwargs if "global_state" in kwargs else GlobalState(
)
self.globalState.display = self
self.scene = kwargs["scene"] if "scene" in kwargs else SimpleTitleScene(
next_scene=None,
)
self.scene.resetState(self.globalState)
self.clock = pygame.time.Clock()
self.surface = pygame.display.set_mode(
(self.globalState.window_width, self.globalState.window_height))
def frame(self):
# Zbieramy zdarzenia użytkownika
for event in pygame.event.get():
if event.type == QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
sys.exit(0)
# Wywołujemy odbiorcę zdarzeń
self.scene.onEvent(event)
self.surface.fill(self.globalState.color_bg)
# Wywołujemy funkcję w każdej klatce
self.scene.onFrame()
# Wywołujemy rysowanie klatki
self.scene.draw(self.surface)
pygame.display.update()
self.clock.tick(self.globalState.fps)
python
from display import Display, SimpleTitleScene
from game import GameScene
import pygame
def main():
pygame.init()
pygame.display.set_caption('TERTIS')
display = Display(scene=SimpleTitleScene(
title_message="TERTIS",
message='''
Strzałka w lewo, prawo porusza strukturą
Strzałka w dół wykonuje dodatkowy krok w dół
Strzałka w górę obraca strukturą
Esc wychodzi z gry
''',
next_scene=GameScene()
))
while True:
display.frame()
if __name__ == '__main__':
main()
from display import Display, SimpleTitleScene
from game import GameScene
import pygame
def main():
pygame.init()
pygame.display.set_caption('TERTIS')
display = Display(scene=SimpleTitleScene(
title_message="TERTIS",
message='''
Strzałka w lewo, prawo porusza strukturą
Strzałka w dół wykonuje dodatkowy krok w dół
Strzałka w górę obraca strukturą
Esc wychodzi z gry
''',
next_scene=GameScene()
))
while True:
display.frame()
if __name__ == '__main__':
main()