feat: improve game music

This commit is contained in:
2021-07-08 11:23:47 -04:00
parent e607002062
commit f6ac6a68aa
14 changed files with 111 additions and 34 deletions

View File

@@ -4,9 +4,13 @@ window:
title: "Tetri5" title: "Tetri5"
sound: sound:
main-music: "resource/sound/main_music.ogg" theme-music: "resource/sound/theme_music.ogg"
row-completion: "resource/sound/row_completion.wav" option-change: "resource/sound/option_change.wav"
piece-set: "resource/sound/piece_set_3.wav" piece-rotate: "resource/sound/piece_rotate.ogg"
piece-set: "resource/sound/piece_set.ogg"
line-complete: "resource/sound/line_complete.ogg"
four-lines-complete: "resource/sound/four_lines_complete.ogg"
level-up: "resource/sound/level_up.ogg"
image: image:
title-screen: "resource/image/title_screen.png" title-screen: "resource/image/title_screen.png"

Binary file not shown.

BIN
resource/sound/level_up.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -6,6 +6,7 @@ from typing import List, Tuple
from types import FunctionType from types import FunctionType
from tetri5.util import ConfigurationManager from tetri5.util import ConfigurationManager
from tetri5.util import Controller from tetri5.util import Controller
from tetri5.util import SoundManager
""" """
TODO description TODO description
@@ -85,7 +86,6 @@ class Piece(Entity):
super().__init__(Piece._get_points(shape, position), color, border_color) super().__init__(Piece._get_points(shape, position), color, border_color)
self._inner_border_color = inner_border_color self._inner_border_color = inner_border_color
self._center = self._get_center(shape, position) self._center = self._get_center(shape, position)
self._piece_set_sound = mixer.Channel(2)
self._previous_points = None self._previous_points = None
self._previous_center = None self._previous_center = None
@@ -118,6 +118,8 @@ class Piece(Entity):
self.rotate() self.rotate()
if well and self.collide(well) or stack and self.collide(stack): if well and self.collide(well) or stack and self.collide(stack):
self.revert() self.revert()
else:
SoundManager.play_piece_rotate_sfx()
if Controller.key_down(pygame.K_LEFT): if Controller.key_down(pygame.K_LEFT):
self.move((-self._tile_size, 0)) self.move((-self._tile_size, 0))
if well and self.collide(well) or stack and self.collide(stack): if well and self.collide(well) or stack and self.collide(stack):
@@ -223,7 +225,7 @@ class Piece(Entity):
if self._current_set_time >= self._set_time: if self._current_set_time >= self._set_time:
self._current_set_time = 0 self._current_set_time = 0
if self._entity_is_below(well) or self._entity_is_below(stack): if self._entity_is_below(well) or self._entity_is_below(stack):
self._play_piece_set_sound() SoundManager.play_piece_set_sfx()
stack.add_piece(self) stack.add_piece(self)
clear_current_piece() clear_current_piece()
else: else:
@@ -240,10 +242,6 @@ class Piece(Entity):
return mimic_points return mimic_points
def _play_piece_set_sound(self) -> None:
piece_set_sound_file = ConfigurationManager.get("sound", "piece-set")
self._piece_set_sound.play(mixer.Sound(piece_set_sound_file))
def _entity_is_below(self, entity: Entity) -> bool: def _entity_is_below(self, entity: Entity) -> bool:
mimic_points = self._mimic_move((0, self._tile_size)) mimic_points = self._mimic_move((0, self._tile_size))
return entity and entity._collide(mimic_points) return entity and entity._collide(mimic_points)
@@ -275,7 +273,6 @@ class Stack(Entity):
super().__init__([], color, border_color) super().__init__([], color, border_color)
self.total_lines = 0 self.total_lines = 0
self.lines_completed_last = 0 self.lines_completed_last = 0
self.line_completed_sound = mixer.Channel(1)
def update(self, elapsed_time: int) -> None: # TODO remove scene argument def update(self, elapsed_time: int) -> None: # TODO remove scene argument
super().update(elapsed_time) super().update(elapsed_time)
@@ -305,7 +302,11 @@ class Stack(Entity):
if not squares_to_exclude: if not squares_to_exclude:
return 0 return 0
self._play_line_completed_sound() if len(rows_completed) == 4:
SoundManager.play_four_lines_complete_sfx()
else:
SoundManager.play_line_complete_sfx()
new_points = [] new_points = []
for square in self._points: for square in self._points:
if square not in squares_to_exclude: if square not in squares_to_exclude:
@@ -314,17 +315,12 @@ class Stack(Entity):
vertex[1] <= row_completed vertex[1] <= row_completed
for row_completed in rows_completed for row_completed in rows_completed
) )
vertex[1] += self._tile_size * distance_to_move vertex[1] += self._tile_size * distance_to_move
new_points.append(square) new_points.append(square)
self._points = new_points self._points = new_points
return len(rows_completed) return len(rows_completed)
def _play_line_completed_sound(self) -> None:
line_completed_sound_file = ConfigurationManager.get("sound", "row-completion")
self.line_completed_sound.play(mixer.Sound(line_completed_sound_file))
""" """
TODO description TODO description
""" """

