Files
spacetris/docs/REFACTORING_SOLID_PRINCIPLES.md
Gregor Klevze 66099809e0 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.
2025-11-21 21:19:14 +01:00

3.6 KiB

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

// 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

// 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

// 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

// 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)