- **Visual Effects**: Upgraded line clear particles to use the game's block texture instead of simple circles, matching the reference web game's aesthetic. - **Particle Physics**: Tuned particle velocity, gravity, and fade rates for a more dynamic explosion effect. - **Rendering Integration**: Updated [main.cpp](cci:7://file:///d:/Sites/Work/tetris/src/main.cpp:0:0-0:0) and `GameRenderer` to pass the block texture to the effect system and correctly trigger animations upon line completion. - **Menu UI**: Fixed [MenuState](cci:1://file:///d:/Sites/Work/tetris/src/states/MenuState.cpp:19:0-19:55) layout calculations to use fixed logical dimensions (1200x1000), ensuring consistent centering and alignment of the logo, buttons, and settings icon across different window sizes. - **Code Cleanup**: Refactored `PlayingState` to delegate effect triggering to the rendering layer where correct screen coordinates are available.
129 lines
3.6 KiB
Markdown
129 lines
3.6 KiB
Markdown
# SOLID Principles Refactoring Plan
|
|
|
|
## Current Architecture Issues
|
|
|
|
### 1. Single Responsibility Principle (SRP) Violations
|
|
- `ApplicationManager` handles initialization, coordination, rendering coordination, and asset management
|
|
- `Game` class mixes game logic with some presentation concerns
|
|
|
|
### 2. Open/Closed Principle (OCP) Opportunities
|
|
- Hard-coded piece types and behaviors
|
|
- Limited extensibility for new game modes or rule variations
|
|
|
|
### 3. Dependency Inversion Principle (DIP) Missing
|
|
- Concrete dependencies instead of interfaces
|
|
- Direct instantiation rather than dependency injection
|
|
|
|
## Proposed Improvements
|
|
|
|
### 1. Extract Interfaces
|
|
|
|
```cpp
|
|
// src/core/interfaces/IRenderer.h
|
|
class IRenderer {
|
|
public:
|
|
virtual ~IRenderer() = default;
|
|
virtual void clear(uint8_t r, uint8_t g, uint8_t b, uint8_t a) = 0;
|
|
virtual void present() = 0;
|
|
virtual SDL_Renderer* getSDLRenderer() = 0;
|
|
};
|
|
|
|
// src/core/interfaces/IAudioSystem.h
|
|
class IAudioSystem {
|
|
public:
|
|
virtual ~IAudioSystem() = default;
|
|
virtual void playSound(const std::string& name) = 0;
|
|
virtual void playMusic(const std::string& name) = 0;
|
|
virtual void setMasterVolume(float volume) = 0;
|
|
};
|
|
|
|
// src/core/interfaces/IAssetLoader.h
|
|
class IAssetLoader {
|
|
public:
|
|
virtual ~IAssetLoader() = default;
|
|
virtual SDL_Texture* loadTexture(const std::string& path) = 0;
|
|
virtual void loadFont(const std::string& name, const std::string& path, int size) = 0;
|
|
};
|
|
```
|
|
|
|
### 2. Dependency Injection Container
|
|
|
|
```cpp
|
|
// src/core/ServiceContainer.h
|
|
class ServiceContainer {
|
|
private:
|
|
std::unordered_map<std::type_index, std::shared_ptr<void>> services;
|
|
|
|
public:
|
|
template<typename T>
|
|
void registerService(std::shared_ptr<T> service) {
|
|
services[std::type_index(typeid(T))] = service;
|
|
}
|
|
|
|
template<typename T>
|
|
std::shared_ptr<T> getService() {
|
|
auto it = services.find(std::type_index(typeid(T)));
|
|
if (it != services.end()) {
|
|
return std::static_pointer_cast<T>(it->second);
|
|
}
|
|
return nullptr;
|
|
}
|
|
};
|
|
```
|
|
|
|
### 3. Break Down ApplicationManager
|
|
|
|
```cpp
|
|
// src/core/ApplicationLifecycle.h
|
|
class ApplicationLifecycle {
|
|
public:
|
|
bool initialize(int argc, char* argv[]);
|
|
void run();
|
|
void shutdown();
|
|
};
|
|
|
|
// src/core/SystemCoordinator.h
|
|
class SystemCoordinator {
|
|
public:
|
|
void initializeSystems(ServiceContainer& container);
|
|
void updateSystems(double deltaTime);
|
|
void shutdownSystems();
|
|
};
|
|
```
|
|
|
|
### 4. Strategy Pattern for Game Rules
|
|
|
|
```cpp
|
|
// src/gameplay/interfaces/IGameRules.h
|
|
class IGameRules {
|
|
public:
|
|
virtual ~IGameRules() = default;
|
|
virtual int calculateScore(int linesCleared, int level) = 0;
|
|
virtual double getGravitySpeed(int level) = 0;
|
|
virtual bool shouldLevelUp(int lines) = 0;
|
|
};
|
|
|
|
// src/gameplay/rules/ClassicTetrisRules.h
|
|
class ClassicTetrisRules : public IGameRules {
|
|
public:
|
|
int calculateScore(int linesCleared, int level) override;
|
|
double getGravitySpeed(int level) override;
|
|
bool shouldLevelUp(int lines) override;
|
|
};
|
|
```
|
|
|
|
## Implementation Priority
|
|
|
|
1. **Phase 1**: Extract core interfaces (IRenderer, IAudioSystem)
|
|
2. **Phase 2**: Implement dependency injection container
|
|
3. **Phase 3**: Break down ApplicationManager responsibilities
|
|
4. **Phase 4**: Add strategy patterns for game rules
|
|
5. **Phase 5**: Improve testability with mock implementations
|
|
|
|
## Benefits
|
|
|
|
- **Testability**: Easy to mock dependencies for unit tests
|
|
- **Extensibility**: New features without modifying existing code
|
|
- **Maintainability**: Clear responsibilities and loose coupling
|
|
- **Flexibility**: Easy to swap implementations (e.g., different renderers)
|