Commit, fix boxcollider

This commit is contained in:
2026-04-15 07:52:14 +02:00
parent dc55af5323
commit ab3baf5cbb
4 changed files with 61 additions and 23 deletions

View File

@@ -8,5 +8,7 @@
namespace Game::AGame { namespace Game::AGame {
GAME_ENTITY(Enemy) GAME_ENTITY(Enemy)
public:
void onCollisionEnter(Object::Entity* other) override;
END_GAME_ENTITY() END_GAME_ENTITY()
} }

View File

@@ -2,6 +2,7 @@
#include <object/components/component.hpp> #include <object/components/component.hpp>
#include <state/gamestate.hpp> #include <state/gamestate.hpp>
#include <unordered_set>
namespace Game::Object::Components { namespace Game::Object::Components {
struct BoxColliderBounds { struct BoxColliderBounds {
@@ -21,10 +22,10 @@ namespace Game::Object::Components {
void update(float deltaTime, Object::Entity* thisEntity) override; void update(float deltaTime, Object::Entity* thisEntity) override;
BoxColliderBounds getBounds() const { return mBounds; } BoxColliderBounds getBounds() const { return mBounds; }
bool isColliding() const { return mIsColliding; } bool isColliding() const { return !mCollidingWith.empty(); }
private: private:
BoxColliderBounds mBounds; BoxColliderBounds mBounds{0.f, 0.f, 0.f, 0.f};
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 std::unordered_set<Object::Entity*> mCollidingWith; // Track collisions per-entity so enter/stay/exit callbacks remain correct with multiple colliders
}; };
} }

View File

@@ -1,11 +1,19 @@
#include <game/agame/enemy.hpp> #include <game/agame/enemy.hpp>
#include <object/components/boxcollider.hpp>
namespace Game::AGame { namespace Game::AGame {
void Enemy::start() { void Enemy::start() {
mZIndex = 20; mZIndex = 20;
addComponent<Object::Components::BoxCollider>();
LOG("Enemy started: " << getName());
} }
void Enemy::update(float deltaTime) { void Enemy::update(float deltaTime) {
return; return;
} }
void Enemy::onCollisionEnter(Object::Entity* other) {
LOG("Enemy '" << getName() << "' collided with '" << other->getName() << "' (onCollisionEnter); Killing myself now!");
GameManager::setSharedData("enemyActiveCount", GameManager::getSharedData<int>("enemyActiveCount") - 1);
}
} }

View File

@@ -1,5 +1,8 @@
#include <object/components/boxcollider.hpp> #include <object/components/boxcollider.hpp>
#include <object/entity.hpp> #include <object/entity.hpp>
#include <renderer/texture.hpp>
#include <algorithm>
namespace Game::Object::Components { namespace Game::Object::Components {
BoxCollider::BoxCollider(const BoxCollider& other) : Component(other) { BoxCollider::BoxCollider(const BoxCollider& other) : Component(other) {
@@ -32,44 +35,68 @@ namespace Game::Object::Components {
void BoxCollider::update(float deltaTime, Object::Entity* thisEntity) { void BoxCollider::update(float deltaTime, Object::Entity* thisEntity) {
// Collision detection and response logic can go here // Collision detection and response logic can go here
(void)deltaTime;
if (!thisEntity) {
return;
}
// Make box bounds // Make box bounds
Transform* transform = thisEntity->getTransform(); Transform* transform = thisEntity->getTransform();
float halfWidth = transform->scaleX * UNIVERSAL_SCALE_COEFFICIENT * 0.5f; if (!transform) {
float halfHeight = transform->scaleY * UNIVERSAL_SCALE_COEFFICIENT * 0.5f; return;
float left = transform->x - halfWidth; }
float right = transform->x + halfWidth;
float top = transform->y - halfHeight; float width = 1.f;
float bottom = transform->y + halfHeight; float height = 1.f;
if (const auto tex = thisEntity->getTexture()) {
width = tex->getWidth() * transform->scaleX * UNIVERSAL_SCALE_COEFFICIENT;
height = tex->getHeight() * transform->scaleY * UNIVERSAL_SCALE_COEFFICIENT;
} else {
width = transform->scaleX * UNIVERSAL_SCALE_COEFFICIENT;
height = transform->scaleY * UNIVERSAL_SCALE_COEFFICIENT;
}
width = std::max(1.f, width);
height = std::max(1.f, height);
// Transform position is used as top-left in rendering, so match that convention for collision bounds.
float left = transform->x;
float right = transform->x + width;
float top = transform->y;
float bottom = transform->y + height;
mBounds = {left, right, top, bottom}; mBounds = {left, right, top, bottom};
// Check for collisions with other entities that have box colliders // Check for collisions with other entities that have box colliders
// For simplicity, just check each // For simplicity, just check each
std::unordered_set<Entity*> currentCollisions;
std::vector<Entity*> entities = State::GameState::getInstance().getEntitiesSnapshot(); std::vector<Entity*> entities = State::GameState::getInstance().getEntitiesSnapshot();
for (Entity* other : entities) { for (Entity* other : entities) {
if (other == thisEntity) continue; // Don't check collision with self if (!other || other == thisEntity || !other->isActive()) continue; // Don't check collision with self/inactive entities
BoxCollider* otherCollider = other->getComponent<BoxCollider>(); BoxCollider* otherCollider = other->getComponent<BoxCollider>();
if (!otherCollider) continue; // No collider, skip if (!otherCollider || !otherCollider->isActive()) continue; // No active collider, skip
BoxColliderBounds otherBounds = otherCollider->getBounds(); BoxColliderBounds otherBounds = otherCollider->getBounds();
if (left < otherBounds.right && right > otherBounds.left && top < otherBounds.bottom && bottom > otherBounds.top) { bool isOverlapping = left < otherBounds.right && right > otherBounds.left && top < otherBounds.bottom && bottom > otherBounds.top;
if (isOverlapping) {
currentCollisions.insert(other);
// Collision detected // Collision detected
if (!mIsColliding) { if (!mCollidingWith.contains(other)) {
mIsColliding = true;
thisEntity->onCollisionEnter(other); thisEntity->onCollisionEnter(other);
other->onCollisionEnter(thisEntity); //other->onCollisionEnter(thisEntity);
} else { } else {
thisEntity->onCollisionStay(other); thisEntity->onCollisionStay(other);
other->onCollisionStay(thisEntity); //other->onCollisionStay(thisEntity);
}
} else {
// No collision
if (mIsColliding) {
mIsColliding = false;
thisEntity->onCollisionExit(other);
other->onCollisionExit(thisEntity);
} }
} }
} }
for (Entity* wasColliding : mCollidingWith) {
if (!currentCollisions.contains(wasColliding)) {
thisEntity->onCollisionExit(wasColliding);
//wasColliding->onCollisionExit(thisEntity);
}
}
mCollidingWith = std::move(currentCollisions);
} }
} }