From 56babcc8955a7f083631032a597d8e22c4c0007d Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Tue, 2 Aug 2022 15:37:47 +0100 Subject: [PATCH] callback-based creation --- demo/demo/rollball.cpp | 51 ++++++++----------- include/fggl/entity/loader/loader.hpp | 37 +++++++++++--- .../include/fggl/phys/bullet/motion.hpp | 2 + integrations/bullet/src/service.cpp | 10 ++-- integrations/bullet/src/simulation.cpp | 5 ++ 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/demo/demo/rollball.cpp b/demo/demo/rollball.cpp index d3661ca..3ef9ec5 100644 --- a/demo/demo/rollball.cpp +++ b/demo/demo/rollball.cpp @@ -49,40 +49,33 @@ static void setup_camera(fggl::entity::EntityManager& world) { } static fggl::entity::EntityID setup_environment(fggl::entity::EntityManager& world, fggl::entity::EntityFactory* factory, const fggl::math::vec2& size, demo::RollState& state) { - { - auto northWall = factory->create(WallNPrefab, world); - auto& transform = world.get<fggl::math::Transform>(northWall); - transform.origin({size.x/2, 0.0F, 0.0F}); - } + factory->create(WallNPrefab, world, [size](auto& manager, const auto& entity) { + auto& transform = manager.template get<fggl::math::Transform>(entity); + transform.origin({size.x/2, 0.0F, 0.0F}); + }); - { - auto southWall = factory->create(WallNPrefab, world); - auto& transform = world.get<fggl::math::Transform>(southWall); + factory->create(WallNPrefab, world, [size](auto& manager, const auto& entity) { + auto& transform = manager.template get<fggl::math::Transform>(entity); transform.origin({-size.x/2, 0.0F, 0.0F}); - } + }); - { - auto westWall = factory->create(WallEPrefab, world); - auto& transform = world.get<fggl::math::Transform>(westWall); + factory->create(WallEPrefab, world, [size](auto& manager, const auto& entity) { + auto& transform = manager.template get<fggl::math::Transform>(entity); transform.origin({0.0F, 0.0F, -size.y/2}); - } + }); - { - auto eastWall = factory->create(WallEPrefab, world); - auto& transform = world.get<fggl::math::Transform>(eastWall); + factory->create(WallEPrefab, world, [size](auto& manager, const auto& entity) { + auto& transform = manager.template get<fggl::math::Transform>(entity); transform.origin({0.0F, 0.0F, size.y/2}); - } + }); - { - auto floor = factory->create(floorPrefab, world); - auto& transform = world.get<fggl::math::Transform>(floor); + factory->create(floorPrefab, world, [](auto& manager, const auto& entity) { + auto& transform = manager.template get<fggl::math::Transform>(entity); transform.origin({0.0F, -2.5F, 0.0F}); - } + }); - { - // player just starts off as the prefab dictates - state.player = factory->create(playerPrefab, world); - } + // the player requires no special setup + state.player = factory->create(playerPrefab, world); { // collectables @@ -95,10 +88,10 @@ static fggl::entity::EntityID setup_environment(fggl::entity::EntityManager& wor // build the collectables int collectCount = 0; for (auto& pos : collectPos) { - auto collectable = factory->create(collectablePrefab, world); - auto& transform = world.get<fggl::math::Transform>(collectable); - transform.origin(pos); - + auto collectable = factory->create(collectablePrefab, world, [pos](auto& manager, const auto& entity) { + auto& transform = manager.template get<fggl::math::Transform>(entity); + transform.origin(pos); + }); state.collectables[collectCount++] = collectable; } } diff --git a/include/fggl/entity/loader/loader.hpp b/include/fggl/entity/loader/loader.hpp index 47381dd..8fc47fa 100644 --- a/include/fggl/entity/loader/loader.hpp +++ b/include/fggl/entity/loader/loader.hpp @@ -34,32 +34,56 @@ namespace fggl::entity { constexpr auto PROTOTYPE_ASSET = assets::AssetType::make("entity_prototype"); using FactoryFunc = std::function<void(const ComponentSpec& config, EntityManager&, const EntityID&)>; + using CustomiseFunc = std::function<void(EntityManager&, const EntityID&)>; + using ComponentID = util::GUID; using EntityType = util::GUID; + struct FactoryInfo { + FactoryFunc factory; + CustomiseFunc finalise = nullptr; + }; + class EntityFactory { public: constexpr static const modules::ModuleService service = modules::make_service("fggl::entity:Factory"); - EntityID create(const EntityType& spec, EntityManager& manager) { + EntityID create(const EntityType& spec, EntityManager& manager, const CustomiseFunc& customise = nullptr) { try { auto &prototype = m_prototypes.at(spec); + std::vector<CustomiseFunc> finishers; + // invoke each component factory as required auto entity = manager.create(); for ( auto& component : prototype.ordering ) { try { auto& data = prototype.components.at(component); - m_factories.at(component)(data, manager, entity); + + auto& info = m_factories.at(component); + info.factory(data, manager, entity); + + if ( info.finalise != nullptr ) { + finishers.push_back(info.finalise); + } } catch (std::out_of_range& ex) { #ifndef NDEBUG - debug::log(debug::Level::error, "EntityFactory: Unknown component factory type '{}'", fggl::util::guidToString(component)); + debug::log(debug::Level::error, "EntityFactory: Unknown component factory type '{}'", fggl::util::guidToString(component)); #endif manager.destroy(entity); return fggl::entity::INVALID; } } + if (customise != nullptr) { + customise(manager, entity); + } + + // finalise the entities + for( auto& finisher : finishers ) { + finisher(manager, entity); + } + return entity; } catch (std::out_of_range& ex) { #ifndef NDEBUG @@ -74,8 +98,9 @@ namespace fggl::entity { } // ability to set and unset factory functions - inline void bind(const ComponentID& configNode, FactoryFunc factory) { - m_factories[configNode] = std::move(factory); + inline void bind(const ComponentID& configNode, FactoryFunc factory, CustomiseFunc finalise = nullptr) { + m_factories[configNode].factory = std::move(factory); + m_factories[configNode].finalise = std::move(finalise); } inline void unbind(const ComponentID& configNode) { @@ -83,7 +108,7 @@ namespace fggl::entity { } private: - std::map<ComponentID, FactoryFunc> m_factories; + std::map<ComponentID, FactoryInfo> m_factories; std::map<EntityType, EntitySpec> m_prototypes; }; diff --git a/integrations/bullet/include/fggl/phys/bullet/motion.hpp b/integrations/bullet/include/fggl/phys/bullet/motion.hpp index 07c1a25..9fa5160 100644 --- a/integrations/bullet/include/fggl/phys/bullet/motion.hpp +++ b/integrations/bullet/include/fggl/phys/bullet/motion.hpp @@ -45,6 +45,8 @@ namespace fggl::phys::bullet { ~FgglMotionState() override = default; void getWorldTransform(btTransform& worldTrans) const override { + debug::trace("BT: syncing from transform: {}.", (uint64_t)m_entity); + const auto* transform = m_world->tryGet<fggl::math::Transform>(m_entity); if ( transform == nullptr ) { debug::warning("BT: attempted to get transform of entity without transform component."); diff --git a/integrations/bullet/src/service.cpp b/integrations/bullet/src/service.cpp index a91c777..c50d791 100644 --- a/integrations/bullet/src/service.cpp +++ b/integrations/bullet/src/service.cpp @@ -52,7 +52,7 @@ namespace fggl::phys::bullet { } } - void add_bt_body(BulletPhysicsEngine* engine, const entity::ComponentSpec& spec, entity::EntityManager& manager, const entity::EntityID& id) { + void add_bt_body(const entity::ComponentSpec& spec, entity::EntityManager& manager, const entity::EntityID& id) { auto& body = manager.add<BulletBody>(id); body.motion = new FgglMotionState(&manager, id); @@ -78,11 +78,11 @@ namespace fggl::phys::bullet { shape, inertia }; + body.body = new btRigidBody(constructionInfo); setup_body(type, *body.body); // add the body to the simulation - engine->addBody(id, body); if ( type == BodyType::DYNAMIC ) { manager.add<phys::Dynamics>(id); } @@ -92,8 +92,10 @@ namespace fggl::phys::bullet { auto* engine = new BulletPhysicsEngine(entityManager); // FIXME: this won't work across multiple scenes - reactive approach might be better... - factory->bind(util::make_guid("phys::Body"), [engine](const entity::ComponentSpec& config, entity::EntityManager& manager, const entity::EntityID& id) { - add_bt_body(engine, config, manager, id); + factory->bind(util::make_guid("phys::Body"), add_bt_body, [engine](auto& manager, const auto& entity) { + debug::trace("adding entity {} to physics scene...", (uint64_t)entity); + auto& physComp = manager.template get<BulletBody>(entity); + engine->addBody(entity, physComp); }); engine->debugDraw = true; diff --git a/integrations/bullet/src/simulation.cpp b/integrations/bullet/src/simulation.cpp index df589cb..20bd2fb 100644 --- a/integrations/bullet/src/simulation.cpp +++ b/integrations/bullet/src/simulation.cpp @@ -85,6 +85,11 @@ namespace fggl::phys::bullet { void BulletPhysicsEngine::addBody(entity::EntityID /*entity*/, BulletBody &body) { m_world->addRigidBody(body.body); + + btMatrix4x4 transform; + body.body->getMotionState()->getWorldTransform(body.transform); + + body.body->setWorldTransform(body.body->getMotionState()->) } inline btCollisionShape* shape_to_bullet(const phys::RigidBody& fgglBody) { -- GitLab