Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions engine/include/velos/entity/entity.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <vector>
#include <memory>
#include <functional>
#include "../graphics/shapes/shape.h"
#include "../physics/collider.h"
#include "../graphics/renderer.h"
Expand All @@ -14,6 +15,21 @@ namespace velos {

virtual void update(float dt) { updateColliders(); }
virtual void render(Renderer& renderer);

using CollisionCallback = std::function<void(Entity&)>;

virtual void onCollisionEnter(Entity& other) {};
virtual void onCollisionStay(Entity& other) {};
virtual void onCollisionExit(Entity& other) {};

void setOnCollisionEnter(CollisionCallback cb) { m_onEnter = std::move(cb); }
void setOnCollisionStay(CollisionCallback cb) { m_onStay = std::move(cb); }
void setOnCollisionExit(CollisionCallback cb) { m_onExit = std::move(cb); }

void dispatchCollisionEnter(Entity& other);
void dispatchCollisionStay(Entity& other);
void dispatchCollisionExit(Entity& other);

void debugRender(Renderer& renderer);
bool containsPoint(const Vec2& worldPos) const;

Expand All @@ -29,5 +45,9 @@ namespace velos {
Transform m_transform;
std::vector<std::shared_ptr<Shape>> m_shapes;
std::vector<std::unique_ptr<Collider>> m_colliders;

CollisionCallback m_onEnter;
CollisionCallback m_onStay;
CollisionCallback m_onExit;
};
}
3 changes: 3 additions & 0 deletions engine/include/velos/entity/entity_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "entity.h"
#include <memory>
#include <vector>
#include "../physics/physics_system.h"

