feat: implement textured line clear effects and refine UI alignment

- **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.
This commit is contained in:
2025-11-21 21:19:14 +01:00
parent b5ef9172b3
commit 66099809e0
47 changed files with 5547 additions and 267 deletions

View File

@ -0,0 +1,128 @@
# 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)