# CollisionSystem

This system checks for collisions between entities, particularly between players and enemies. It uses position and hitbox components to determine collisions and triggers appropriate responses such as game over callbacks.

```cpp
class CollisionSystem : public System {
public:
    /**
     * @brief Construct a new Collision System object.
     *
     * @param gameOverCallback Callback function to be called when a collision resulting in game over is detected.
     * @param enemyEntityIds A set containing the IDs of enemy entities to check for collisions.
     * @param collisionThresholdX The horizontal threshold for collision detection.
     * @param collisionThresholdY The vertical threshold for collision detection.
     */
    CollisionSystem(std::function<void(int)> gameOverCallback, 
                    const std::set<int>& enemyEntityIds, 
                    float collisionThresholdX, 
                    float collisionThresholdY)
        : gameOverCallback_(gameOverCallback), 
          enemyEntityIds_(enemyEntityIds), 
          collisionThresholdX_(collisionThresholdX), 
          collisionThresholdY_(collisionThresholdY) {}

    /**
     * @brief Update method overridden from System, checks for collisions between entities.
     * 
     * @param dt Delta time since the last update call (not used in this system).
     * @param components A reference to the map storing all components associated with their entity IDs.
     */
    void update(float /*dt*/, 
                std::unordered_map<std::pair<std::type_index, int>, 
                std::shared_ptr<Component>, PairHash>& components) override {
        for (int enemyId : enemyEntityIds_) {
            checkCollisionsWithEnemy(enemyId, components);
        }
    }

    /**
     * @brief Checks for collisions between a specific enemy entity and all player entities.
     * 
     * @param enemyId The ID of the enemy entity to check for collisions.
     * @param components A reference to the map storing all components associated with their entity IDs.
     */
    void checkCollisionsWithEnemy(int enemyId, 
            std::unordered_map<std::pair<std::type_index, int>, 
            std::shared_ptr<Component>, PairHash>& components) {
        auto enemyPosComp = std::dynamic_pointer_cast<PositionComponent>(
                            components[{typeid(PositionComponent), enemyId}]);
        auto enemyHitboxComp = std::dynamic_pointer_cast<HitboxComponent>(
                            components[{typeid(HitboxComponent), enemyId}]);

        if (!enemyPosComp || !enemyHitboxComp) {
            return;  // Enemy components not found, skip
        }

        for (auto& pair : components) {
            int playerId = -1;
            if (pair.first.first == typeid(PositionComponent) && pair.first.second != enemyId) {
                playerId = pair.first.second;
                auto playerPosComp = std::dynamic_pointer_cast<PositionComponent>(pair.second);
                auto playerHitboxComp = std::dynamic_pointer_cast<HitboxComponent>(
                                components[{typeid(HitboxComponent), pair.first.second}]);

                if (playerPosComp && playerHitboxComp) {
                    if (isCollision(playerPosComp, playerHitboxComp, enemyPosComp, enemyHitboxComp)) {
                        if (processedCollisions_.find({playerId, enemyId}) == processedCollisions_.end()) {
                            // New collision detected, call the callback
                            gameOverCallback_(playerId);

                            // Mark this collision as processed
                            processedCollisions_.insert({playerId, enemyId});
                        }
                    } else {
                        // If there's no collision, remove from processed collisions
                        processedCollisions_.erase({playerId, enemyId});
                    }
                }
            }
        }
    }

    /**
     * @brief Determines if there is a collision between a player and an enemy entity.
     * 
     * @param playerPosComp Position component of the player entity.
     * @param playerHitboxComp Hitbox component of the player entity.
     * @param enemyPosComp Position component of the enemy entity.
     * @param enemyHitboxComp Hitbox component of the enemy entity.
     * @return true if a collision is detected, false otherwise.
     */
    bool isCollision(std::shared_ptr<PositionComponent> playerPosComp, 
                     std::shared_ptr<HitboxComponent> playerHitboxComp,
                     std::shared_ptr<PositionComponent> enemyPosComp, 
                     std::shared_ptr<HitboxComponent> enemyHitboxComp) {
        return playerPosComp->x < enemyPosComp->x + enemyHitboxComp->width &&
               playerPosComp->x + playerHitboxComp->width > enemyPosComp->x &&
               playerPosComp->y < enemyPosComp->y + enemyHitboxComp->height &&
               playerPosComp->y + playerHitboxComp->height > enemyPosComp->y;
    }

    /**
     * @brief Updates the set of enemy entity IDs to be checked for collisions.
     * 
     * @param enemyEntityIds The new set of enemy entity IDs.
     */
    void updateEnemyEntityIds(const std::set<int>& enemyEntityIds) {
        enemyEntityIds_ = enemyEntityIds;
    }

private:
    std::function<void(int)> gameOverCallback_; ///< Callback function for game over events.
    std::set<int> enemyEntityIds_; ///< Set of enemy entity IDs to check for collisions.
    float collisionThresholdX_; ///< Horizontal threshold for collision detection.
    float collisionThresholdY_; ///< Vertical threshold for collision detection.
    std::set<std::pair<int, int>> processedCollisions_; ///< Set of processed collisions to avoid repeated processing.
};
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://r-type-5.gitbook.io/r-type/development-guidelines/ecs/collisionsystem.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