namespace velos {
class EntityManager {
Expand All @@ -15,6 +16,8 @@ namespace velos {
std::vector<std::shared_ptr<Entity>> entities() { return m_entities; }
private:
std::vector<std::shared_ptr<Entity>> m_entities;
PhysicsSystem m_physics;

bool m_debugRender = false;
};
}
3 changes: 3 additions & 0 deletions engine/include/velos/physics/aabb_collider.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace velos {
void setSize(const Vec2 size);
void debugRender(Renderer& renderer) const override;

const Vec2& size() const { return m_size; }
const Vec2& worldPosition() const { return m_worldPosition; }

private:
Vec2 m_size;
Vec2 m_offset;
Expand Down
3 changes: 3 additions & 0 deletions engine/include/velos/physics/circle_collider.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace velos {
void setRadius(float radius);
void debugRender(Renderer& renderer) const override;

float radius() const { return m_radius; }
const Vec2& worldPosition() const { return m_worldPosition; }

private:
float m_radius;
Vec2 m_offset;
Expand Down
30 changes: 30 additions & 0 deletions engine/include/velos/physics/physics_system.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once
#include <utility>
#include <set>
#include <vector>
#include <memory>
#include "../entity/entity.h"
#include "aabb_collider.h"
#include "circle_collider.h"
#include "collider.h"

namespace velos {
class PhysicsSystem {
public:
void update(const std::vector<std::shared_ptr<Entity>>& entities);

private:
using CollisionPair = std::pair<Entity*, Entity*>;

std::set<CollisionPair> m_previous;
std::set<CollisionPair> m_current;

bool checkCollision(Entity& e1, Entity& e2);
static CollisionPair makeOrderedPair(Entity* e1, Entity* e2);

bool intersects(const Collider& c1, const Collider& c2);
bool aabbVsAabb(const AABBCollider& c1, const AABBCollider& c2);
bool circleVsCircle(const CircleCollider& c1, const CircleCollider& c2);
bool aabbVsCircle(const AABBCollider& c1, const CircleCollider& c2);
};
}
18 changes: 18 additions & 0 deletions engine/src/entity/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,22 @@ namespace velos {
for (auto& collider: m_colliders)
collider->computeWorld(m_transform);
}

void Entity::dispatchCollisionEnter(Entity& other) {
onCollisionEnter(other);
if (m_onEnter)
m_onEnter(other);
}

void Entity::dispatchCollisionStay(Entity& other) {
onCollisionStay(other);
if (m_onStay)
m_onStay(other);
}

void Entity::dispatchCollisionExit(Entity& other) {
onCollisionExit(other);
if (m_onExit)
m_onExit(other);
}
}
1 change: 1 addition & 0 deletions engine/src/entity/entity_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace velos {
void EntityManager::update(float dt) {
for (auto& entity: m_entities)
entity->update(dt);
m_physics.update(m_entities);
}

void EntityManager::render(Renderer& renderer) {
Expand Down
111 changes: 111 additions & 0 deletions engine/src/physics/physics_system.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "velos/physics/physics_system.h"

namespace velos {
PhysicsSystem::CollisionPair PhysicsSystem::makeOrderedPair(Entity* e1, Entity* e2) {
if (e1 < e2)
return std::make_pair(e1, e2);
return std::make_pair(e2, e1);
}

void PhysicsSystem::update(const std::vector<std::shared_ptr<Entity>>& entities) {
m_current.clear();

for (size_t i = 0; i < entities.size(); ++i) {
for (size_t j = i + 1; j < entities.size(); ++j) {
Entity& e1 = *entities[i];
Entity& e2 = *entities[j];

if (checkCollision(e1, e2))
m_current.insert(makeOrderedPair(&e1, &e2));
}
}

for (const auto& pair: m_current) {
Entity* e1 = pair.first;
Entity* e2 = pair.second;

if (m_previous.find(pair) == m_previous.end()) {
e1->dispatchCollisionEnter(*e2);
e2->dispatchCollisionEnter(*e1);
} else {
e1->dispatchCollisionStay(*e2);
e2->dispatchCollisionStay(*e1);
}
}

for (const auto& pair: m_previous) {
if (m_current.find(pair) == m_current.end()) {
Entity* e1 = pair.first;
Entity* e2 = pair.second;

e1->dispatchCollisionExit(*e2);
e2->dispatchCollisionExit(*e1);
}
}

m_previous = m_current;
}

bool PhysicsSystem::checkCollision(Entity& e1, Entity& e2) {
for (const auto& c1: e1.colliders())
for (const auto& c2: e2.colliders())
if (intersects(*c1, *c2))
return true;
return false;
}

bool PhysicsSystem::intersects(const Collider& c1, const Collider& c2) {
if (c1.type() == ColliderType::AABB && c2.type() == ColliderType::AABB)
return aabbVsAabb(
static_cast<const AABBCollider&>(c1),
static_cast<const AABBCollider&>(c2)
);

if (c1.type() == ColliderType::Circle && c2.type() == ColliderType::Circle)
return circleVsCircle(
static_cast<const CircleCollider&>(c1),
static_cast<const CircleCollider&>(c2)
);

if (c1.type() == ColliderType::AABB && c2.type() == ColliderType::Circle)
return aabbVsCircle(
static_cast<const AABBCollider&>(c1),
static_cast<const CircleCollider&>(c2)
);

if (c1.type() == ColliderType::Circle && c2.type() == ColliderType::AABB)
return aabbVsCircle(
static_cast<const AABBCollider&>(c2),
static_cast<const CircleCollider&>(c1)
);

return false;
}

bool PhysicsSystem::aabbVsAabb(const AABBCollider& c1, const AABBCollider& c2) {
return c1.worldPosition().x < c2.worldPosition().x + c2.size().x &&
c1.worldPosition().x + c1.size().x > c2.worldPosition().x &&
c1.worldPosition().y < c2.worldPosition().y + c2.size().y &&
c1.worldPosition().y + c1.size().y > c2.worldPosition().y;
}

bool PhysicsSystem::circleVsCircle(const CircleCollider& c1, const CircleCollider& c2) {
Vec2 d = c1.worldPosition() - c2.worldPosition();
float r = c1.radius() + c2.radius();
return d.lengthSquared() <= r * r;
}

bool PhysicsSystem::aabbVsCircle(const AABBCollider& c1, const CircleCollider& c2) {
Vec2 closest{
std::clamp(c2.worldPosition().x,
c1.worldPosition().x,
c1.worldPosition().x + c1.size().x),
std::clamp(c2.worldPosition().y,
c1.worldPosition().y,
c1.worldPosition().y + c1.size().y)
};

Vec2 delta = c2.worldPosition() - closest;
return delta.lengthSquared() <= c2.radius() * c2.radius();
}
}
10 changes: 10 additions & 0 deletions examples/sandbox/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ int main() {
auto stationary_entity = std::make_shared<velos::Entity>();
stationary_entity->addShape(circle);

auto stationary_collider = std::make_unique<velos::CircleCollider>(50, velos::Vec2{100.f, 100.f});
stationary_entity->addCollider(std::move(stationary_collider));

stationary_entity->setOnCollisionEnter([](velos::Entity& other) {
VELOS_INFO("Entered collision!");
});
stationary_entity->setOnCollisionExit([](velos::Entity& other) {
VELOS_INFO("Exited collision!");
});

float speed = 200.f;
engine.setAction(velos::Key::W, "MoveForward", velos::ActionType::Hold, 0.05f, [entity, speed](float dt){ entity->move(0, -speed * dt); });
engine.setAction(velos::Key::S, "MoveBackward", velos::ActionType::Hold, 0.05f, [entity, speed](float dt){ entity->move(0, speed * dt); });
Expand Down