View File

@@ -2,21 +2,19 @@ import sys
import pygame import pygame
from tetri5.util import ConfigurationManager from tetri5.util import ConfigurationManager
from tetri5.util import TextGenerator from tetri5.util import TextGenerator
from tetri5.util import SoundManager
from tetri5.scene import Scene, TitleScene from tetri5.scene import Scene, 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 create a util that manages sfx
class Game: class Game:
_current_scene = None _current_scene = None
@classmethod
def change_scene(cls, scene: Scene) -> None:
cls._current_scene = scene
@classmethod @classmethod
def init(cls) -> None: def init(cls) -> None:
pygame.init() pygame.init()
SoundManager.init()
TextGenerator.init(ConfigurationManager.get("image", "font"), (20, 20)) TextGenerator.init(ConfigurationManager.get("image", "font"), (20, 20))
cls._current_scene = TitleScene(Game.change_scene) cls._current_scene = TitleScene(Game.change_scene)
@@ -32,7 +30,6 @@ class Game:
pygame.display.set_caption(win_title) pygame.display.set_caption(win_title)
pygame.display.set_icon(pygame.image.load(win_icon)) pygame.display.set_icon(pygame.image.load(win_icon))
# gets called from the games main loop
@classmethod @classmethod
def update(cls) -> None: def update(cls) -> None:
# TODO write not initialized exception # TODO write not initialized exception
@@ -49,12 +46,15 @@ class Game:
@classmethod @classmethod
def draw(cls) -> None: def draw(cls) -> None:
# TODO write not initialized exception # TODO write not initialized exception
if cls._current_scene: if cls._current_scene:
cls._current_scene.draw(cls.screen) cls._current_scene.draw(cls.screen)
# update display # update display
pygame.display.update() pygame.display.update()
@classmethod
def change_scene(cls, scene: Scene) -> None:
cls._current_scene = scene

View File

