diff --git a/Arkanoid/Arkanoid.vcxproj b/Arkanoid/Arkanoid.vcxproj index d4ff605..8d2cb66 100644 --- a/Arkanoid/Arkanoid.vcxproj +++ b/Arkanoid/Arkanoid.vcxproj @@ -170,6 +170,9 @@ + + + @@ -196,12 +199,17 @@ + + + + + @@ -226,6 +234,7 @@ + diff --git a/Arkanoid/Arkanoid.vcxproj.filters b/Arkanoid/Arkanoid.vcxproj.filters index 8b32265..1a009a8 100644 --- a/Arkanoid/Arkanoid.vcxproj.filters +++ b/Arkanoid/Arkanoid.vcxproj.filters @@ -61,6 +61,12 @@ {1654612d-e2f7-4d8a-92b0-aa25e908bc0b} + + {28abb3a2-739e-4a92-9fed-d8bd8b87ebb1} + + + {c0c2398e-3653-45a6-8880-d3ef03be4dcb} + @@ -162,6 +168,21 @@ Header Files + + Header Files\Components\PowerUps + + + Header Files\Textures + + + Header Files\Textures + + + Header Files\Textures + + + Header Files + @@ -248,6 +269,18 @@ Source Files + + Source Files\Components\PowerUps + + + Source Files\Texture + + + Source Files\Texture + + + Source Files\Texture + diff --git a/Arkanoid/BallBehaviorComponent.cpp b/Arkanoid/BallBehaviorComponent.cpp index 59f66aa..6c29567 100644 --- a/Arkanoid/BallBehaviorComponent.cpp +++ b/Arkanoid/BallBehaviorComponent.cpp @@ -32,10 +32,10 @@ BallBehaviorComponent::BallBehaviorComponent(EntityID entityID, GameState* game, mTransform->setPosition(pos); - sf::SoundBuffer* buffer = ServiceLocator::getAudio()->getSound(SoundID::BALL_HIT_WALL); + sf::SoundBuffer* buffer = ServiceLocator::getAudioService()->getSound(SoundID::BALL_HIT_WALL); mHitSound.setBuffer(*buffer); - buffer = ServiceLocator::getAudio()->getSound(SoundID::BALL_HIT_BRICK); + buffer = ServiceLocator::getAudioService()->getSound(SoundID::BALL_HIT_BRICK); mHitBrickSound.setBuffer(*buffer); } diff --git a/Arkanoid/ComponentList.h b/Arkanoid/ComponentList.h index 02baa9c..8a579fe 100644 --- a/Arkanoid/ComponentList.h +++ b/Arkanoid/ComponentList.h @@ -16,6 +16,8 @@ enum CompType { CIRCLE_COLLIDER, STICKY, + DISRUPTION, + BOMBER, GAME_OVER_WATCHER, diff --git a/Arkanoid/GameOverWatcherComponent.cpp b/Arkanoid/GameOverWatcherComponent.cpp index eac69db..6874bbf 100644 --- a/Arkanoid/GameOverWatcherComponent.cpp +++ b/Arkanoid/GameOverWatcherComponent.cpp @@ -11,7 +11,7 @@ GameOverWatcherComponent::GameOverWatcherComponent(EntityID entityID, GameState* auto bricks = mGame->getAllEntitiesByType(EntityType::TAG_BRICK); mNumBricks = (int)bricks.size(); - sf::SoundBuffer* buffer = ServiceLocator::getAudio()->getSound(SoundID::BALL_LOST); + sf::SoundBuffer* buffer = ServiceLocator::getAudioService()->getSound(SoundID::BALL_LOST); mLostBallSound.setBuffer(*buffer); } diff --git a/Arkanoid/GameState.cpp b/Arkanoid/GameState.cpp index 9586c69..4af36b7 100644 --- a/Arkanoid/GameState.cpp +++ b/Arkanoid/GameState.cpp @@ -17,6 +17,7 @@ #include "PCAudioService.h" #include "ServiceLocator.h" +#include "PCTextureService.h" #include #include @@ -55,135 +56,155 @@ void GameState::enter() { std::cout << "GameState::enter" << std::endl; - // register types - using UniquePtrVector = std::vector; - for (size_t i = 0; i < CompType::COUNT; ++i) + try { - mCompMap.insert({ CompType(i), UniquePtrVector() }); - } + // register types + using UniquePtrVector = std::vector; + for (size_t i = 0; i < CompType::COUNT; ++i) + { + mCompMap.insert({ CompType(i), UniquePtrVector() }); + } - // load sounds - auto audioService = new PCAudioService(); + // load sounds + auto audioService = new PCAudioService(); - std::string sfxFolder = mTree.get("AUDIO_FOLDER"); - std::string musicFolder = mTree.get("MUSIC_FOLDER"); - std::vector sounds( + std::string sfxFolder = mTree.get("AUDIO_FOLDER"); + std::string musicFolder = mTree.get("MUSIC_FOLDER"); + std::vector sounds( + { + {SoundID::BALL_HIT_BRICK, mTree.get("AUDIO_BALL_HIT_BRICK")}, + {SoundID::BALL_HIT_WALL, mTree.get("AUDIO_BALL_HIT_WALL")}, + {SoundID::POWER_UP_PICKED, mTree.get("AUDIO_POWER_UP_PICKED")}, + {SoundID::BALL_LOST, mTree.get("AUDIO_BALL_LOST")}, + }); + std::vector musics( + { + {MusicID::MUSIC_GAME, mTree.get("GAME_MUSIC")}, + {MusicID::MUSIC_WIN, mTree.get("WIN_MUSIC")}, + {MusicID::MUSIC_LOSE, mTree.get("LOSE_MUSIC")}, + }); + + if (!audioService->initialize(sfxFolder, musicFolder, sounds, musics)) { - {SoundID::BALL_HIT_BRICK, mTree.get("AUDIO_BALL_HIT_BRICK")}, - {SoundID::BALL_HIT_WALL, mTree.get("AUDIO_BALL_HIT_WALL")}, - {SoundID::POWER_UP_PICKED, mTree.get("AUDIO_POWER_UP_PICKED")}, - {SoundID::BALL_LOST, mTree.get("AUDIO_BALL_LOST")}, - }); - std::vector musics( + throw std::exception("Error initializing the audio service"); + } + + ServiceLocator::provideAudioService(audioService); + + ServiceLocator::getAudioService()->playMusic(MusicID::MUSIC_GAME); + ServiceLocator::getAudioService()->setLooping(MusicID::MUSIC_GAME, true); + + buildLevel(); + + if (!mFont.loadFromFile("resources/joystix monospace.ttf")) { - {MusicID::MUSIC_GAME, mTree.get("GAME_MUSIC")}, - {MusicID::MUSIC_WIN, mTree.get("WIN_MUSIC")}, - {MusicID::MUSIC_LOSE, mTree.get("LOSE_MUSIC")}, - }); + throw std::exception("Error loading font"); + } - if (!audioService->initialize(sfxFolder, musicFolder, sounds, musics)) - { - throw "Error initializing the audio service"; - } + mRemainingLives = mTree.get("NUM_LIVES"); + mHighScore = mTree.get("HIGH_SCORE"); - ServiceLocator::provide(audioService); + mHighScoreText.setFont(mFont); + mHighScoreNumberText.setFont(mFont); - ServiceLocator::getAudio()->playMusic(MusicID::MUSIC_GAME); - ServiceLocator::getAudio()->setLooping(MusicID::MUSIC_GAME, true); + mCurrentScoreText.setFont(mFont); + mCurrentScoreNumberText.setFont(mFont); - buildLevel(); + mRemainingLivesText.setFont(mFont); + mRemainingLivesNumberText.setFont(mFont); - if (!mFont.loadFromFile("resources/joystix monospace.ttf")) - { - std::cout << "Error loading font" << std::endl; - } + mGameOverText.setFont(mFont); + mGameOverInstructionsText.setFont(mFont); + mGameOverInstructions2Text.setFont(mFont); - mRemainingLives = mTree.get("NUM_LIVES"); - mHighScore = mTree.get("HIGH_SCORE"); + mHighScoreText.setString("High score"); + mHighScoreNumberText.setString(std::to_string(mHighScore)); + mCurrentScoreText.setString("Score"); + mCurrentScoreNumberText.setString(std::to_string(mCurrentScore)); + mRemainingLivesText.setString("Lives"); + mRemainingLivesNumberText.setString(std::to_string(mRemainingLives)); + mGameOverText.setString("GAME OVER!"); + mGameOverInstructionsText.setString("Enter to restart"); + mGameOverInstructions2Text.setString("Escape to return to Menu"); - mHighScoreText.setFont(mFont); - mHighScoreNumberText.setFont(mFont); + sf::Vector2f textPos( + mWalls.getPosition().x + mWalls.getSize().x + 10.f, + mWalls.getPosition().y + 200.f); - mCurrentScoreText.setFont(mFont); - mCurrentScoreNumberText.setFont(mFont); + mHighScoreText.setPosition(textPos); - mRemainingLivesText.setFont(mFont); - mRemainingLivesNumberText.setFont(mFont); + textPos.y += mHighScoreText.getGlobalBounds().height + 5.f; + mHighScoreNumberText.setPosition(textPos); - mGameOverText.setFont(mFont); - mGameOverInstructionsText.setFont(mFont); - mGameOverInstructions2Text.setFont(mFont); + textPos.y += mHighScoreNumberText.getGlobalBounds().height + 50.f; + mCurrentScoreText.setPosition(textPos); - mHighScoreText.setString("High score"); - mHighScoreNumberText.setString(std::to_string(mHighScore)); - mCurrentScoreText.setString("Score"); - mCurrentScoreNumberText.setString(std::to_string(mCurrentScore)); - mRemainingLivesText.setString("Lives"); - mRemainingLivesNumberText.setString(std::to_string(mRemainingLives)); - mGameOverText.setString("GAME OVER!"); - mGameOverInstructionsText.setString("Enter to restart"); - mGameOverInstructions2Text.setString("Escape to return to Menu"); + textPos.y += mCurrentScoreText.getGlobalBounds().height + 5.f; + mCurrentScoreNumberText.setPosition(textPos); - sf::Vector2f textPos( - mWalls.getPosition().x + mWalls.getSize().x + 10.f, - mWalls.getPosition().y + 200.f); + textPos.y = mTree.get("SCREEN_HEIGHT") - mRemainingLivesText.getGlobalBounds().height * 2.f - mRemainingLivesNumberText.getGlobalBounds().height; + mRemainingLivesText.setPosition(textPos); - mHighScoreText.setPosition(textPos); + textPos.y += mRemainingLivesNumberText.getGlobalBounds().height + 5.f; + mRemainingLivesNumberText.setPosition(textPos); - textPos.y += mHighScoreText.getGlobalBounds().height + 5.f; - mHighScoreNumberText.setPosition(textPos); + mGameOverText.setPosition(mWalls.getPosition().x + mWalls.getSize().x * 0.5f - mGameOverText.getGlobalBounds().width * 0.5f, mWalls.getPosition().y + 90.f); - textPos.y += mHighScoreNumberText.getGlobalBounds().height + 50.f; - mCurrentScoreText.setPosition(textPos); + mGameOverInstructionsText.setPosition(mGameOverText.getPosition().x, + mWalls.getSize().y * 0.5f + mGameOverText.getGlobalBounds().height + 50.f); - textPos.y += mCurrentScoreText.getGlobalBounds().height + 5.f; - mCurrentScoreNumberText.setPosition(textPos); + mGameOverInstructions2Text.setPosition(mGameOverText.getPosition().x, + mGameOverInstructionsText.getPosition().y + mGameOverInstructionsText.getGlobalBounds().height + mGameOverInstructions2Text.getGlobalBounds().height + 5.f); - textPos.y = mTree.get("SCREEN_HEIGHT") - mRemainingLivesText.getGlobalBounds().height * 2.f - mRemainingLivesNumberText.getGlobalBounds().height; - mRemainingLivesText.setPosition(textPos); + mHighScoreText.setCharacterSize(20); + mHighScoreNumberText.setCharacterSize(20); + mCurrentScoreText.setCharacterSize(22); + mCurrentScoreNumberText.setCharacterSize(22); + mRemainingLivesText.setCharacterSize(20); + mRemainingLivesNumberText.setCharacterSize(20); - textPos.y += mRemainingLivesNumberText.getGlobalBounds().height + 5.f; - mRemainingLivesNumberText.setPosition(textPos); + mGameOverText.setCharacterSize(40); + mGameOverInstructionsText.setCharacterSize(20); + mGameOverInstructions2Text.setCharacterSize(20); - mGameOverText.setPosition(mWalls.getPosition().x + mWalls.getSize().x * 0.5f - mGameOverText.getGlobalBounds().width * 0.5f, mWalls.getPosition().y + 90.f); + mHighScoreText.setFillColor(sf::Color::Red); + mCurrentScoreText.setFillColor(sf::Color::Red); + mRemainingLivesText.setFillColor(sf::Color::Red); - mGameOverInstructionsText.setPosition(mGameOverText.getPosition().x, - mWalls.getSize().y * 0.5f + mGameOverText.getGlobalBounds().height + 50.f); + mGameOverText.setFillColor(sf::Color::Magenta); + mGameOverInstructionsText.setFillColor(sf::Color::Magenta); + mGameOverInstructions2Text.setFillColor(sf::Color::Magenta); - mGameOverInstructions2Text.setPosition(mGameOverText.getPosition().x, - mGameOverInstructionsText.getPosition().y + mGameOverInstructionsText.getGlobalBounds().height + mGameOverInstructions2Text.getGlobalBounds().height + 5.f); + auto textureService = new PCTextureService(); - mHighScoreText.setCharacterSize(20); - mHighScoreNumberText.setCharacterSize(20); - mCurrentScoreText.setCharacterSize(22); - mCurrentScoreNumberText.setCharacterSize(22); - mRemainingLivesText.setCharacterSize(20); - mRemainingLivesNumberText.setCharacterSize(20); + std::string textureFolder = mTree.get("TEXTURE_FOLDER"); + std::vector textures( + { + {TextureID::TEXTURE_BACKGROUND, mTree.get("BACKGROUND"), sf::IntRect()}, + {TextureID::TEXTURE_LOGO, mTree.get("LOGO_IMAGE"), sf::IntRect()}, + {TextureID::TEXTURE_BOMBER, mTree.get("BOMBER_IMAGE"), sf::IntRect(0, 0, 109, 166)} + }); - mGameOverText.setCharacterSize(40); - mGameOverInstructionsText.setCharacterSize(20); - mGameOverInstructions2Text.setCharacterSize(20); + if (!textureService->initialize(textureFolder, textures)) + { + throw std::exception("Error initializing the texture service"); + } - mHighScoreText.setFillColor(sf::Color::Red); - mCurrentScoreText.setFillColor(sf::Color::Red); - mRemainingLivesText.setFillColor(sf::Color::Red); + ServiceLocator::provideTextureService(textureService); - mGameOverText.setFillColor(sf::Color::Magenta); - mGameOverInstructionsText.setFillColor(sf::Color::Magenta); - mGameOverInstructions2Text.setFillColor(sf::Color::Magenta); + std::string filename = mTree.get("BACKGROUND"); - std::string filename = mTree.get("BACKGROUND"); + sf::Texture* backgroundTex = ServiceLocator::getTextureService()->getTexture(TextureID::TEXTURE_BACKGROUND); + mWalls.setTexture(backgroundTex); - if (!mBackgroundTexture.loadFromFile(filename)) + mPreviousTime = mClock.getElapsedTime().asSeconds(); + mTimeLag = 0.f; + mMSPerUpdate = mTree.get("MS_PER_UPDATE"); + } + catch (const std::exception& e) { - std::cout << "Error loading background image " << filename << std::endl; + std::cout << e.what() << std::endl; } - - mWalls.setTexture(&mBackgroundTexture); - - mPreviousTime = mClock.getElapsedTime().asSeconds(); - mTimeLag = 0.f; - mMSPerUpdate = mTree.get("MS_PER_UPDATE"); } void GameState::update() @@ -256,6 +277,10 @@ void GameState::updateGame(float elapsed) } } auto powerups = getComponentList(CompType::STICKY); + auto disruptionList = getComponentList(CompType::DISRUPTION); + auto bomberList = getComponentList(CompType::BOMBER); + powerups.insert(powerups.end(), disruptionList.begin(), disruptionList.end()); + powerups.insert(powerups.end(), bomberList.begin(), bomberList.end()); // append other power ups here... for (auto e : powerups) { @@ -402,7 +427,7 @@ void GameState::exit() pt::write_json("resources/settings.json", mTree); } - ServiceLocator::getAudio()->stopMusic(MusicID::MUSIC_GAME); + ServiceLocator::getAudioService()->stopMusic(MusicID::MUSIC_GAME); mWindow->clear(); } @@ -563,15 +588,15 @@ void GameState::gameOver(bool win) { mGameStatus = GameStatus::GAME_WIN; mGameOverText.setString("You WIN!"); - ServiceLocator::getAudio()->stopMusic(MusicID::MUSIC_GAME); - ServiceLocator::getAudio()->playMusic(MusicID::MUSIC_WIN); + ServiceLocator::getAudioService()->stopMusic(MusicID::MUSIC_GAME); + ServiceLocator::getAudioService()->playMusic(MusicID::MUSIC_WIN); } else { mGameStatus = GameStatus::GAME_LOSE; mGameOverText.setString("GAME OVER!"); - ServiceLocator::getAudio()->stopMusic(MusicID::MUSIC_GAME); - ServiceLocator::getAudio()->playMusic(MusicID::MUSIC_LOSE); + ServiceLocator::getAudioService()->stopMusic(MusicID::MUSIC_GAME); + ServiceLocator::getAudioService()->playMusic(MusicID::MUSIC_LOSE); } } @@ -590,12 +615,9 @@ void GameState::restartGame() mRemainingLives = mTree.get("NUM_LIVES"); mCurrentScore = 0; - ServiceLocator::getAudio()->stopMusic(MusicID::MUSIC_GAME); - ServiceLocator::getAudio()->playMusic(MusicID::MUSIC_GAME); - ServiceLocator::getAudio()->setLooping(MusicID::MUSIC_GAME, true); - // TODO mBackgroundMusic.stop(); - //mBackgroundMusic.play(); - //mBackgroundMusic.setLoop(true); + ServiceLocator::getAudioService()->stopMusic(MusicID::MUSIC_GAME); + ServiceLocator::getAudioService()->playMusic(MusicID::MUSIC_GAME); + ServiceLocator::getAudioService()->setLooping(MusicID::MUSIC_GAME, true); buildLevel(); diff --git a/Arkanoid/MenuState.cpp b/Arkanoid/MenuState.cpp index 289e1a2..70c3c00 100644 --- a/Arkanoid/MenuState.cpp +++ b/Arkanoid/MenuState.cpp @@ -5,6 +5,7 @@ #include "ServiceLocator.h" #include "PCAudioService.h" +#include "PCTextureService.h" #include @@ -36,24 +37,34 @@ void MenuState::enter() if (!audioService->initialize(sfxFolder, musicFolder, sounds, musics)) { - throw "Error initializing the audio service"; + throw std::exception("Error initializing the audio service"); } - ServiceLocator::provide(audioService); + ServiceLocator::provideAudioService(audioService); - ServiceLocator::getAudio()->playMusic(MusicID::MUSIC_MENU); + ServiceLocator::getAudioService()->playMusic(MusicID::MUSIC_MENU); - std::string filename = mTree.get("BACKGROUND"); + auto textureService = new PCTextureService(); - if (!mBackgroundTexture.loadFromFile(filename)) + std::string textureFolder = mTree.get("TEXTURE_FOLDER"); + std::vector textures( + { + {TextureID::TEXTURE_BACKGROUND, mTree.get("BACKGROUND"), sf::IntRect()}, + {TextureID::TEXTURE_LOGO, mTree.get("LOGO_IMAGE"), sf::IntRect()} + }); + + if (!textureService->initialize(textureFolder, textures)) { - throw "Error loading background image " + filename; + throw std::exception("Error initializing the texture service"); } + ServiceLocator::provideTextureService(textureService); + float screenSizeX = mTree.get("SCREEN_WIDTH"); float screenSizeY = mTree.get("SCREEN_HEIGHT"); - sf::Vector2u texSize = mBackgroundTexture.getSize(); + mBackgroundTexture = ServiceLocator::getTextureService()->getTexture(TextureID::TEXTURE_BACKGROUND); + sf::Vector2u texSize = mBackgroundTexture->getSize(); mBackground[0].position = sf::Vector2f(0.f, 0.f); mBackground[1].position = sf::Vector2f(screenSizeX, 0.f); @@ -65,20 +76,15 @@ void MenuState::enter() mBackground[2].texCoords = sf::Vector2f((float)texSize.x, (float)texSize.y); mBackground[3].texCoords = sf::Vector2f(0.f, (float)texSize.y); + sf::Texture* logoTex = ServiceLocator::getTextureService()->getTexture(TextureID::TEXTURE_LOGO); - filename = mTree.get("LOGO_IMAGE"); - if (!mLogoTexture.loadFromFile(filename)) - { - throw "Error loading background image " + filename; - } - - mLogo.setTexture(mLogoTexture); + mLogo.setTexture(*logoTex); - mLogo.setPosition(screenSizeX * 0.5f - mLogoTexture.getSize().x * 0.5f, screenSizeY * 0.5f - mLogoTexture.getSize().y * 0.5f - 100.f); + mLogo.setPosition(screenSizeX * 0.5f - logoTex->getSize().x * 0.5f, screenSizeY * 0.5f - logoTex->getSize().y * 0.5f - 100.f); if (!mFont.loadFromFile("resources/joystix monospace.ttf")) { - throw "Error loading font"; + throw std::exception("Error loading font"); } mPressEnterText.setFont(mFont); @@ -122,7 +128,7 @@ void MenuState::update() mWindow->clear(); - mWindow->draw(mBackground, &mBackgroundTexture); + mWindow->draw(mBackground, mBackgroundTexture); mWindow->draw(mLogo); mWindow->draw(mPressEnterText); mWindow->draw(mInstructionText); @@ -132,5 +138,5 @@ void MenuState::update() void MenuState::exit() { - ServiceLocator::getAudio()->stopMusic(MusicID::MUSIC_MENU); + ServiceLocator::getAudioService()->stopMusic(MusicID::MUSIC_MENU); } diff --git a/Arkanoid/MenuState.h b/Arkanoid/MenuState.h index 7c229cb..46509ea 100644 --- a/Arkanoid/MenuState.h +++ b/Arkanoid/MenuState.h @@ -32,10 +32,8 @@ class MenuState : pt::ptree& mTree; - sf::Texture mBackgroundTexture; + sf::Texture* mBackgroundTexture; sf::VertexArray mBackground; - - sf::Texture mLogoTexture; sf::Sprite mLogo; }; diff --git a/Arkanoid/MessageHandler.cpp b/Arkanoid/MessageHandler.cpp index eee7796..81389e8 100644 --- a/Arkanoid/MessageHandler.cpp +++ b/Arkanoid/MessageHandler.cpp @@ -23,7 +23,7 @@ void MessageHandler::receive(Message& msg, SendType sendType, const sf::Time& ti mDelayedMessages.push_back(std::make_pair(mClock.getElapsedTime() + timeToFire, msg)); // keep sorted by order of firing mDelayedMessages.sort([](const DelayedMsg& rhs, const DelayedMsg& lhs) { - return rhs.first > lhs.first; + return rhs.first < lhs.first; }); break; case IMMEDIATE: diff --git a/Arkanoid/MessageTypes.h b/Arkanoid/MessageTypes.h index 910c628..f7ecb92 100644 --- a/Arkanoid/MessageTypes.h +++ b/Arkanoid/MessageTypes.h @@ -22,6 +22,7 @@ enum MessageType { MSG_PU_END_EFFECT, MSG_PU_STICKY, MSG_PU_DISRUPTION, + MSG_PU_BOMBER, MSG_BALL_LOST, MSG_BRICK_DESTROYED, @@ -47,7 +48,7 @@ struct CollisionData : BaseData }; /// -/// For MSG_COLLISION messages +/// For MSG_PU_STICKY messages /// struct StickyData : BaseData { @@ -56,5 +57,15 @@ struct StickyData : BaseData virtual ~StickyData() {} }; +/// +/// For MSG_PU_BOMBER messages +/// +struct BomberData : BaseData +{ + bool start; + + virtual ~BomberData() {} +}; + #endif // !MESSAGE_TYPES_H diff --git a/Arkanoid/NullTextureService.cpp b/Arkanoid/NullTextureService.cpp new file mode 100644 index 0000000..b45c5a6 --- /dev/null +++ b/Arkanoid/NullTextureService.cpp @@ -0,0 +1,30 @@ +#include "NullTextureService.h" + + + +NullTextureService::NullTextureService() +{ +} + + +NullTextureService::~NullTextureService() +{ +} + +bool NullTextureService::loadTexture(const std::string & filename, TextureID id, const sf::IntRect & textureRect) +{ + filename; id; textureRect; + return false; +} + +sf::Texture * NullTextureService::getTexture(TextureID id) +{ + id; + return nullptr; +} + +sf::IntRect NullTextureService::getTextureRect(TextureID id) +{ + id; + return sf::IntRect(); +} diff --git a/Arkanoid/NullTextureService.h b/Arkanoid/NullTextureService.h new file mode 100644 index 0000000..9d1cb05 --- /dev/null +++ b/Arkanoid/NullTextureService.h @@ -0,0 +1,20 @@ +#ifndef NULL_TEXTURE_SERVICE_H +#define NULL_TEXTURE_SERVICE_H + +#include "TextureService.h" + +class NullTextureService : + public TextureService +{ +public: + NullTextureService(); + virtual ~NullTextureService(); + + // Inherited via TextureService + virtual bool loadTexture(const std::string & filename, TextureID id, const sf::IntRect & textureRect) override; + virtual sf::Texture * getTexture(TextureID id) override; + virtual sf::IntRect getTextureRect(TextureID id) override; +}; + + +#endif // !NULL_TEXTURE_SERVICE_H diff --git a/Arkanoid/PCAudioService.cpp b/Arkanoid/PCAudioService.cpp index 0cf4e6e..232c458 100644 --- a/Arkanoid/PCAudioService.cpp +++ b/Arkanoid/PCAudioService.cpp @@ -32,7 +32,6 @@ bool PCAudioService::initialize(const std::string& sfxFolder, const std::string& fs::path audioPath(sfxFolder); if (fs::is_directory(audioPath)) { - // preallocate all needed elements, this way I can access them by index mSoundBuffers.clear(); mSoundBuffers.insert(mSoundBuffers.end(), sfxFiles.size(), sf::SoundBuffer()); @@ -41,7 +40,8 @@ bool PCAudioService::initialize(const std::string& sfxFolder, const std::string& fs::path filePath(sfxFolder + pair.second); if (!fs::is_regular_file(filePath)) { - throw "Error opening " + filePath.filename().string(); + std::string err = "Error opening " + filePath.filename().string(); + throw std::exception(err.c_str()); } // SoundID is used both as enumerator for outside use and as index for fast retrieval @@ -49,20 +49,21 @@ bool PCAudioService::initialize(const std::string& sfxFolder, const std::string& if (!buffer.loadFromFile(filePath.string())) { - throw "Error loading " + filePath.string(); + std::string err = "Error loading " + filePath.string(); + throw std::exception(err.c_str()); } } } else { - throw "Invalid SFX path " + audioPath.string(); + std::string err = "Invalid SFX path " + audioPath.string(); + throw std::exception(err.c_str()); } fs::path musicPath(musicFolder); if (fs::is_directory(musicPath)) { - // preallocate all needed elements, this way I can access them by index mMusics.clear(); for (auto pair : musicFiles) @@ -70,7 +71,8 @@ bool PCAudioService::initialize(const std::string& sfxFolder, const std::string& fs::path filePath(musicFolder + pair.second); if (!fs::is_regular_file(filePath)) { - throw "Error opening " + filePath.filename().string(); + std::string err = "Error opening " + filePath.filename().string(); + throw std::exception(err.c_str()); } // SoundID is used both as enumerator for outside use and as index for fast retrieval @@ -78,7 +80,8 @@ bool PCAudioService::initialize(const std::string& sfxFolder, const std::string& if (!music->openFromFile(filePath.string())) { - throw "Error loading " + filePath.string(); + std::string err = "Error loading " + filePath.string(); + throw std::exception(err.c_str()); } mMusics[pair.first] = music; @@ -86,7 +89,8 @@ bool PCAudioService::initialize(const std::string& sfxFolder, const std::string& } else { - throw "Invalid music path " + musicPath.string(); + std::string err = "Invalid music path " + musicPath.string(); + throw std::exception(err.c_str()); } } catch (const std::exception& e) diff --git a/Arkanoid/PCTextureService.cpp b/Arkanoid/PCTextureService.cpp new file mode 100644 index 0000000..e81e719 --- /dev/null +++ b/Arkanoid/PCTextureService.cpp @@ -0,0 +1,109 @@ +#include "PCTextureService.h" + +#include +#include +#include + +#include + +namespace fs = boost::filesystem; +namespace pt = boost::property_tree; + +PCTextureService::PCTextureService() : + TextureService(), + mTextureMap() +{ +} + + +PCTextureService::~PCTextureService() +{ + clearTextures(); +} + +bool PCTextureService::initialize(const std::string & textureFolder, const std::vector& textures) +{ + try + { + fs::path texturePath(textureFolder); + + if (fs::is_directory(texturePath)) { + + clearTextures(); + + for (auto tup : textures) + { + fs::path filePath(textureFolder + std::get<1>(tup)); + if (!fs::is_regular_file(filePath)) + { + std::string err = "Error opening " + filePath.filename().string(); + throw std::exception(err.c_str()); + } + + + if (!loadTexture(textureFolder + std::get<1>(tup), std::get<0>(tup), std::get<2>(tup))) + { + std::string err = "Error loading " + filePath.string(); + throw std::exception(err.c_str()); + } + } + } + else + { + std::string err = "Invalid texture path " + texturePath.string(); + throw std::exception(err.c_str()); + } + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; + + return false; + } + + return true; +} + +bool PCTextureService::loadTexture(const std::string & filename, TextureID id, const sf::IntRect& textureRect) +{ + sf::Texture* tex = new sf::Texture(); + + if (!tex->loadFromFile(filename, textureRect)) + { + return false; + } + + mTextureMap[id] = std::make_pair(tex, textureRect); + + return true; +} + +sf::Texture* PCTextureService::getTexture(TextureID id) +{ + if (mTextureMap.count(id) > 0) + { + return mTextureMap[id].first; + } + + return nullptr; +} + +sf::IntRect PCTextureService::getTextureRect(TextureID id) +{ + if (mTextureMap.count(id) > 0) + { + return mTextureMap[id].second; + } + + return sf::IntRect(); +} + +void PCTextureService::clearTextures() +{ + for (auto it = mTextureMap.begin(); it != mTextureMap.end();) + { + // deallocate the texture + delete it->second.first; + it = mTextureMap.erase(it); + } +} diff --git a/Arkanoid/PCTextureService.h b/Arkanoid/PCTextureService.h new file mode 100644 index 0000000..05c49c0 --- /dev/null +++ b/Arkanoid/PCTextureService.h @@ -0,0 +1,32 @@ +#ifndef PC_TEXTURE_SERVICE_H +#define PC_TEXTURE_SERVICE_H + +#include "TextureService.h" + +#include +#include + +using TextureIDFilename = std::tuple; + +class PCTextureService : + public TextureService +{ +public: + PCTextureService(); + virtual ~PCTextureService(); + + bool initialize(const std::string& textureFolder, const std::vector& textures); + + // Inherited via TextureService + virtual bool loadTexture(const std::string & filename, TextureID id, const sf::IntRect& textureRect) override; + virtual sf::Texture* getTexture(TextureID id) override; + virtual sf::IntRect getTextureRect(TextureID id) override; + + void clearTextures(); + +private: + std::unordered_map mTextureMap; +}; + + +#endif // !PC_TEXTURE_SERVICE_H diff --git a/Arkanoid/PaddleBehaviorComponent.cpp b/Arkanoid/PaddleBehaviorComponent.cpp index ca8f42a..200dfe3 100644 --- a/Arkanoid/PaddleBehaviorComponent.cpp +++ b/Arkanoid/PaddleBehaviorComponent.cpp @@ -16,7 +16,9 @@ PaddleBehaviorComponent::PaddleBehaviorComponent(EntityID entityID, GameState* g BaseComponent(entityID, game), mVel(0.f, 0.f), mAccel(0.f, 0.f), - mState(PaddleState::STATE_START) + mState(PaddleState::STATE_START), + mElapsedEffectTime(sf::Time::Zero), + mPreviousColor(sf::Color::Transparent) { mWindow = mGame->getWindow(); @@ -32,7 +34,7 @@ PaddleBehaviorComponent::PaddleBehaviorComponent(EntityID entityID, GameState* g mPaddleMaxVel = config.get("PADDLE_MAX_VELOCITY"); mPaddleFriction = config.get("PADDLE_FRICTION"); - sf::SoundBuffer* buffer = ServiceLocator::getAudio()->getSound(SoundID::POWER_UP_PICKED); + sf::SoundBuffer* buffer = ServiceLocator::getAudioService()->getSound(SoundID::POWER_UP_PICKED); mPUSound.setBuffer(*buffer); } @@ -48,13 +50,15 @@ void PaddleBehaviorComponent::update(float elapsed) sf::Vector2f gameAreaSize(walls.getSize()); sf::Vector2f gameAreaPos(walls.getPosition()); - if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Left) || - sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) + if (!isDisabled() && + (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Left) || + sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A))) { mVel.x = -mPaddleMaxVel; } - else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Right) || - sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D)) + else if (!isDisabled() && + (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::Right) || + sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))) { mVel.x = mPaddleMaxVel; } @@ -75,6 +79,29 @@ void PaddleBehaviorComponent::update(float elapsed) sf::Vector2f(gameAreaPos.x + gameAreaSize.x - collSize.x, gameAreaSize.y - collSize.y)); } + + if (isDisabled()) + { + // start blinking the renderer + mElapsedEffectTime += mClock.getElapsedTime(); + + if (mElapsedEffectTime.asSeconds() >= 1.f) + { + mElapsedEffectTime = sf::Time::Zero; + + if (mPreviousColor == sf::Color::Transparent) + { + mPreviousColor = mRenderer->getShape().getFillColor(); + mRenderer->getShape().setFillColor(sf::Color::Transparent); + } + else + { + mRenderer->getShape().setFillColor(mPreviousColor); + mPreviousColor = sf::Color::Transparent; + } + } + //float + } } void PaddleBehaviorComponent::handleMessage(Message & msg) @@ -85,8 +112,9 @@ void PaddleBehaviorComponent::handleMessage(Message & msg) if (extraInfo->start) { + std::cout << "STICKY START " << std::endl; // start effect - mState = PaddleState::STATE_STICKY; + changeState(PaddleState::STATE_STICKY); mPUSound.play(); @@ -95,8 +123,9 @@ void PaddleBehaviorComponent::handleMessage(Message & msg) // if not sticky, this PU has been overwritten and this is an obsolete message, so I can ignore it else if(!extraInfo->start && isSticky()) { - mState = PaddleState::STATE_NORMAL; - mRenderer->getShape().setFillColor(sf::Color::Green); + std::cout << "STICKY END " << std::endl; + changeState(PaddleState::STATE_NORMAL); + //mRenderer->getShape().setFillColor(sf::Color::Green); // tell balls to go Message msgBall(mEntityID, MessageType::MSG_RELEASE_BALL); @@ -107,6 +136,32 @@ void PaddleBehaviorComponent::handleMessage(Message & msg) { mPUSound.play(); } + else if (msg.mType == MessageType::MSG_PU_BOMBER) + { + std::shared_ptr extraInfo = std::dynamic_pointer_cast(msg.mExtraInfo); + + if (extraInfo->start) + { + // start effect + std::cout << "Disable START " << std::endl; + changeState(PaddleState::STATE_DISABLED); + mElapsedEffectTime = sf::Time::Zero; + + mPUSound.play(); + } + // if not disabled, this PU has been overwritten and this is an obsolete message, so I can ignore it + else if (!extraInfo->start && isDisabled()) + { + std::cout << "Disable END " << std::endl; + changeState(mPreviousState); + + //if (mPreviousColor != sf::Color::Transparent) + //{ + // mRenderer->getShape().setFillColor(mPreviousColor); + // mPreviousColor = sf::Color::Transparent; + //} + } + } } float PaddleBehaviorComponent::getFriction() const @@ -139,8 +194,91 @@ bool PaddleBehaviorComponent::isNormal() const return mState == PaddleState::STATE_NORMAL; } +bool PaddleBehaviorComponent::isDisabled() const +{ + return mState == PaddleState::STATE_DISABLED; +} + void PaddleBehaviorComponent::changeState(PaddleState newState) { + std::string currentState, newStateString, prevState; + switch (mState) + { + case PaddleState::STATE_NORMAL: + currentState = "STATE_NORMAL"; + break; + case PaddleState::STATE_STICKY: + currentState = "STATE_STICKY"; + break; + case PaddleState::STATE_DISABLED: + currentState = "STATE_DISABLED"; + break; + case PaddleState::STATE_START: + currentState = "STATE_START"; + break; + } + + switch (newState) + { + case PaddleState::STATE_NORMAL: + newStateString = "STATE_NORMAL"; + break; + case PaddleState::STATE_STICKY: + newStateString = "STATE_STICKY"; + break; + case PaddleState::STATE_DISABLED: + newStateString = "STATE_DISABLED"; + break; + case PaddleState::STATE_START: + newStateString = "STATE_START"; + break; + } + + switch (mPreviousState) + { + case PaddleState::STATE_NORMAL: + prevState = "STATE_NORMAL"; + break; + case PaddleState::STATE_STICKY: + prevState = "STATE_STICKY"; + break; + case PaddleState::STATE_DISABLED: + prevState = "STATE_DISABLED"; + break; + case PaddleState::STATE_START: + prevState = "STATE_START"; + break; + } + + std::cout << "ChangeState" << std::endl; + std::cout << "Current " << currentState << std::endl; + std::cout << "New " << newStateString << std::endl; + std::cout << "Prev " << prevState << std::endl << std::endl; + + if (isDisabled() && mPreviousColor != sf::Color::Transparent) + { + mRenderer->getShape().setFillColor(mPreviousColor); + mPreviousColor = sf::Color::Transparent; + } + + if (isSticky()) + { + mRenderer->getShape().setFillColor(sf::Color::Green); + } + + if (!isNormal() && + newState == PaddleState::STATE_START) + { + mState = newState; + mPreviousState = PaddleState::STATE_NORMAL; + } + + // overwrite other powerups + if (mState != PaddleState::STATE_NORMAL) + { + mPreviousState = PaddleState::STATE_NORMAL; + } + mPreviousState = mState; mState = newState; } diff --git a/Arkanoid/PaddleBehaviorComponent.h b/Arkanoid/PaddleBehaviorComponent.h index 96bff85..9bc8ea0 100644 --- a/Arkanoid/PaddleBehaviorComponent.h +++ b/Arkanoid/PaddleBehaviorComponent.h @@ -17,7 +17,8 @@ enum class PaddleState STATE_STICKY, STATE_ENLARGED, STATE_LASER, - STATE_DISRUPTION + STATE_DISRUPTION, + STATE_DISABLED }; /// @@ -43,6 +44,7 @@ class PaddleBehaviorComponent : bool isSticky() const; bool isStarting() const; bool isNormal() const; + bool isDisabled() const; void changeState(PaddleState newState); @@ -61,8 +63,16 @@ class PaddleBehaviorComponent : float mPaddleFriction; PaddleState mState; + PaddleState mPreviousState; sf::Sound mPUSound; + + /// + /// To measure timed effects, such as disabled blinking + /// + sf::Clock mClock; + sf::Time mElapsedEffectTime; + sf::Color mPreviousColor; }; diff --git a/Arkanoid/PowerUpBomberComponent.cpp b/Arkanoid/PowerUpBomberComponent.cpp new file mode 100644 index 0000000..215d146 --- /dev/null +++ b/Arkanoid/PowerUpBomberComponent.cpp @@ -0,0 +1,54 @@ +#include "PowerUpBomberComponent.h" + +#include "GameState.h" +#include "BoxColliderComponent.h" +#include "CircleColliderComponent.h" +#include "TransformComponent.h" +#include "CircleRenderComponent.h" + +#include "PaddleBehaviorComponent.h" + +#include "AudioService.h" +#include "ServiceLocator.h" + +PowerUpBomberComponent::PowerUpBomberComponent(EntityID entityID, GameState* game, sf::Vector2f pos, sf::Texture* texture, sf::IntRect textureRect) : + PowerUpComponent(entityID, game, pos) +{ + mCollider = mGame->getComponent(CompType::CIRCLE_COLLIDER, getEntityID()); + mRenderer = mGame->getComponent(CompType::CIRCLE_RENDER, getEntityID()); + + mRenderer->getShape().setTexture(texture, true); + mRenderer->getShape().setTextureRect(textureRect); + + std::function cb = std::bind(&PowerUpBomberComponent::onCollisionCb, this, std::placeholders::_1); + + mCollider->setOnCollision(cb); + + mEffectDuration = mGame->config().get("POWER_UP_BOMBER_TIME_SEC"); +} + + +PowerUpBomberComponent::~PowerUpBomberComponent() +{ +} + +void PowerUpBomberComponent::onCollisionCb(const CollisionData & data) +{ + auto otherID = data.otherCollider->getEntityID(); + if (mGame->getEntityType(otherID) == EntityType::TAG_PLAYER) + { + auto paddleBehavior = mGame->getPaddleComponent(); + std::shared_ptr bomberData = std::make_shared(); + bomberData->start = true; + Message msg(mEntityID, MessageType::MSG_PU_BOMBER, bomberData); + paddleBehavior->receive(msg); + + // send delayed message to stop the effect + std::shared_ptr endData = std::make_shared(); + endData->start = false; + Message msgEnd(mEntityID, MessageType::MSG_PU_BOMBER, endData); + paddleBehavior->receive(msgEnd, SendType::DELAYED, sf::seconds(mEffectDuration)); + + mGame->destroyEntity(getEntityID()); + } +} diff --git a/Arkanoid/PowerUpBomberComponent.h b/Arkanoid/PowerUpBomberComponent.h new file mode 100644 index 0000000..c2c2b63 --- /dev/null +++ b/Arkanoid/PowerUpBomberComponent.h @@ -0,0 +1,26 @@ +#ifndef BOMBER_POWER_UP_COMPONENT_H +#define BOMBER_POWER_UP_COMPONENT_H + +#include "PowerUpComponent.h" + +class CircleColliderComponent; +class CircleRenderComponent; + +class PowerUpBomberComponent : + public PowerUpComponent +{ +public: + PowerUpBomberComponent(EntityID entityID, GameState* game, sf::Vector2f pos, sf::Texture* texture, sf::IntRect textureRect = sf::IntRect()); + virtual ~PowerUpBomberComponent(); + + void onCollisionCb(const CollisionData& data); + +private: + CircleColliderComponent* mCollider; + CircleRenderComponent* mRenderer; + + float mEffectDuration; +}; + + +#endif // !BOMBER_POWER_UP_COMPONENT_H diff --git a/Arkanoid/PowerUpService.cpp b/Arkanoid/PowerUpService.cpp index f5c9c55..3567d6c 100644 --- a/Arkanoid/PowerUpService.cpp +++ b/Arkanoid/PowerUpService.cpp @@ -8,9 +8,14 @@ #include "CircleColliderComponent.h" #include "RectRenderComponent.h" #include "CircleRenderComponent.h" +#include "SpriteRenderComponent.h" #include "PowerUpStickyComponent.h" #include "PowerUpDisruptionComponent.h" +#include "PowerUpBomberComponent.h" + +#include "PCTextureService.h" +#include "ServiceLocator.h" PowerUpService::PowerUpService(GameState* game) : @@ -26,8 +31,9 @@ PowerUpService::~PowerUpService() void PowerUpService::spawnRandomPU(const sf::Vector2f & pos) { + int chancePU = rand() % 100; - if (chancePU > 15) return; + if (chancePU > 20) return; PUType type = (PUType)(rand() % (PUType::PU_COUNT)); @@ -39,6 +45,9 @@ void PowerUpService::spawnRandomPU(const sf::Vector2f & pos) case PU_DISRUPTION: createDisruptionPU(pos); break; + case PU_BOMBER: + createBomberPU(pos); + break; default: break; } @@ -67,7 +76,29 @@ void PowerUpService::createDisruptionPU(const sf::Vector2f & pos) float radius = config.get("POWER_UP_SIZE"); + sf::Vector2f finalPos(pos.x - radius, pos.y - radius); + mGame->addComponent(CompType::CIRCLE_COLLIDER, id, radius); mGame->addComponent(CompType::CIRCLE_RENDER, id, radius, sf::Color(20, 180, 80)); - mGame->addComponent(CompType::STICKY, id, pos); + mGame->addComponent(CompType::DISRUPTION, id, finalPos); +} + +void PowerUpService::createBomberPU(const sf::Vector2f & pos) +{ + auto id = mGame->createEntity(EntityType::TAG_POWER_UP); + + std::cout << "BOMBER" << std::endl; + + auto config = mGame->config(); + + float radius = config.get("POWER_UP_BOMBER_SIZE"); + + sf::Vector2f finalPos(pos.x - radius, pos.y - radius); + + sf::Texture* tex = ServiceLocator::getTextureService()->getTexture(TextureID::TEXTURE_BOMBER); + sf::IntRect rect = ServiceLocator::getTextureService()->getTextureRect(TextureID::TEXTURE_BOMBER); + + mGame->addComponent(CompType::CIRCLE_COLLIDER, id, radius); + mGame->addComponent(CompType::CIRCLE_RENDER, id, radius, sf::Color::White); + mGame->addComponent(CompType::BOMBER, id, finalPos, tex, rect); } diff --git a/Arkanoid/PowerUpService.h b/Arkanoid/PowerUpService.h index 663bb35..51bcac9 100644 --- a/Arkanoid/PowerUpService.h +++ b/Arkanoid/PowerUpService.h @@ -11,6 +11,7 @@ enum PUType { PU_STICKY = 0, PU_DISRUPTION, + PU_BOMBER, PU_COUNT }; @@ -29,6 +30,7 @@ class PowerUpService private: void createStickyPU(const sf::Vector2f & pos); void createDisruptionPU(const sf::Vector2f & pos); + void createBomberPU(const sf::Vector2f & pos); private: GameState* mGame; diff --git a/Arkanoid/ServiceLocator.cpp b/Arkanoid/ServiceLocator.cpp index 362fd92..530435b 100644 --- a/Arkanoid/ServiceLocator.cpp +++ b/Arkanoid/ServiceLocator.cpp @@ -1,11 +1,14 @@ #include "ServiceLocator.h" #include "NullAudio.h" +#include "NullTextureService.h" std::unique_ptr ServiceLocator::mAudioService; +std::unique_ptr ServiceLocator::mTextureService; ServiceLocator::ServiceLocator() { - ServiceLocator::provide(nullptr); + ServiceLocator::provideAudioService(nullptr); + ServiceLocator::provideTextureService(nullptr); } @@ -13,12 +16,17 @@ ServiceLocator::~ServiceLocator() { } -AudioService * ServiceLocator::getAudio() +AudioService * ServiceLocator::getAudioService() { return ServiceLocator::mAudioService.get(); } -void ServiceLocator::provide(AudioService * service) +TextureService * ServiceLocator::getTextureService() +{ + return ServiceLocator::mTextureService.get(); +} + +void ServiceLocator::provideAudioService(AudioService * service) { if (service == nullptr) { @@ -29,3 +37,15 @@ void ServiceLocator::provide(AudioService * service) mAudioService.reset(service); } } + +void ServiceLocator::provideTextureService(TextureService * service) +{ + if (service == nullptr) + { + mTextureService.reset(new NullTextureService()); + } + else + { + mTextureService.reset(service); + } +} diff --git a/Arkanoid/ServiceLocator.h b/Arkanoid/ServiceLocator.h index 7b158c0..aff7c5b 100644 --- a/Arkanoid/ServiceLocator.h +++ b/Arkanoid/ServiceLocator.h @@ -2,6 +2,7 @@ #define SERVICE_LOCATOR_H #include "AudioService.h" +#include "TextureService.h" #include @@ -11,12 +12,15 @@ class ServiceLocator ServiceLocator(); ~ServiceLocator(); - static AudioService* getAudio(); + static AudioService* getAudioService(); + static TextureService* getTextureService(); - static void provide(AudioService* service); + static void provideAudioService(AudioService* service); + static void provideTextureService(TextureService* service); private: static std::unique_ptr mAudioService; + static std::unique_ptr mTextureService; }; diff --git a/Arkanoid/SpriteRenderComponent.h b/Arkanoid/SpriteRenderComponent.h index 56d6adc..220e665 100644 --- a/Arkanoid/SpriteRenderComponent.h +++ b/Arkanoid/SpriteRenderComponent.h @@ -17,6 +17,7 @@ class SpriteRenderComponent : /// The GameState pointer. /// The texture reference. /// The texture subrect to use. + /// The color to add to the sprite. SpriteRenderComponent(EntityID entityID, GameState* game, const sf::Texture& texture, const sf::IntRect& textureRect, const sf::Color& color = sf::Color::White); diff --git a/Arkanoid/TextureIDs.h b/Arkanoid/TextureIDs.h new file mode 100644 index 0000000..21027b9 --- /dev/null +++ b/Arkanoid/TextureIDs.h @@ -0,0 +1,11 @@ +#ifndef TEXTURE_ID_H +#define TEXTURE_ID_H + +enum TextureID +{ + TEXTURE_BACKGROUND, + TEXTURE_BOMBER, + TEXTURE_LOGO +}; + +#endif // !TEXTURE_ID_H diff --git a/Arkanoid/TextureService.cpp b/Arkanoid/TextureService.cpp new file mode 100644 index 0000000..ac18853 --- /dev/null +++ b/Arkanoid/TextureService.cpp @@ -0,0 +1,12 @@ +#include "TextureService.h" + + + +TextureService::TextureService() +{ +} + + +TextureService::~TextureService() +{ +} diff --git a/Arkanoid/TextureService.h b/Arkanoid/TextureService.h new file mode 100644 index 0000000..607673b --- /dev/null +++ b/Arkanoid/TextureService.h @@ -0,0 +1,27 @@ +#ifndef TEXTURE_SERVICE_H +#define TEXTURE_SERVICE_H + +#include + +#include "TextureIDs.h" + +#include + +using TexturePair = std::pair; + +/// +/// An interface for Texture managers (for different platforms or other cases). +/// +class TextureService +{ +public: + TextureService(); + virtual ~TextureService(); + + virtual bool loadTexture(const std::string& filename, TextureID id, const sf::IntRect& textureRect) = 0; + virtual sf::Texture* getTexture(TextureID id) = 0; + virtual sf::IntRect getTextureRect(TextureID id) = 0; +}; + + +#endif // !TEXTURE_SERVICE_H diff --git a/Arkanoid/World.cpp b/Arkanoid/World.cpp index fa7cb22..8898976 100644 --- a/Arkanoid/World.cpp +++ b/Arkanoid/World.cpp @@ -8,15 +8,22 @@ World::World() : mWindow(new sf::RenderWindow()), mCurrentState(nullptr) { - if (!loadFile("resources/settings.json")) + try { - std::cout << "Error reading settings.json file!" << std::endl; + if (!loadFile("resources/settings.json")) + { + throw std::exception("Error reading settings.json file!"); + } + + mWindow->create(sf::VideoMode(mTree.get("SCREEN_WIDTH"), + mTree.get("SCREEN_HEIGHT")), + "Arkanoid"); + mWindow->setVerticalSyncEnabled(true); + } + catch (const std::exception& e) + { + std::cout << e.what() << std::endl; } - - mWindow->create(sf::VideoMode( mTree.get("SCREEN_WIDTH"), - mTree.get("SCREEN_HEIGHT")), - "Arkanoid"); - mWindow->setVerticalSyncEnabled(true); } diff --git a/Arkanoid/resources/settings.json b/Arkanoid/resources/settings.json index ae72208..827a000 100644 --- a/Arkanoid/resources/settings.json +++ b/Arkanoid/resources/settings.json @@ -1,6 +1,7 @@ { "AUDIO_FOLDER": "./resources\/audio\/", "MUSIC_FOLDER": "./resources\/audio\/music\/", + "TEXTURE_FOLDER": "./resources\/sprites\/", "AUDIO_BALL_HIT_BRICK": "Ball_brick.wav", "AUDIO_BALL_HIT_WALL": "Hit_wall.wav", "AUDIO_POWER_UP_PICKED": "Powerup.wav", @@ -9,8 +10,9 @@ "WIN_MUSIC": "victory.wav", "LOSE_MUSIC": "lose.wav", "MENU_MUSIC": "menu_music.wav", - "BACKGROUND": "resources\/sprites\/hexagon_pattern.png", - "LOGO_IMAGE": "resources\/sprites\/arkanoid_logo.png", + "BACKGROUND": "hexagon_pattern.png", + "LOGO_IMAGE": "arkanoid_logo.png", + "BOMBER_IMAGE": "kamikaze_skeleton.PNG", "SCREEN_WIDTH": "1280", "SCREEN_HEIGHT": "768", "MS_PER_UPDATE": "0.0111", @@ -29,5 +31,7 @@ "POWER_UP_VELOCITY": "150", "POWER_UP_SIZE": "10", "POWER_UP_POINTS": "100", - "POWER_UP_STICKY_TIME_SEC": "10" + "POWER_UP_STICKY_TIME_SEC": "10", + "POWER_UP_BOMBER_TIME_SEC": "2", + "POWER_UP_BOMBER_SIZE": "30" }