From dc55af5323e5e19c669a5aa208b1589f7cde7467 Mon Sep 17 00:00:00 2001 From: DcruBro Date: Mon, 13 Apr 2026 14:03:59 +0200 Subject: [PATCH] box collider --- include/game/agame/player.hpp | 2 +- include/object/components/boxcollider.hpp | 10 ++++++ include/object/entity.hpp | 8 +++++ include/state/gamestate.hpp | 4 +-- include/utils.hpp | 1 + src/main.cpp | 4 ++- src/object/components/boxcollider.cpp | 40 +++++++++++++++++++++++ src/state/gamestate.cpp | 3 +- 8 files changed, 67 insertions(+), 5 deletions(-) diff --git a/include/game/agame/player.hpp b/include/game/agame/player.hpp index 7dc89ce..524b0ea 100644 --- a/include/game/agame/player.hpp +++ b/include/game/agame/player.hpp @@ -10,6 +10,6 @@ GAME_ENTITY(Player) private: Object::Sound mSound; float mSpeed = 200.f; // Pixels per second - float mHealth = 100.f; + [[maybe_unused]] float mHealth = 100.f; END_GAME_ENTITY() } \ No newline at end of file diff --git a/include/object/components/boxcollider.hpp b/include/object/components/boxcollider.hpp index 227eac0..da6f66b 100644 --- a/include/object/components/boxcollider.hpp +++ b/include/object/components/boxcollider.hpp @@ -1,8 +1,13 @@ #pragma once #include +#include namespace Game::Object::Components { + struct BoxColliderBounds { + float left, right, top, bottom; + }; + class BoxCollider : public Component { public: BoxCollider() = default; @@ -15,6 +20,11 @@ namespace Game::Object::Components { void start(Object::Entity* thisEntity) override; void update(float deltaTime, Object::Entity* thisEntity) override; + BoxColliderBounds getBounds() const { return mBounds; } + bool isColliding() const { return mIsColliding; } + private: + BoxColliderBounds mBounds; + bool mIsColliding = false; // Whether this collider is currently colliding with another collider; used to determine whether to call onCollisionEnter vs onCollisionStay, and to call onCollisionExit when collisions end }; } \ No newline at end of file diff --git a/include/object/entity.hpp b/include/object/entity.hpp index 396625c..aafb386 100644 --- a/include/object/entity.hpp +++ b/include/object/entity.hpp @@ -35,6 +35,14 @@ namespace Game::Object { virtual void destroyed() {}; // Pre-destruction call void render(Game::Renderer::Renderer* renderer, Game::Renderer::RendererConfig config); + // Collision calls + // Called once when a collision begins + virtual void onCollisionEnter(Entity* other) {} + // Called every update while a collision continues + virtual void onCollisionStay(Entity* other) {} + // Called once when a collision ends + virtual void onCollisionExit(Entity* other) {} + // Setters and getters void setTexture(std::shared_ptr tex) { mTex = tex; } void setName(const std::string& name) { mName = name; } diff --git a/include/state/gamestate.hpp b/include/state/gamestate.hpp index 04171a4..ebaaf4e 100644 --- a/include/state/gamestate.hpp +++ b/include/state/gamestate.hpp @@ -26,8 +26,8 @@ namespace Game::State { // Update entity at index, by REFERENCE. Object::Entity* getAtIndex(size_t at); - // Add an entity to the gamestate. - void addEntity(std::unique_ptr entity); + // Add an entity to the gamestate; Returns a temporary pointer to the entity added. Note that the validity of this pointer cannot be guaranteed after the first call. + Object::Entity* addEntity(std::unique_ptr entity); bool removeEntity(const std::string& name); private: diff --git a/include/utils.hpp b/include/utils.hpp index d660fe0..7548e36 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include diff --git a/src/main.cpp b/src/main.cpp index b1c5464..f4db427 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace Game; @@ -22,7 +23,8 @@ int main() { //Object::Transform t1{100.f, 100.f, 0.f, 1.f, 1.f}; State::GameState::getInstance().addEntity(std::make_unique("BG", std::make_shared("../resources/bgtest.png", window.getRenderer()->getSDLRenderer()), Object::DEFAULT_TRANSFORM)); - State::GameState::getInstance().addEntity(std::make_unique("Player", std::make_shared("../resources/l3ladja.png", window.getRenderer()->getSDLRenderer()), Object::DEFAULT_TRANSFORM)); + Object::Entity* player = State::GameState::getInstance().addEntity(std::make_unique("Player", std::make_shared("../resources/l3ladja.png", window.getRenderer()->getSDLRenderer()), Object::DEFAULT_TRANSFORM)); + player->addComponent(); //State::GameState::getInstance().addEntity(std::make_unique("Player2", std::make_shared("../resources/roboto.ttf", window.getRenderer()->getSDLRenderer(), 128, "Roboto"), t1)); window.run(); diff --git a/src/object/components/boxcollider.cpp b/src/object/components/boxcollider.cpp index c11758c..8fb9f15 100644 --- a/src/object/components/boxcollider.cpp +++ b/src/object/components/boxcollider.cpp @@ -1,4 +1,5 @@ #include +#include namespace Game::Object::Components { BoxCollider::BoxCollider(const BoxCollider& other) : Component(other) { @@ -31,5 +32,44 @@ namespace Game::Object::Components { void BoxCollider::update(float deltaTime, Object::Entity* thisEntity) { // Collision detection and response logic can go here + + // Make box bounds + Transform* transform = thisEntity->getTransform(); + float halfWidth = transform->scaleX * UNIVERSAL_SCALE_COEFFICIENT * 0.5f; + float halfHeight = transform->scaleY * UNIVERSAL_SCALE_COEFFICIENT * 0.5f; + float left = transform->x - halfWidth; + float right = transform->x + halfWidth; + float top = transform->y - halfHeight; + float bottom = transform->y + halfHeight; + + mBounds = {left, right, top, bottom}; + + // Check for collisions with other entities that have box colliders + // For simplicity, just check each + std::vector entities = State::GameState::getInstance().getEntitiesSnapshot(); + for (Entity* other : entities) { + if (other == thisEntity) continue; // Don't check collision with self + BoxCollider* otherCollider = other->getComponent(); + if (!otherCollider) continue; // No collider, skip + BoxColliderBounds otherBounds = otherCollider->getBounds(); + if (left < otherBounds.right && right > otherBounds.left && top < otherBounds.bottom && bottom > otherBounds.top) { + // Collision detected + if (!mIsColliding) { + mIsColliding = true; + thisEntity->onCollisionEnter(other); + other->onCollisionEnter(thisEntity); + } else { + thisEntity->onCollisionStay(other); + other->onCollisionStay(thisEntity); + } + } else { + // No collision + if (mIsColliding) { + mIsColliding = false; + thisEntity->onCollisionExit(other); + other->onCollisionExit(thisEntity); + } + } + } } } \ No newline at end of file diff --git a/src/state/gamestate.cpp b/src/state/gamestate.cpp index 3ce673a..e3feb48 100644 --- a/src/state/gamestate.cpp +++ b/src/state/gamestate.cpp @@ -13,7 +13,7 @@ namespace Game::State { } } - void GameState::addEntity(std::unique_ptr entity) { + Object::Entity* GameState::addEntity(std::unique_ptr entity) { Object::Entity* addedEntity = nullptr; { std::lock_guard lock(mMutex); // Lock the mutex for thread safety @@ -23,6 +23,7 @@ namespace Game::State { addedEntity->start(); // Initialize the entity after insertion without holding the GameState lock. LOG("Added entity '" << addedEntity->getName() << "' to GameState"); + return addedEntity; } bool GameState::removeEntity(const std::string& name) {