feat!: add title screen scene
This commit is contained in:
17
config.yaml
17
config.yaml
@@ -1,11 +1,10 @@
|
|||||||
window:
|
window:
|
||||||
width: 800
|
width: 800
|
||||||
height: 600
|
height: 600
|
||||||
|
title: "Tetri5"
|
||||||
title: "Tetris"
|
|
||||||
|
|
||||||
sound:
|
sound:
|
||||||
main-music: "resource/sound/main_music.wav"
|
main-music: "resource/sound/main_music.ogg"
|
||||||
row-completion: "resource/sound/row_completion.wav"
|
row-completion: "resource/sound/row_completion.wav"
|
||||||
piece-set: "resource/sound/piece_set_3.wav"
|
piece-set: "resource/sound/piece_set_3.wav"
|
||||||
|
|
||||||
@@ -14,9 +13,17 @@ image:
|
|||||||
window-icon: "resource/image/tetris_icon.png"
|
window-icon: "resource/image/tetris_icon.png"
|
||||||
font: "resource/image/press-start-2p-font.bmp"
|
font: "resource/image/press-start-2p-font.bmp"
|
||||||
|
|
||||||
|
position:
|
||||||
|
title-logo: [280, 125]
|
||||||
|
option-one: [320, 390]
|
||||||
|
option-two: [320, 440]
|
||||||
|
cursor-option-one: [300, 399]
|
||||||
|
cursor-option-two: [300, 449]
|
||||||
|
|
||||||
engine:
|
engine:
|
||||||
fps: 60
|
fps: 60
|
||||||
tile-size: 20
|
tile-size: 20
|
||||||
|
cursor-blink-interval: 150
|
||||||
piece-gravity-time: 600
|
piece-gravity-time: 600
|
||||||
piece-set-time: 600
|
piece-set-time: 600
|
||||||
piece-gravity-increase: 56
|
piece-gravity-increase: 56
|
||||||
@@ -29,7 +36,11 @@ engine:
|
|||||||
- 1200 # 4 lines
|
- 1200 # 4 lines
|
||||||
|
|
||||||
color:
|
color:
|
||||||
|
# window
|
||||||
window-bg: "#000000"
|
window-bg: "#000000"
|
||||||
|
# title screen
|
||||||
|
cursor: "#FFFFFF"
|
||||||
|
# in game
|
||||||
piece-1: "#1F37EC"
|
piece-1: "#1F37EC"
|
||||||
piece-2: "#3DBBFC"
|
piece-2: "#3DBBFC"
|
||||||
piece-3: "#FFFFFF"
|
piece-3: "#FFFFFF"
|
||||||
|
|||||||
6
main.py
6
main.py
@@ -4,14 +4,14 @@
|
|||||||
https://tetris.com/play-tetris
|
https://tetris.com/play-tetris
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from tetris.game import Game
|
from tetri5.game import Game
|
||||||
from tetris.util import ConfigurationManager
|
from tetri5.util import ConfigurationManager
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
ConfigurationManager.init()
|
ConfigurationManager.init()
|
||||||
|
|
||||||
game = Game()
|
game = Game()
|
||||||
game.initialize()
|
game.init()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
game.update()
|
game.update()
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
@@ -3,12 +3,12 @@ import random
|
|||||||
import pygame
|
import pygame
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from pygame import mixer
|
from pygame import mixer
|
||||||
from tetris.util import ConfigurationManager
|
from tetri5.util import ConfigurationManager
|
||||||
from tetris.util import Controller
|
from tetri5.util import Controller
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from tetris.game import Game
|
from tetri5.game import Game
|
||||||
|
|
||||||
"""
|
"""
|
||||||
TODO description
|
TODO description
|
||||||
@@ -65,9 +65,9 @@ class Well(Entity):
|
|||||||
shape = []
|
shape = []
|
||||||
for i in range(self.WIDTH + 2):
|
for i in range(self.WIDTH + 2):
|
||||||
for j in range(self.HEIGHT + 2):
|
for j in range(self.HEIGHT + 2):
|
||||||
if i == 0 or i == self.WIDTH + 1:
|
if i in [0, self.WIDTH + 1]:
|
||||||
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
|
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
|
||||||
elif j == 0 or j == self.HEIGHT + 1:
|
elif j in [0, self.HEIGHT + 1]:
|
||||||
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
|
shape.append(((i, j), (i + 1, j), (i + 1, j + 1), (i, j + 1)))
|
||||||
|
|
||||||
points = []
|
points = []
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import sys
|
import sys
|
||||||
import pygame
|
import pygame
|
||||||
from pygame import mixer
|
from pygame import mixer
|
||||||
from tetris.util import ConfigurationManager
|
from tetri5.util import ConfigurationManager
|
||||||
from tetris.util import TextGenerator
|
from tetri5.util import TextGenerator
|
||||||
from tetris.entity import PieceGenerator
|
from tetri5.entity import PieceGenerator
|
||||||
from tetris.entity import Well
|
from tetri5.entity import Well
|
||||||
from tetris.entity import Stack
|
from tetri5.entity import Stack
|
||||||
from tetris.online import MultiplayerService
|
from tetri5.online import MultiplayerService
|
||||||
from tetris.scene import TitleScene
|
from tetri5.scene import TitleScene
|
||||||
|
|
||||||
# TODO improve game assets https://www.spriters-resource.com/nes/tetris/
|
# TODO improve game assets https://www.spriters-resource.com/nes/tetris/
|
||||||
# TODO should be a singleton and refactor the whole file?
|
# TODO should be a singleton and refactor the whole file?
|
||||||
@@ -18,7 +18,6 @@ class Game:
|
|||||||
self.tile_size = -1
|
self.tile_size = -1
|
||||||
self.screen = None
|
self.screen = None
|
||||||
self.clock = None
|
self.clock = None
|
||||||
|
|
||||||
self.current_scene = TitleScene()
|
self.current_scene = TitleScene()
|
||||||
|
|
||||||
# In Game #
|
# In Game #
|
||||||
@@ -27,8 +26,9 @@ class Game:
|
|||||||
self.well = None
|
self.well = None
|
||||||
self.stack = None
|
self.stack = None
|
||||||
self.main_music = None
|
self.main_music = None
|
||||||
|
self.score = -1
|
||||||
|
|
||||||
def initialize(self) -> None:
|
def init(self) -> None:
|
||||||
pygame.init()
|
pygame.init()
|
||||||
TextGenerator.init(ConfigurationManager.get("image", "font"), (20, 20))
|
TextGenerator.init(ConfigurationManager.get("image", "font"), (20, 20))
|
||||||
|
|
||||||
@@ -41,28 +41,26 @@ class Game:
|
|||||||
self.tile_size = ConfigurationManager.get("engine", "tile-size")
|
self.tile_size = ConfigurationManager.get("engine", "tile-size")
|
||||||
self.screen = pygame.display.set_mode((win_width, win_height))
|
self.screen = pygame.display.set_mode((win_width, win_height))
|
||||||
self.clock = pygame.time.Clock()
|
self.clock = pygame.time.Clock()
|
||||||
|
pygame.display.set_caption(win_title)
|
||||||
|
pygame.display.set_icon(pygame.image.load(win_icon))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.main_music = mixer.Channel(0)
|
self.main_music = mixer.Channel(0)
|
||||||
self.well = Well((280, 80), ConfigurationManager.get("color", "well-1"), ConfigurationManager.get("color", "well-border-1")) # TODO calculate position later and redo color config for well
|
self.well = Well((280, 80), ConfigurationManager.get("color", "well-1"), ConfigurationManager.get("color", "well-border-1")) # TODO calculate position later and redo color config for well
|
||||||
self.stack = Stack(ConfigurationManager.get("color", "stack-1"), ConfigurationManager.get("color", "stack-border-1"))
|
self.stack = Stack(ConfigurationManager.get("color", "stack-1"), ConfigurationManager.get("color", "stack-border-1"))
|
||||||
self.score = 0
|
self.score = 0
|
||||||
|
|
||||||
loaded_icon = pygame.image.load(win_icon)
|
|
||||||
pygame.display.set_caption(win_title)
|
|
||||||
pygame.display.set_icon(loaded_icon)
|
|
||||||
|
|
||||||
main_music_file = ConfigurationManager.get("sound", "main-music")
|
|
||||||
self.main_music.set_volume(0.7) # TODO add volume to the config
|
self.main_music.set_volume(0.7) # TODO add volume to the config
|
||||||
self.main_music.play(mixer.Sound(main_music_file), -1)
|
self.main_music.play(ConfigurationManager.get("sound", "main-music"), -1)
|
||||||
|
|
||||||
# gets called from the games main loop
|
# gets called from the games main loop
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
|
|
||||||
if self.current_scene:
|
|
||||||
self.current_scene.update()
|
|
||||||
else:
|
|
||||||
# TODO write not initialized exception
|
# TODO write not initialized exception
|
||||||
elapsed_time = self.clock.tick(self.fps)
|
elapsed_time = self.clock.tick(self.fps)
|
||||||
|
|
||||||
|
if self.current_scene:
|
||||||
|
self.current_scene.update(elapsed_time)
|
||||||
|
else:
|
||||||
if not self.next_piece:
|
if not self.next_piece:
|
||||||
self.next_piece = PieceGenerator.get_piece((620, 160))
|
self.next_piece = PieceGenerator.get_piece((620, 160))
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ class _NetworkConnectionService():
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def _try_receive_message(cls) -> None:
|
async def _try_receive_message(cls) -> None:
|
||||||
try:
|
try:
|
||||||
task = cls._pending_receive_task if cls._pending_receive_task else asyncio.create_task(cls._websocket.recv())
|
task = cls._pending_receive_task or asyncio.create_task(cls._websocket.recv())
|
||||||
done, pending = await asyncio.wait({task}, timeout=8e-3) # TODO experiment with the timeout
|
done, pending = await asyncio.wait({task}, timeout=8e-3) # TODO experiment with the timeout
|
||||||
|
|
||||||
if task in done:
|
if task in done:
|
||||||
68
tetri5/scene.py
Normal file
68
tetri5/scene.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import pygame
|
||||||
|
from tetri5.util import ConfigurationManager
|
||||||
|
from tetri5.util import TextGenerator
|
||||||
|
from tetri5.util import Controller
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
class TitleScene:
|
||||||
|
|
||||||
|
# Title screen options
|
||||||
|
ONE_PLAYER = "1 PLAYER"
|
||||||
|
TWO_PLAYER = "2 PLAYER"
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._tile_size = ConfigurationManager.get("engine", "tile-size")
|
||||||
|
self._logo_image = pygame.image.load(ConfigurationManager.get("image", "title-screen"))
|
||||||
|
self._cursor_position_one = ConfigurationManager.get("position", "cursor-option-one")
|
||||||
|
self._cursor_position_two = ConfigurationManager.get("position", "cursor-option-two")
|
||||||
|
self._cursor_position = self._cursor_position_one
|
||||||
|
self._cursor_blink_interval = ConfigurationManager.get("engine", "cursor-blink-interval")
|
||||||
|
self._cursor_blink_time = 0
|
||||||
|
self._cursor_color = pygame.Color(ConfigurationManager.get("color", "cursor"))
|
||||||
|
self._cursor_off = False
|
||||||
|
self._background_color = pygame.Color(ConfigurationManager.get("color", "window-bg"))
|
||||||
|
self._logo_position = ConfigurationManager.get("position", "title-logo")
|
||||||
|
self._option_one_position = ConfigurationManager.get("position", "option-one")
|
||||||
|
self._option_two_position = ConfigurationManager.get("position", "option-two")
|
||||||
|
self._is_multiplayer = False
|
||||||
|
|
||||||
|
def draw(self, surface: pygame.Surface) -> None:
|
||||||
|
surface.fill(self._background_color)
|
||||||
|
surface.blit(self._logo_image, self._logo_position)
|
||||||
|
|
||||||
|
TextGenerator.draw(TitleScene.ONE_PLAYER, self._option_one_position, surface)
|
||||||
|
TextGenerator.draw(TitleScene.TWO_PLAYER, self._option_two_position, surface)
|
||||||
|
|
||||||
|
if self._cursor_off:
|
||||||
|
pygame.draw.circle(surface, self._cursor_color, self._cursor_position, self._tile_size // 3)
|
||||||
|
|
||||||
|
def update(self, elapsed_time) -> None:
|
||||||
|
if Controller.key_pressed(pygame.K_UP):
|
||||||
|
self._cursor_position = self._cursor_position_one
|
||||||
|
self._is_multiplayer = False
|
||||||
|
if Controller.key_pressed(pygame.K_DOWN):
|
||||||
|
self._cursor_position = self._cursor_position_two
|
||||||
|
self._is_multiplayer = True
|
||||||
|
|
||||||
|
self._cursor_blink_time += elapsed_time
|
||||||
|
if self._cursor_blink_time >= self._cursor_blink_interval:
|
||||||
|
self._cursor_blink_time = 0
|
||||||
|
self._cursor_off = not self._cursor_off
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
class SinglePlayerScene:
|
||||||
|
pass
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
class MultiPlayerScene:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import pygame
|
|
||||||
from tetris.util import ConfigurationManager
|
|
||||||
from tetris.util import TextGenerator
|
|
||||||
from tetris.util import Controller
|
|
||||||
|
|
||||||
"""
|
|
||||||
TODO
|
|
||||||
"""
|
|
||||||
class TitleScene:
|
|
||||||
|
|
||||||
# Title screen options
|
|
||||||
ONE_PLAYER = "ONE_PLAYER"
|
|
||||||
TWO_PLAYER = "TWO_PLAYER"
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
image_path = ConfigurationManager.get("image", "title-screen")
|
|
||||||
|
|
||||||
self.splash_image = pygame.image.load(image_path)
|
|
||||||
self.cursor_position = None
|
|
||||||
self.cursor_flash_timer = 0
|
|
||||||
|
|
||||||
def draw(self, screen) -> None:
|
|
||||||
screen.fill(pygame.Color(ConfigurationManager.get("color", "window-bg")))
|
|
||||||
screen.blit(self.splash_image, (300, 0))
|
|
||||||
|
|
||||||
TextGenerator.draw("1 PLAYER", (300, 400), screen)
|
|
||||||
TextGenerator.draw("2 PLAYER", (300, 450), screen)
|
|
||||||
|
|
||||||
def update(self) -> None:
|
|
||||||
if Controller.key_pressed(pygame.K_DOWN):
|
|
||||||
self.current_option = TitleScene.ONE_PLAYER
|
|
||||||
if Controller.key_pressed(pygame.K_UP):
|
|
||||||
self.current_option = TitleScene.TWO_PLAYER
|
|
||||||
Reference in New Issue
Block a user