reworking sound system

This commit is contained in:
2024-10-16 17:34:14 +02:00
parent d8298f6661
commit d2597784d4
7 changed files with 193 additions and 64 deletions

View File

@@ -3,8 +3,10 @@ cmake_minimum_required(VERSION 3.5)
project(SDL_TD VERSION 0.1 LANGUAGES CXX) project(SDL_TD VERSION 0.1 LANGUAGES CXX)
# Find SDL2 # Find SDL2
find_package(SDL2 QUIET) find_package(SDL2 REQUIRED)
find_package(SDL2_mixer REQUIRED) find_package(SDL2_mixer REQUIRED)
find_package(SDL2_image REQUIRED)
find_package(SDL2_ttf REQUIRED)
# Set SDL include directories and libraries # Set SDL include directories and libraries
set(SDL_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS}) set(SDL_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS})

View File

@@ -1,6 +1,6 @@
#include "Game.hpp" #include "Game.hpp"
Game::Game( ) : window(nullptr, SDL_DestroyWindow) { } Game::Game( ) : window(nullptr, SDL_DestroyWindow), sound(make_unique<Sound>( )) { }
bool Game::init(const char* title, int w, int h) { bool Game::init(const char* title, int w, int h) {
window.reset(SDL_CreateWindow( window.reset(SDL_CreateWindow(
@@ -34,15 +34,6 @@ bool Game::init(const char* title, int w, int h) {
handleWindowResize( ); handleWindowResize( );
bgm = std::shared_ptr<Mix_Music>(Mix_LoadMUS("assets/sound_tracks/bgm.mp3"), [ ](Mix_Music* m) {
Mix_FreeMusic(m);
});
if (!bgm) {
SDL_Log("Failed to load background music: %s", Mix_GetError( ));
return false;
}
return true; return true;
} }
@@ -53,7 +44,7 @@ void Game::run( ) {
gameRenderer->renderStartScreen( ); gameRenderer->renderStartScreen( );
} }
Mix_PlayMusic(bgm.get( ), -1); sound->PlayMusic(MusicName::MAIN_THEME);
lastUpdateTime = SDL_GetTicks( ); lastUpdateTime = SDL_GetTicks( );
while (!gameState.gameover && !gameBoard->isCollision( )) { while (!gameState.gameover && !gameBoard->isCollision( )) {
@@ -62,15 +53,10 @@ void Game::run( ) {
update( ); update( );
render( ); render( );
} }
gameState.gameover = true;
Mix_PauseMusic( );
Mix_Chunk* game_over = Mix_LoadWAV("assets/sound_effects/game_over.wav"); gameState.gameover = true;
if (game_over == nullptr) sound->PauseMusic( );
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( )); sound->PlaySound(SoundName::GAME_OVER);
else {
Mix_PlayChannel(-1, game_over, 0);
}
while (gameState.gameover) { while (gameState.gameover) {
if (gameState.quit) return; if (gameState.quit) return;
@@ -83,7 +69,6 @@ void Game::run( ) {
void Game::inputHandler( ) { void Game::inputHandler( ) {
SDL_Event event; SDL_Event event;
Mix_Chunk* movePieceSound = Mix_LoadWAV("assets/sound_effects/move_piece.wav");
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) { if (event.type == SDL_QUIT) {
SDL_Quit( ); SDL_Quit( );
@@ -93,43 +78,33 @@ void Game::inputHandler( ) {
case SDLK_LEFT: case SDLK_LEFT:
case SDLK_a: case SDLK_a:
if (!gameState.gameover && !gameState.startSequence) if (!gameState.gameover && !gameState.startSequence)
gameBoard->tryMoveCurrentTetromino(-1, 0); if (gameBoard->tryMoveCurrentTetromino(-1, 0))
if (movePieceSound == nullptr) sound->PlaySound(SoundName::MOVE_PIECE);
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
else {
Mix_PlayChannel(-1, movePieceSound, 0);
}
break; break;
case SDLK_RIGHT: case SDLK_RIGHT:
case SDLK_d: case SDLK_d:
if (!gameState.gameover && !gameState.startSequence) if (!gameState.gameover && !gameState.startSequence)
gameBoard->tryMoveCurrentTetromino(1, 0); if (gameBoard->tryMoveCurrentTetromino(1, 0))
if (movePieceSound == nullptr) sound->PlaySound(SoundName::MOVE_PIECE);
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
else {
Mix_PlayChannel(-1, movePieceSound, 0);
}
break; break;
case SDLK_DOWN: case SDLK_DOWN:
case SDLK_s: case SDLK_s:
if (!gameState.gameover && !gameState.startSequence) if (!gameState.gameover && !gameState.startSequence) {
gameBoard->moveToBottom( ); gameBoard->moveToBottom( );
sound->PlaySound(SoundName::PIECE_LANDED);
}
break; break;
case SDLK_SPACE: case SDLK_SPACE:
if (!gameState.gameover && !gameState.startSequence) if (!gameState.gameover && !gameState.startSequence)
gameBoard->tryRotateCurrentTetromino( ); if (gameBoard->tryRotateCurrentTetromino( ))
sound->PlaySound(SoundName::ROTATE_PIECE);
break; break;
case SDLK_ESCAPE: case SDLK_ESCAPE:
break; break;
case SDLK_g: case SDLK_g:
if (gameState.startSequence) { if (gameState.startSequence) {
gameState.startSequence = false; gameState.startSequence = false;
Mix_Chunk* menuSound = Mix_LoadWAV("assets/sound_effects/menu.wav"); sound->PlaySound(SoundName::MENU);
if (menuSound == nullptr)
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
else {
Mix_PlayChannel(-1, menuSound, 0);
}
} }
break; break;
case SDLK_r: case SDLK_r:
@@ -149,11 +124,10 @@ void Game::inputHandler( ) {
Mix_VolumeMusic(Mix_GetMusicVolume(bgm.get( )) - 8); Mix_VolumeMusic(Mix_GetMusicVolume(bgm.get( )) - 8);
break; break;
case SDLK_m: case SDLK_m:
if (Mix_PausedMusic( )) if (true)
Mix_ResumeMusic( ); sound->ResumeMusic( );
else else
Mix_PauseMusic( ); sound->PauseMusic( );
break; break;
default: default:
break; break;

View File

@@ -9,6 +9,7 @@ extern "C" {
#include "Renderer.hpp" #include "Renderer.hpp"
#include "GameBoard.hpp" #include "GameBoard.hpp"
#include "Sound.hpp"
using namespace std; using namespace std;
@@ -37,6 +38,8 @@ private:
bool quit = false; bool quit = false;
} gameState; } gameState;
const unique_ptr<Sound> sound;
public: public:
Game( ); Game( );

View File

@@ -2,7 +2,9 @@
#include <iostream> #include <iostream>
GameBoard::GameBoard( ) GameBoard::GameBoard( )
: lockedTetrominos(20, vector<int>(10, 0)), lockedColors(20, std::vector<SDL_Color>(10, { 0, 0, 0, 255 })), score(0), level(0), lines(0), collision(false) { : lockedTetrominos(20, vector<int>(10, 0)),
lockedColors(20, std::vector<SDL_Color>(10, { 0, 0, 0, 255 })), score(0), level(0), lines(0), collision(false),
sound(make_unique<Sound>( )) {
spawnNewTetromino( ); spawnNewTetromino( );
} }
@@ -16,20 +18,15 @@ bool GameBoard::tryMoveCurrentTetromino(int dx, int dy) {
return true; return true;
} }
void GameBoard::tryRotateCurrentTetromino( ) { bool GameBoard::tryRotateCurrentTetromino( ) {
if (!currentTetromino) return; if (!currentTetromino) return false;
currentTetromino->rotate(*this); currentTetromino->rotate(*this);
if (checkCollision(*currentTetromino)) if (checkCollision(*currentTetromino)) {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
currentTetromino->rotate(*this); currentTetromino->rotate(*this);
else { return false;
Mix_Chunk* rotateSound = Mix_LoadWAV("assets/sound_effects/rotate_piece.wav");
if (rotateSound == nullptr)
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
else {
Mix_PlayChannel(-1, rotateSound, 0);
}
} }
return true;
} }
bool GameBoard::checkCollision(const Tetromino& tetromino) const { bool GameBoard::checkCollision(const Tetromino& tetromino) const {
@@ -108,12 +105,7 @@ void GameBoard::lockTetromino( ) {
} }
} }
Mix_Chunk* pieceLanded = Mix_LoadWAV("assets/sound_effects/piece_landed.wav"); sound->PlaySound(SoundName::PIECE_LANDED);
if (pieceLanded == nullptr)
SDL_Log("Failed to play sound effect: %s", Mix_GetError( ));
else {
Mix_PlayChannel(-1, pieceLanded, 0);
}
} }
void GameBoard::clearLines( ) { void GameBoard::clearLines( ) {

View File

@@ -8,6 +8,7 @@ extern "C" {
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include "Tetromino.hpp" #include "Tetromino.hpp"
#include "Sound.hpp"
class GameBoard { class GameBoard {
private: private:
@@ -27,13 +28,15 @@ private:
int level; int level;
int lines; int lines;
const unique_ptr<Sound> sound;
public: public:
GameBoard( ); GameBoard( );
void update( ); void update( );
bool tryMoveCurrentTetromino(int dx, int dy); bool tryMoveCurrentTetromino(int dx, int dy);
void tryRotateCurrentTetromino( ); bool tryRotateCurrentTetromino( );
bool isValidPosition(const vector<vector<int>>& shape, int x, int y) const; bool isValidPosition(const vector<vector<int>>& shape, int x, int y) const;
void moveToBottom( ); bool moveToBottom( );
const bool isCollision( ) const; const bool isCollision( ) const;
const int getScore( ) const; const int getScore( ) const;

109
src/Sound.cpp Normal file
View File

@@ -0,0 +1,109 @@
#include "Sound.hpp"
Sound::Sound( ) {
if (!cachedSounds) {
cachedSounds = make_unique<unordered_map<SoundName, shared_ptr<Mix_Chunk>>>( );
cachedSounds->emplace(
SoundName::GAME_OVER,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/game_over.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::LINE_CLEAR,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/line_clear.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::MOVE_PIECE,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/move_piece.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::PIECE_LANDED,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/piece_landed.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::ROCKET_ENDING,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/rocket_ending.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::TETRIS_LINE_CLEAR,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/tetris_line_clear.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::LEVEL_UP,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/level_up.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::MENU,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/menu.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::PIECE_FALLING_AFTER_LINE_CLEAR,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/piece_falling_after_line_clear.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::PLAYER_SENDING_BLOCKS,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/player_sending_blocks.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
cachedSounds->emplace(
SoundName::ROTATE_PIECE,
std::shared_ptr<Mix_Chunk>(Mix_LoadWAV("assets/sound_effects/rotate_piece.wav"), [ ](Mix_Chunk* r) { Mix_FreeChunk(r); })
);
}
if (!cachedMusic) {
cachedMusic = make_unique<unordered_map<MusicName, shared_ptr<Mix_Music>>>( );
cachedMusic->emplace(
MusicName::MAIN_THEME,
shared_ptr<Mix_Music>(Mix_LoadMUS("assets/sound_tracks/bgm.mp3"), [ ](Mix_Music* r) {Mix_FreeMusic(r);})
);
}
}
bool Sound::PlaySound(SoundName soundName, int loop) {
auto it = cachedSounds->find(soundName);
if (it == cachedSounds->end( ) || !it->second) {
return false;
}
Mix_PlayChannel(-1, it->second.get( ), loop);
return true;
}
bool Sound::PlayMusic(MusicName musicName, int loop) {
auto it = cachedMusic->find(musicName);
if (it == cachedMusic->end( ) || !it->second) {
return false;
}
Mix_PlayMusic(it->second.get( ), loop);
return true;
}
bool Sound::PauseMusic( ) {
if (Mix_PlayingMusic( ) != 0)
Mix_PauseMusic( );
}
bool Sound::ResumeMusic( ) {
if (Mix_PausedMusic( ) == 0)
Mix_ResumeMusic( );
}
bool Sound::IncreaseVolume( ) {
int currentVolume = Mix_Volume(-1, -1);
if (currentVolume < MIX_MAX_VOLUME) {
Mix_Volume(-1, currentVolume + 2);
return true;
}
return false;
}
bool Sound::DecreaseVolume( ) {
int currentVolume = Mix_Volume(-1, -1);
if (currentVolume > 0) {
Mix_Volume(-1, currentVolume - 2);
return true;
}
return false;
}

46
src/Sound.hpp Normal file
View File

@@ -0,0 +1,46 @@
#pragma once
#include <unordered_map>
#include <memory>
#include <string>
extern "C" {
#include <SDL2/SDL_mixer.h>
}
enum class SoundName {
GAME_OVER,
LINE_CLEAR,
MOVE_PIECE,
PIECE_LANDED,
ROCKET_ENDING,
TETRIS_LINE_CLEAR,
LEVEL_UP,
MENU,
PIECE_FALLING_AFTER_LINE_CLEAR,
PLAYER_SENDING_BLOCKS,
ROTATE_PIECE
};
enum class MusicName {
MAIN_THEME
};
using namespace std;
class Sound {
private:
static unique_ptr <unordered_map<SoundName, shared_ptr<Mix_Chunk>>> cachedSounds;
static unique_ptr <unordered_map<MusicName, shared_ptr<Mix_Music>>> cachedMusic;
public:
Sound( );
bool PlaySound(SoundName soundName, int loop = 0);
bool PlayMusic(MusicName musicName, int loop = -1);
bool PauseMusic( );
bool ResumeMusic( );
bool IncreaseVolume( );
bool DecreaseVolume( );
};