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"
}