@@ -1,10 +1,10 @@
import sys import sys
import pygame import pygame
from pygame import mixer
from types import FunctionType from types import FunctionType
from tetri5.util import ConfigurationManager from tetri5.util import ConfigurationManager
from tetri5.util import TextGenerator from tetri5.util import TextGenerator
from tetri5.util import Controller from tetri5.util import Controller
from tetri5.util import SoundManager
from tetri5.entity import Well from tetri5.entity import Well
from tetri5.entity import Stack from tetri5.entity import Stack
from tetri5.entity import PieceGenerator from tetri5.entity import PieceGenerator
@@ -39,7 +39,6 @@ class TitleScene(Scene):
self._option_one_position = ConfigurationManager.get("position", "option-one") self._option_one_position = ConfigurationManager.get("position", "option-one")
self._option_two_position = ConfigurationManager.get("position", "option-two") self._option_two_position = ConfigurationManager.get("position", "option-two")
self._is_multiplayer = False self._is_multiplayer = False
self._change_scence = change_scene self._change_scence = change_scene
def draw(self, surface: pygame.Surface) -> None: def draw(self, surface: pygame.Surface) -> None:
@@ -53,12 +52,18 @@ class TitleScene(Scene):
pygame.draw.circle(surface, self._cursor_color, self._cursor_position, self._tile_size // 3) pygame.draw.circle(surface, self._cursor_color, self._cursor_position, self._tile_size // 3)
def update(self, elapsed_time: int) -> None: def update(self, elapsed_time: int) -> None:
if Controller.key_pressed(pygame.K_UP): option_change = False
if Controller.key_pressed(pygame.K_UP) and self._is_multiplayer:
self._cursor_position = self._cursor_position_one self._cursor_position = self._cursor_position_one
self._is_multiplayer = False self._is_multiplayer = False
if Controller.key_pressed(pygame.K_DOWN): option_change = True
if Controller.key_pressed(pygame.K_DOWN) and not self._is_multiplayer:
self._cursor_position = self._cursor_position_two self._cursor_position = self._cursor_position_two
self._is_multiplayer = True self._is_multiplayer = True
option_change = True
if option_change:
SoundManager.play_option_change_sfx() # TODO add cool down
self._cursor_blink_time += elapsed_time self._cursor_blink_time += elapsed_time
if self._cursor_blink_time >= self._cursor_blink_interval: if self._cursor_blink_time >= self._cursor_blink_interval:
@@ -66,7 +71,7 @@ class TitleScene(Scene):
self._cursor_off = not self._cursor_off self._cursor_off = not self._cursor_off
if Controller.key_pressed(pygame.K_RETURN): if Controller.key_pressed(pygame.K_RETURN):
self._change_scence(SinglePlayerScene(self._change_scence)) self._change_scence(SinglePlayerScene(self._change_scence)) # TODO implement multiplayer
""" """
TODO TODO
@@ -77,17 +82,14 @@ class SinglePlayerScene(Scene):
self._tile_size = ConfigurationManager.get("engine", "tile-size") self._tile_size = ConfigurationManager.get("engine", "tile-size")
self._background_color = pygame.Color(ConfigurationManager.get("color", "window-bg")) self._background_color = pygame.Color(ConfigurationManager.get("color", "window-bg"))
self._score = 0 self._score = 0
self._level = 0 self._previous_level = 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._current_piece = None self._current_piece = None
self._next_piece = PieceGenerator.get_piece((620, 160)) self._next_piece = PieceGenerator.get_piece((620, 160))
self._main_music = mixer.Channel(0)
self._main_music.set_volume(0.7) # TODO add volume to the config
self._main_music.play(mixer.Sound(ConfigurationManager.get("sound", "main-music")), -1)
self._points_table = ConfigurationManager.get("engine", "points-table") self._points_table = ConfigurationManager.get("engine", "points-table")
self._change_scence = change_scene self._change_scence = change_scene
SoundManager.play_theme_music()
def draw(self, surface: pygame.Surface) -> None: def draw(self, surface: pygame.Surface) -> None:
surface.fill(self._background_color) surface.fill(self._background_color)
@@ -133,6 +135,10 @@ class SinglePlayerScene(Scene):
self._score += self._points_table[self._stack.lines_completed_last] * (self._get_level() + 1) self._score += self._points_table[self._stack.lines_completed_last] * (self._get_level() + 1)
if self._previous_level != self._get_level():
self._previous_level = self._get_level()
SoundManager.play_level_up_sfx()
def _get_level(self) -> int: def _get_level(self) -> int:
lines_per_level = ConfigurationManager.get("engine", "lines-per-level") lines_per_level = ConfigurationManager.get("engine", "lines-per-level")
return 0 if not self._stack else self._stack.total_lines // lines_per_level return 0 if not self._stack else self._stack.total_lines // lines_per_level

View File

@@ -1,6 +1,6 @@
import yaml import yaml
import pygame import pygame
from typing import KeysView, Tuple from typing import Tuple
""" """
TODO description TODO description
@@ -22,6 +22,77 @@ class ConfigurationManager:
else: else:
return cls._configuration[key] return cls._configuration[key]
"""
TODO description
"""
class SoundManager:
# Channels
_theme_music_ch = None
_option_change_sfx_ch = None
_piece_rotate_sfx_ch = None
_piece_set_sfx_ch = None
_line_complete_sfx_ch = None
_four_lines_complete_sfx_ch = None
# Sounds
_theme_music = None
_option_change_sfx = None
_piece_rotate_sfx = None
_piece_set_sfx = None
_line_complete_sfx = None
_four_lines_complete_sfx = None
@classmethod
def init(cls) -> None:
pygame.mixer.init()
cls._theme_music_ch = pygame.mixer.Channel(0)
cls._option_change_sfx_ch = pygame.mixer.Channel(1)
cls._piece_rotate_sfx_ch = pygame.mixer.Channel(2)
cls._piece_set_sfx_ch = pygame.mixer.Channel(3)
cls._line_complete_sfx_ch = pygame.mixer.Channel(4)
cls._four_lines_complete_sfx_ch = pygame.mixer.Channel(5)
cls._level_up_sfx_ch = pygame.mixer.Channel(6)
cls._theme_music = pygame.mixer.Sound(ConfigurationManager.get("sound", "theme-music"))
cls._option_change_sfx = pygame.mixer.Sound(ConfigurationManager.get("sound", "option-change"))
cls._piece_rotate_sfx = pygame.mixer.Sound(ConfigurationManager.get("sound", "piece-rotate"))
cls._piece_set_sfx = pygame.mixer.Sound(ConfigurationManager.get("sound", "piece-set"))
cls._line_complete_sfx = pygame.mixer.Sound(ConfigurationManager.get("sound", "line-complete"))
cls._four_lines_complete_sfx = pygame.mixer.Sound(ConfigurationManager.get("sound", "four-lines-complete"))
cls._level_up_sfx = pygame.mixer.Sound(ConfigurationManager.get("sound", "level-up"))
@classmethod
def play_theme_music(cls) -> None:
cls._theme_music_ch.set_volume(0.7)
cls._theme_music_ch.play(cls._theme_music, -1)
@classmethod
def play_option_change_sfx(cls) -> None:
cls._option_change_sfx_ch.set_volume(0.8)
cls._option_change_sfx_ch.play(cls._option_change_sfx)
@classmethod
def play_piece_rotate_sfx(cls) -> None:
cls._piece_rotate_sfx_ch.set_volume(0.7)
cls._piece_rotate_sfx_ch.play(cls._piece_rotate_sfx)
@classmethod
def play_piece_set_sfx(cls) -> None:
cls._piece_set_sfx_ch.play(cls._piece_set_sfx)
@classmethod
def play_line_complete_sfx(cls) -> None:
cls._line_complete_sfx_ch.play(cls._line_complete_sfx)
@classmethod
def play_four_lines_complete_sfx(cls) -> None:
cls._four_lines_complete_sfx_ch.play(cls._four_lines_complete_sfx)
@classmethod
def play_level_up_sfx(cls) -> None:
cls._level_up_sfx_ch.play(cls._level_up_sfx)
""" """
TODO description TODO description
""" """