reworking sound system
This commit is contained in:
@@ -3,8 +3,10 @@ cmake_minimum_required(VERSION 3.5)
|
||||
project(SDL_TD VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
# Find SDL2
|
||||
find_package(SDL2 QUIET)
|
||||
find_package(SDL2 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_DIRS ${SDL2_INCLUDE_DIRS})
|
||||
|
||||
62
src/Game.cpp
62
src/Game.cpp
@@ -1,6 +1,6 @@
|
||||
#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) {
|
||||
window.reset(SDL_CreateWindow(
|
||||
@@ -34,15 +34,6 @@ bool Game::init(const char* title, int w, int h) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -53,7 +44,7 @@ void Game::run( ) {
|
||||
gameRenderer->renderStartScreen( );
|
||||
}
|
||||
|
||||
Mix_PlayMusic(bgm.get( ), -1);
|
||||
sound->PlayMusic(MusicName::MAIN_THEME);
|
||||
|
||||
lastUpdateTime = SDL_GetTicks( );
|
||||
while (!gameState.gameover && !gameBoard->isCollision( )) {
|
||||
@@ -62,15 +53,10 @@ void Game::run( ) {
|
||||
update( );
|
||||
render( );
|
||||
}
|
||||
gameState.gameover = true;
|
||||
Mix_PauseMusic( );
|
||||
|
||||
Mix_Chunk* game_over = Mix_LoadWAV("assets/sound_effects/game_over.wav");
|
||||
if (game_over == nullptr)
|
||||
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
|
||||
else {
|
||||
Mix_PlayChannel(-1, game_over, 0);
|
||||
}
|
||||
gameState.gameover = true;
|
||||
sound->PauseMusic( );
|
||||
sound->PlaySound(SoundName::GAME_OVER);
|
||||
|
||||
while (gameState.gameover) {
|
||||
if (gameState.quit) return;
|
||||
@@ -83,7 +69,6 @@ void Game::run( ) {
|
||||
|
||||
void Game::inputHandler( ) {
|
||||
SDL_Event event;
|
||||
Mix_Chunk* movePieceSound = Mix_LoadWAV("assets/sound_effects/move_piece.wav");
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SDL_QUIT) {
|
||||
SDL_Quit( );
|
||||
@@ -93,43 +78,33 @@ void Game::inputHandler( ) {
|
||||
case SDLK_LEFT:
|
||||
case SDLK_a:
|
||||
if (!gameState.gameover && !gameState.startSequence)
|
||||
gameBoard->tryMoveCurrentTetromino(-1, 0);
|
||||
if (movePieceSound == nullptr)
|
||||
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
|
||||
else {
|
||||
Mix_PlayChannel(-1, movePieceSound, 0);
|
||||
}
|
||||
if (gameBoard->tryMoveCurrentTetromino(-1, 0))
|
||||
sound->PlaySound(SoundName::MOVE_PIECE);
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
case SDLK_d:
|
||||
if (!gameState.gameover && !gameState.startSequence)
|
||||
gameBoard->tryMoveCurrentTetromino(1, 0);
|
||||
if (movePieceSound == nullptr)
|
||||
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
|
||||
else {
|
||||
Mix_PlayChannel(-1, movePieceSound, 0);
|
||||
}
|
||||
if (gameBoard->tryMoveCurrentTetromino(1, 0))
|
||||
sound->PlaySound(SoundName::MOVE_PIECE);
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
case SDLK_s:
|
||||
if (!gameState.gameover && !gameState.startSequence)
|
||||
if (!gameState.gameover && !gameState.startSequence) {
|
||||
gameBoard->moveToBottom( );
|
||||
sound->PlaySound(SoundName::PIECE_LANDED);
|
||||
}
|
||||
break;
|
||||
case SDLK_SPACE:
|
||||
if (!gameState.gameover && !gameState.startSequence)
|
||||
gameBoard->tryRotateCurrentTetromino( );
|
||||
if (gameBoard->tryRotateCurrentTetromino( ))
|
||||
sound->PlaySound(SoundName::ROTATE_PIECE);
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
break;
|
||||
case SDLK_g:
|
||||
if (gameState.startSequence) {
|
||||
gameState.startSequence = false;
|
||||
Mix_Chunk* menuSound = Mix_LoadWAV("assets/sound_effects/menu.wav");
|
||||
if (menuSound == nullptr)
|
||||
SDL_Log("Failed to play rotate sound effect: %s", Mix_GetError( ));
|
||||
else {
|
||||
Mix_PlayChannel(-1, menuSound, 0);
|
||||
}
|
||||
sound->PlaySound(SoundName::MENU);
|
||||
}
|
||||
break;
|
||||
case SDLK_r:
|
||||
@@ -149,11 +124,10 @@ void Game::inputHandler( ) {
|
||||
Mix_VolumeMusic(Mix_GetMusicVolume(bgm.get( )) - 8);
|
||||
break;
|
||||
case SDLK_m:
|
||||
if (Mix_PausedMusic( ))
|
||||
Mix_ResumeMusic( );
|
||||
if (true)
|
||||
sound->ResumeMusic( );
|
||||
else
|
||||
Mix_PauseMusic( );
|
||||
|
||||
sound->PauseMusic( );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -9,6 +9,7 @@ extern "C" {
|
||||
|
||||
#include "Renderer.hpp"
|
||||
#include "GameBoard.hpp"
|
||||
#include "Sound.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -37,6 +38,8 @@ private:
|
||||
bool quit = false;
|
||||
} gameState;
|
||||
|
||||
const unique_ptr<Sound> sound;
|
||||
|
||||
public:
|
||||
Game( );
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include <iostream>
|
||||
|
||||
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( );
|
||||
}
|
||||
|
||||
@@ -16,20 +18,15 @@ bool GameBoard::tryMoveCurrentTetromino(int dx, int dy) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameBoard::tryRotateCurrentTetromino( ) {
|
||||
if (!currentTetromino) return;
|
||||
bool GameBoard::tryRotateCurrentTetromino( ) {
|
||||
if (!currentTetromino) return false;
|
||||
currentTetromino->rotate(*this);
|
||||
if (checkCollision(*currentTetromino))
|
||||
if (checkCollision(*currentTetromino)) {
|
||||
for (int i = 0; i < 3; i++)
|
||||
currentTetromino->rotate(*this);
|
||||
else {
|
||||
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 false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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");
|
||||
if (pieceLanded == nullptr)
|
||||
SDL_Log("Failed to play sound effect: %s", Mix_GetError( ));
|
||||
else {
|
||||
Mix_PlayChannel(-1, pieceLanded, 0);
|
||||
}
|
||||
sound->PlaySound(SoundName::PIECE_LANDED);
|
||||
}
|
||||
|
||||
void GameBoard::clearLines( ) {
|
||||
|
||||
@@ -8,6 +8,7 @@ extern "C" {
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include "Tetromino.hpp"
|
||||
#include "Sound.hpp"
|
||||
|
||||
class GameBoard {
|
||||
private:
|
||||
@@ -27,13 +28,15 @@ private:
|
||||
int level;
|
||||
int lines;
|
||||
|
||||
const unique_ptr<Sound> sound;
|
||||
|
||||
public:
|
||||
GameBoard( );
|
||||
void update( );
|
||||
bool tryMoveCurrentTetromino(int dx, int dy);
|
||||
void tryRotateCurrentTetromino( );
|
||||
bool tryRotateCurrentTetromino( );
|
||||
bool isValidPosition(const vector<vector<int>>& shape, int x, int y) const;
|
||||
void moveToBottom( );
|
||||
bool moveToBottom( );
|
||||
|
||||
const bool isCollision( ) const;
|
||||
const int getScore( ) const;
|
||||
|
||||
109
src/Sound.cpp
Normal file
109
src/Sound.cpp
Normal 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
46
src/Sound.hpp
Normal 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( );
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user