|
#include <iostream> |
|
#include <vector> |
|
#include <memory> |
|
|
|
class GameUI { |
|
public: |
|
void showGameOver() { /* Implementation */ } |
|
void updateEnemyCount() { /* Implementation */ } |
|
}; |
|
|
|
class AchievementSystem { |
|
public: |
|
void unlockAchievement(const std::string& achievement) { /* Implementation */ } |
|
void incrementEnemyKillCount() { /* Implementation */ } |
|
}; |
|
|
|
class LeaderboardSystem { |
|
public: |
|
void submitScore(int score) { /* Implementation */ } |
|
}; |
|
|
|
class AudioManager { |
|
public: |
|
void playSound(const std::string& soundName) { /* Implementation */ } |
|
}; |
|
|
|
class ParticleSystem { |
|
public: |
|
void spawnDeathParticles(const Vector2D& position) { /* Implementation */ } |
|
}; |
|
|
|
class Player { |
|
public: |
|
Player(GameUI* ui, AchievementSystem* achievements, LeaderboardSystem* leaderboard, |
|
AudioManager* audio, ParticleSystem* particles) |
|
: m_ui(ui), m_achievements(achievements), m_leaderboard(leaderboard), |
|
m_audio(audio), m_particles(particles) {} |
|
|
|
void takeDamage(int amount) { |
|
health -= amount; |
|
if (health <= 0) { |
|
// Update UI |
|
m_ui->showGameOver(); |
|
// Update achievements |
|
m_achievements->unlockAchievement("Game Over"); |
|
// Update leaderboard |
|
m_leaderboard->submitScore(score); |
|
// Play sound |
|
m_audio->playSound("player_death"); |
|
// Spawn particles |
|
m_particles->spawnDeathParticles(position); |
|
} |
|
} |
|
|
|
void addScore(int amount) { |
|
score += amount; |
|
} |
|
|
|
private: |
|
int health; |
|
int score; |
|
Vector2D position; |
|
GameUI* m_ui; |
|
AchievementSystem* m_achievements; |
|
LeaderboardSystem* m_leaderboard; |
|
AudioManager* m_audio; |
|
ParticleSystem* m_particles; |
|
}; |
|
|
|
class Enemy { |
|
public: |
|
Enemy(GameUI* ui, AchievementSystem* achievements, Player* player, |
|
AudioManager* audio, ParticleSystem* particles) |
|
: m_ui(ui), m_achievements(achievements), m_player(player), |
|
m_audio(audio), m_particles(particles) {} |
|
|
|
void die() { |
|
// Update UI |
|
m_ui->updateEnemyCount(); |
|
// Update achievements |
|
m_achievements->incrementEnemyKillCount(); |
|
// Update player score |
|
m_player->addScore(100); |
|
// Play sound |
|
m_audio->playSound("enemy_death"); |
|
// Spawn particles |
|
m_particles->spawnDeathParticles(position); |
|
} |
|
|
|
private: |
|
Vector2D position; |
|
GameUI* m_ui; |
|
AchievementSystem* m_achievements; |
|
Player* m_player; |
|
AudioManager* m_audio; |
|
ParticleSystem* m_particles; |
|
}; |
|
|
|
/* |
|
This main function does the following: |
|
Creates instances of all the required systems (GameUI, AchievementSystem, etc.). |
|
Creates a Player instance, passing in pointers to all the required systems. |
|
Creates a vector of Enemy instances (in this case, 3 enemies). |
|
|
|
Simulates some game actions: |
|
The player takes some damage |
|
An enemy dies |
|
The player takes fatal damage |
|
*/ |
|
|
|
int main() { |
|
// Create instances of the required systems |
|
auto ui = std::make_unique<GameUI>(); |
|
auto achievements = std::make_unique<AchievementSystem>(); |
|
auto leaderboard = std::make_unique<LeaderboardSystem>(); |
|
auto audio = std::make_unique<AudioManager>(); |
|
auto particles = std::make_unique<ParticleSystem>(); |
|
|
|
// Create a player |
|
Player player(ui.get(), achievements.get(), leaderboard.get(), audio.get(), particles.get()); |
|
|
|
// Create some enemies |
|
std::vector<std::unique_ptr<Enemy>> enemies; |
|
for (int i = 0; i < 3; ++i) { |
|
enemies.push_back(std::make_unique<Enemy>(ui.get(), achievements.get(), &player, audio.get(), particles.get())); |
|
} |
|
|
|
// Simulate some game actions |
|
std::cout << "Simulating game actions:\n"; |
|
|
|
std::cout << "Player takes damage\n"; |
|
player.takeDamage(50); |
|
|
|
std::cout << "Enemy dies\n"; |
|
enemies[0]->die(); |
|
|
|
std::cout << "Player dies\n"; |
|
player.takeDamage(100); |
|
|
|
return 0; |
|
} |
The refactored version using the Observer pattern offers several improvements:
Decoupling: Player and Enemy are no longer directly dependent on other systems. They simply notify observers of events.
Single Responsibility: Each class now has a more focused responsibility. Player and Enemy manage their own state and notify of changes, while other systems react to these notifications.
Extensibility: New observers can be added without modifying Player or Enemy. For example, adding a new achievement or UI element becomes trivial.
Flexibility: Observers can be dynamically added or removed at runtime.
Improved testability: Each component can be easily tested in isolation.
Cleaner main function: The main function is now simpler and doesn't need to manage as many dependencies.
This implementation demonstrates how the Observer pattern can significantly improve the structure and maintainability of the game code.