Skip to content
Snippets Groups Projects
Commit 6ab943c2 authored by Joseph Walton-Rivers's avatar Joseph Walton-Rivers
Browse files

make entity removal work reliably

parent 0940fe44
No related branches found
No related tags found
No related merge requests found
Pipeline #3401 failed
......@@ -114,7 +114,14 @@ static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) {
fggl::data::make_cube(meshComponent.mesh);
world.set<fggl::data::StaticMesh>(prefabs.collectable, &meshComponent);
auto* callbacks = world.add<fggl::phys::CollisionCallbacks>(prefabs.collectable);
// physics stuff
auto* rb = world.add<fggl::phys::RigidBody>(prefabs.collectable);
rb->shape = new fggl::phys::Box({0.5f, 0.5f, 0.5f});
rb->type = fggl::phys::BodyType::KINEMATIC;
// we need both of these for callbacks to trigger.
world.add<fggl::phys::CollisionCallbacks>(prefabs.collectable);
world.add<fggl::phys::CollisionCache>(prefabs.collectable);
}
}
......@@ -200,12 +207,21 @@ namespace demo {
Prefabs prefabs{};
setupPrefabs(world(), prefabs);
// collectable callbacks
auto* collectableCallbacks = world().get<fggl::phys::CollisionCallbacks>(prefabs.collectable);
collectableCallbacks->onEnter = [this](auto ourID, auto theirID) {
if ( theirID == player) {
this->world().destroy(ourID);
}
};
// actual scene objects
setupCamera(world());
// create a 20x20 grid
fggl::math::vec2 size{40.0f, 40.0f};
player = setupEnvironment(world(), prefabs, size);
}
void RollBall::update() {
......
......@@ -37,6 +37,8 @@ namespace fggl::phys::bullet {
m_debug = std::make_unique<debug::BulletDebugDrawList>();
m_world->setDebugDrawer( m_debug.get() );
m_debug->setDebugMode(1);
m_ecs->addDeathListener( [this](auto entity) { this->onEntityDeath(entity);} );
}
void BulletPhysicsEngine::step() {
......@@ -66,6 +68,7 @@ namespace fggl::phys::bullet {
m_world->debugDrawWorld();
}
static void build_motation_state(math::Transform* myState, BulletBody* btState) {
auto myPos = myState->origin();
btVector3 position{myPos.x, myPos.y, myPos.z};
......@@ -203,12 +206,12 @@ namespace fggl::phys::bullet {
auto itr = cache->collisions.find(other);
if ( itr == cache->collisions.end() ) {
if ( callbacks->onEnter != nullptr ) {
callbacks->onEnter(other);
callbacks->onEnter(owner, other);
}
cache->collisions.insert( other );
cache->collisions.insert( other );
} else {
if ( callbacks->onStay != nullptr ) {
callbacks->onStay(other);
callbacks->onStay(owner, other);
}
}
}
......@@ -231,13 +234,23 @@ namespace fggl::phys::bullet {
const auto* body0 = contactManifold->getBody0();
const auto* body1 = contactManifold->getBody1();
handleCollisionCallbacks(m_ecs, body0->getUserIndex(), body1->getUserIndex());
handleCollisionCallbacks(m_ecs, body1->getUserIndex(), body0->getUserIndex());
// FIXME rigid body didn't die according to plan!
if ( body0->getUserIndex() == ecs::NULL_ENTITY || body1->getUserIndex() == ecs::NULL_ENTITY) {
continue;
}
if ( !m_ecs->alive( body0->getUserIndex()) || !m_ecs->alive(body1->getUserIndex()) ) {
continue;
}
std::cerr << "contact: " << body0->getUserIndex() << " on " << body1->getUserIndex() << std::endl;
handleCollisionCallbacks(m_ecs, body0->getUserIndex(), body1->getUserIndex());
handleCollisionCallbacks(m_ecs, body1->getUserIndex(), body0->getUserIndex());
}
// note conacts that have ended
caches = m_ecs->findMatching<CollisionCache>(); // re-fetch, entities can (and probably do) die in handlers.
for( auto& ent : caches) {
auto* cache = m_ecs->get<CollisionCache>(ent);
......@@ -251,10 +264,18 @@ namespace fggl::phys::bullet {
for (const auto& other : cache->lastFrame) {
auto itr = cache->collisions.find(other);
if (itr == cache->collisions.end()) {
callbacks->onExit(other);
callbacks->onExit( ent,other);
}
}
}
}
void BulletPhysicsEngine::onEntityDeath(ecs::entity_t entity) {
auto* btPhysics = m_ecs->tryGet<BulletBody>(entity);
if ( btPhysics != nullptr) {
btPhysics->body->setUserIndex( ecs::NULL_ENTITY );
m_world->removeRigidBody( btPhysics->body );
}
}
} // namespace fggl::phys::bullet
\ No newline at end of file
......@@ -59,6 +59,8 @@ namespace fggl::scenes {
if ( m_phys != nullptr ) {
m_phys->step();
}
m_world->reapEntities();
}
void Game::render(fggl::gfx::Graphics &gfx) {
......
......@@ -6,6 +6,9 @@
#define FGGL_ECS3_PROTOTYPE_WORLD_H
#include <map>
#include <functional>
#include <unordered_set>
#include <fggl/ecs3/types.hpp>
/**
......@@ -15,6 +18,8 @@
*/
namespace fggl::ecs3::prototype {
using entity_cb = std::function<void(const entity_t)>;
class Entity {
public:
bool m_abstract;
......@@ -122,9 +127,39 @@ namespace fggl::ecs3::prototype {
return clone;
}
bool alive(entity_t entity) const {
if (entity == NULL_ENTITY) {
// tis a silly question, but can be asked by accident.
return false;
}
if ( m_killList.find( entity ) != m_killList.end() ) {
// getting reaped
return false;
}
// check liveness
return m_entities.find( entity ) != m_entities.end();
}
void destroy(entity_t entity) {
assert( entity != NULL_ENTITY && "attempted to kill null entity" );
// TOOD resolve and clean components
m_entities.erase(entity);
//m_entities.erase(entity);
m_killList.insert(entity);
}
void reapEntities() {
for (const auto& entity : m_killList) {
//auto& entityObj = m_entities.at(entity);
//entityObj.clear();
for (auto& listener : m_deathListeners) {
listener( entity );
}
m_entities.erase(entity);
}
m_killList.clear();
}
inline TypeRegistry &types() {
......@@ -140,6 +175,8 @@ namespace fggl::ecs3::prototype {
}
std::vector<component_type_t> getComponents(entity_t entityID) {
assert(alive(entityID) && "attempted to get components on dead entity");
std::vector<component_type_t> components{};
auto &entity = m_entities.at(entityID);
auto comps = entity.getComponentIDs();
......@@ -168,6 +205,8 @@ namespace fggl::ecs3::prototype {
template<typename C>
C *add(entity_t entity_id) {
assert( entity_id != NULL_ENTITY && "attempted to add component on null entity" );
//spdlog::info("component '{}' added to '{}'", C::name, entity_id);
auto &entity = m_entities.at(entity_id);
auto comp = entity.template add<C>();
......@@ -177,6 +216,8 @@ namespace fggl::ecs3::prototype {
}
void *add(entity_t entity_id, component_type_t component_id) {
assert( entity_id != NULL_ENTITY && "attempted to add component on null entity" );
auto meta = m_types.meta(component_id);
auto &entity = m_entities.at(entity_id);
......@@ -187,6 +228,8 @@ namespace fggl::ecs3::prototype {
template<typename C>
C *set(entity_t entity_id, const C *ptr) {
assert( entity_id != NULL_ENTITY && "attempted to set component on null entity" );
//spdlog::info("component '{}' set on '{}'", C::name, entity_id);
auto &entity = m_entities.at(entity_id);
auto comp = entity.set<C>(ptr);
......@@ -196,6 +239,8 @@ namespace fggl::ecs3::prototype {
}
void *set(entity_t entity_id, component_type_t cid, const void *ptr) {
assert( entity_id != NULL_ENTITY && "attempted to set component on null entity" );
auto &entity = m_entities.at(entity_id);
auto cMeta = m_types.meta(cid);
......@@ -206,6 +251,8 @@ namespace fggl::ecs3::prototype {
template<typename C>
C* tryGet(entity_t entity_id) const {
assert( entity_id != NULL_ENTITY && "attempted to tryGet component on null entity" );
try {
const auto &entity = m_entities.at(entity_id);
try {
......@@ -214,13 +261,15 @@ namespace fggl::ecs3::prototype {
return nullptr;
}
} catch ( std::out_of_range& e) {
std::cerr << "someone requested an component that didn't exist, entity was: " << entity_id << std::endl;
std::cerr << "someone requested an entity that didn't exist, entity was: " << entity_id << std::endl;
return nullptr;
}
}
template<typename C>
C *get(entity_t entity_id) const {
assert( entity_id != NULL_ENTITY && "attempted to get component on null entity" );
C* ptr = tryGet<C>(entity_id);
if (ptr == nullptr) {
std::cerr << "entity " << entity_id << " does not have component "<< C::name << std::endl;
......@@ -230,6 +279,8 @@ namespace fggl::ecs3::prototype {
template<typename C>
void remove(entity_t entity_id) {
assert( entity_id != NULL_ENTITY && "attempted to remove component on null entity" );
try {
auto &entity = m_entities.at(entity_id);
try {
......@@ -247,10 +298,16 @@ namespace fggl::ecs3::prototype {
return entity.get(t);
}
void addDeathListener(const entity_cb& callback) {
m_deathListeners.emplace_back(callback);
}
private:
std::vector< entity_cb > m_deathListeners;
TypeRegistry &m_types;
entity_t m_next;
std::map<entity_t, Entity> m_entities;
std::unordered_set<entity_t> m_killList;
};
......
......@@ -62,6 +62,8 @@ namespace fggl::phys::bullet {
~BulletPhysicsEngine() override;
void step() override;
void onEntityDeath(ecs::entity_t entity);
private:
ecs3::World* m_ecs;
BulletConfiguration m_config;
......
......@@ -30,7 +30,7 @@
namespace fggl::phys {
using CollisionCB = std::function<void(ecs3::entity_t)>;
using CollisionCB = std::function<void(ecs3::entity_t, ecs3::entity_t)>;
struct CollisionCallbacks {
constexpr static const char* name = "phys::Callbacks";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment