diff --git a/core/include/cubos/core/ecs/cubos.hpp b/core/include/cubos/core/ecs/cubos.hpp index 787304ab90..896d44550d 100644 --- a/core/include/cubos/core/ecs/cubos.hpp +++ b/core/include/cubos/core/ecs/cubos.hpp @@ -71,6 +71,11 @@ namespace cubos::core::ecs /// @return Reference to this object, for chaining. TagBuilder& after(const std::string& tag); + /// @brief Makes the current tag inherit from given tag. + /// @param tag Tag to be inherited from. + /// @return Reference to this object, for chaining. + TagBuilder& tagged(const std::string& tag); + /// @brief Adds a condition to the current tag. If this condition returns false, systems /// with this tag will not be executed. For the tagged systems to run, all conditions must /// return true. @@ -79,28 +84,46 @@ namespace cubos::core::ecs template TagBuilder& runIf(F func); + /// @brief Adds a repeat condition to the current tag, also making it a group. + /// @param func Condition function. + /// @return Reference to this object, for chaining. + template + TagBuilder& repeatWhile(F func); + private: core::ecs::Dispatcher& mDispatcher; std::vector& mTags; }; - /// @brief Used to make groups of tags. - /// @ingroup engine + /// @brief Used to create groups and subgroups. + /// @ingroup core-ecs class GroupBuilder { public: /// @brief Construct. /// @param dispatcher Dispatcher being configured - /// @param tags Vector which stores the tags for this dispatcher. + /// @param grouptag Tag for the group. + /// @return Reference to this object, for chaining. + GroupBuilder(core::ecs::Dispatcher& dispatcher, const std::string& grouptag); + + /// @brief Creates a subgroup. + /// @param tag Tag for the subgroup. /// @return Reference to this object, for chaining. - GroupBuilder(core::ecs::Dispatcher& dispatcher, std::vector& tags); + GroupBuilder& subgroup(); - + /// @brief Ends a group by reseting current group. + /// @return Reference to this object, for chaining. GroupBuilder& endgroup(); + /// @brief Sets the group to have a repeatWhile condition. + /// @param func Condition function. + /// @return Reference to this object, for chaining. + template + GroupBuilder& repeatWhile(F func); + private: core::ecs::Dispatcher& mDispatcher; - std::vector& mTags; + const std::string& mgrouptag; }; /// @brief Used to chain configurations related to systems @@ -128,6 +151,11 @@ namespace cubos::core::ecs /// @return Reference to this object, for chaining. SystemBuilder& after(const std::string& tag); + /// @brief Sets the current system to be executed inside a group. + /// @param grouptag Grouptag of the group. + /// @return Reference to this object, for chaining. + SystemBuilder& ingroup(const std::string& grouptag); + /// @brief Adds a condition to the current system. If this condition returns false, the /// system will not be executed. For a system to run, all conditions must return true. /// @tparam F Condition system type. @@ -172,11 +200,6 @@ namespace cubos::core::ecs template Cubos& addResource(TArgs... args); - /// @brief Returns a @ref groupBuilder to configure the given group. - /// @param tags Tags that will be in the group. - /// @return @ref groupBuilder used to configure the group. - GroupBuilder group(const std::string& tag); - /// @brief Adds a new component type to the engine. /// @tparam C Type of the component. /// @return Reference to this object, for chaining. @@ -209,6 +232,11 @@ namespace cubos::core::ecs /// @return @ref TagBuilder used to configure the tag. TagBuilder startupTag(const std::string& tag); + /// @brief creates a group. + /// @param tag Tag for the group. + /// @return @ref GroupBuilder used to configure the group. + GroupBuilder group(const std::string& tag); + /// @brief Adds a new system to the engine, which will be executed at every iteration of /// the main loop. /// @tparam F Type of the system function. @@ -249,6 +277,12 @@ namespace cubos::core::ecs return *this; } + template + TagBuilder& TagBuilder::repeatWhile(F func){ + mDispatcher.tagRepeatWhile(func); + return *this; + } + template SystemBuilder& SystemBuilder::runIf(F func) { diff --git a/core/include/cubos/core/ecs/system/dispatcher.hpp b/core/include/cubos/core/ecs/system/dispatcher.hpp index 4122fc9d85..da95b5073d 100644 --- a/core/include/cubos/core/ecs/system/dispatcher.hpp +++ b/core/include/cubos/core/ecs/system/dispatcher.hpp @@ -61,10 +61,6 @@ namespace cubos::core::ecs /// @param tag Tag to add. void addTag(const std::string& tag); - /// @brief Adds a group. - /// @param tag Tags to add. - void addGroup(const std::string& tag); - /// @brief Makes the current tag inherit the settings of another tag. /// @param tag Tag to inherit from. void tagInheritTag(const std::string& tag); @@ -83,6 +79,15 @@ namespace cubos::core::ecs template void tagAddCondition(F func); + /// @brief Adds a repeat condition to the current tag. + /// @tparam F Condition type. + /// @param func Condition to add. + template + void tagRepeatWhile(F func); + + /// @brief Adds a (sub)group to the current group. + void groupAddGroup(); + /// @brief Adds a system, and sets it as the current system for further configuration. /// @tparam F System type. /// @param func System to add. @@ -93,6 +98,10 @@ namespace cubos::core::ecs /// @param tag Tag to run under. void systemAddTag(const std::string& tag); + /// @brief Links a system to a certain group. + /// @param grouptag Tag of the group. + void systemAddGroup(const std::string& grouptag); + /// @brief Sets the current system to run after the tag. /// @param tag Tag to run after. void systemSetAfterTag(const std::string& tag); @@ -118,11 +127,9 @@ namespace cubos::core::ecs /// @param cmds Command buffer. void callSystems(World& world, CommandBuffer& cmds); - private: struct Dependency; struct SystemSettings; struct System; - struct Group; /// @brief Internal class to specify system dependencies struct Dependency @@ -131,26 +138,6 @@ namespace cubos::core::ecs std::vector system; }; - /// @brief Internal class to specify system groups - struct Group - { - std::vector groups; - std::vector tags; - std::vector systems; - std::vector before_subgroups; - std::vector after_subgroups; - - Group(std::vector mgroups, std::vector mtags, std::vector msystems, - std::vector mbefore_subgroups, std::vector mafter_subgroups) - : groups(mgroups) - , tags(mtags) - , systems(msystems) - , before_subgroups(mbefore_subgroups) - , after_subgroups(mafter_subgroups) - { - } - }; - /// @brief Internal class with settings pertaining to system/tag execution struct SystemSettings { @@ -168,8 +155,128 @@ namespace cubos::core::ecs std::shared_ptr settings; std::shared_ptr> system; std::unordered_set tags; + std::string grouptag = "main"; + }; + + class Step + { + public: + virtual ~Step() = default; + virtual void run(World& world, CommandBuffer& cmds, + std::vector>> mConditions, + std::bitset mRunConditions, + std::bitset mRetConditions) = 0; + virtual void prepare(World& world) = 0; + }; + + class SystemStep : public Step + { + public: + SystemStep(const System* system) + : system(system) + { + } + void run(World& world, CommandBuffer& cmds, + std::vector>> mConditions, + std::bitset mRunConditions, + std::bitset mRetConditions); + void prepare(World& world); + + private: + const System* system; + }; + + class GroupStep : public Step, public std::enable_shared_from_this + { + public: + GroupStep(const std::string& grouptag, const std::shared_ptr parent_step) + : grouptag(grouptag) + , parent_step(parent_step) + { + } + void run(World& world, CommandBuffer& cmds, + std::vector>> mConditions, + std::bitset mRunConditions, + std::bitset mRetConditions); + void prepare(World& world); + + void addSystemStep(const System* system) + { + steps.insert(steps.begin(), std::make_shared(system)); + } + + std::shared_ptr addGroupStep(const std::string& grouptag, + const std::shared_ptr& parent) + { + std::shared_ptr newStep = std::make_shared(grouptag, parent); + steps.insert(steps.begin(), newStep); + return newStep; + } + + void moveToFront(const std::shared_ptr& step) + { + auto it = std::find(steps.begin(), steps.end(), step); + if (it != steps.end()) + { + std::rotate(steps.begin(), it, it + 1); + } + } + + std::shared_ptr FindGroup(const std::string& tag) + { + if (tag == grouptag) + { + return std::make_shared(*this); + } + else + { + for (const auto& step : this->steps) + { + if (auto groupStepPtr = std::dynamic_pointer_cast(step)) + { + return groupStepPtr->FindGroup(tag); + } + } + } + return nullptr; + } + + void QueueSystem(const std::string& system_grouptag, System* system) + { + if (system_grouptag == this->grouptag) + { + addSystemStep(system); + + if (this->grouptag != "main") + { + this->parent_step->moveToFront(shared_from_this()); + } + return; + } + else + { + for (const auto& step : this->steps) + { + if (auto groupStepPtr = std::dynamic_pointer_cast(step)) + { + groupStepPtr->QueueSystem(system_grouptag, system); + } + } + } + } + + const std::string& getGroupTag(){ + return grouptag; + } + std::bitset conditions; + + private: + const std::string grouptag; + std::shared_ptr parent_step; + std::vector> steps; }; + private: /// @brief Internal class used to implement a DFS algorithm for call chain compilation struct DFSNode { @@ -190,23 +297,11 @@ namespace cubos::core::ecs /// @return True if a cycle was detected, false if otherwise. bool dfsVisit(DFSNode& node, std::vector& nodes); - /// @param system system pointer. - /// @return The group that corresponds to the system. - bool FindGroup(Group&, Group* parent_group, System* system); - - void prepareGroup(Group& group, World& world); - /// @brief Copies settings from inherited tags to this system, recursively solving nested /// inheritance. /// @param settings Settings to handle inheritance for. void handleTagInheritance(std::shared_ptr& settings); - /// @brief Calls all systems in a group - /// @param group Group to call the systems in. - /// @param world World to call the systems in. - /// @param cmds Command buffer. - void runGroup(Group group, World& world, CommandBuffer& cmds); - /// @brief Assign a condition a bit in the condition bitset, and returns that assigned bit. /// @ŧparam F Condition type. /// @param func Condition to assign a bit for. @@ -216,8 +311,6 @@ namespace cubos::core::ecs // Variables for holding information before call chain is compiled. - std::vector mUnorderedGroups; - Group* mCurrGroup = nullptr; ///< Current group. std::vector mPendingSystems; ///< All systems. std::map> mTagSettings; ///< All tags. std::vector>> mConditions; ///< All conditions. @@ -230,8 +323,9 @@ namespace cubos::core::ecs // Variables for holding information after call chain is compiled. std::vector mSystems; ///< Compiled order of running systems. - std::vector mGroups; ///< Compiled order of running groups. bool mPrepared = false; ///< Whether the systems are prepared for execution. + std::shared_ptr mMainStep = std::make_shared("main", nullptr); + std::shared_ptr mCurrGroup = mMainStep; }; template @@ -242,6 +336,15 @@ namespace cubos::core::ecs mTagSettings[mCurrTag]->conditions |= bit; } + template + void Dispatcher::tagRepeatWhile(F func) + { + ENSURE_CURR_TAG(); + groupAddGroup(); + auto bit = assignConditionBit(func); + mCurrGroup->conditions |= bit; + } + template void Dispatcher::addSystem(F func) { diff --git a/core/src/cubos/core/ecs/cubos.cpp b/core/src/cubos/core/ecs/cubos.cpp index 7cb56663ff..0a8b55d30e 100644 --- a/core/src/cubos/core/ecs/cubos.cpp +++ b/core/src/cubos/core/ecs/cubos.cpp @@ -11,6 +11,7 @@ using cubos::core::ecs::DeltaTime; using cubos::core::ecs::ShouldQuit; using cubos::core::ecs::SystemBuilder; using cubos::core::ecs::TagBuilder; +using cubos::core::ecs::GroupBuilder; DeltaTime::DeltaTime(float value) : value(value) @@ -33,12 +34,6 @@ TagBuilder::TagBuilder(core::ecs::Dispatcher& dispatcher, std::vector& tags) - : mDispatcher(dispatcher) - , mTags(tags) -{ -} - TagBuilder& TagBuilder::before(const std::string& tag) { mTags.push_back(tag); @@ -53,6 +48,29 @@ TagBuilder& TagBuilder::after(const std::string& tag) return *this; } +TagBuilder& TagBuilder::tagged(const std::string& tag){ + mDispatcher.tagInheritTag(tag); + return *this; +} + +GroupBuilder::GroupBuilder(core::ecs::Dispatcher& dispatcher, const std::string& grouptag) + : mDispatcher(dispatcher) + , mgrouptag(grouptag) +{ +} + +GroupBuilder& GroupBuilder::subgroup() +{ + mDispatcher.groupAddGroup(); + return *this; +} + +GroupBuilder& GroupBuilder::endgroup() +{ + mDispatcher.groupAddGroup(); + return *this; +} + SystemBuilder::SystemBuilder(core::ecs::Dispatcher& dispatcher, std::vector& tags) : mDispatcher(dispatcher) , mTags(tags) @@ -92,6 +110,12 @@ SystemBuilder& SystemBuilder::after(const std::string& tag) return *this; } +SystemBuilder& SystemBuilder::ingroup(const std::string& grouptag) +{ + mDispatcher.systemAddGroup(grouptag); + return *this; +} + Cubos& Cubos::addPlugin(void (*func)(Cubos&)) { if (!mPlugins.contains(func)) @@ -114,24 +138,18 @@ TagBuilder Cubos::tag(const std::string& tag) return builder; } -GroupBuilder Cubos::group(const std::string& tag) +TagBuilder Cubos::startupTag(const std::string& tag) { - mMainDispatcher.addGroup(tag); - GroupBuilder builder(mMainDispatcher, mMainTags); + mStartupDispatcher.addTag(tag); + TagBuilder builder(mStartupDispatcher, mStartupTags); return builder; } -GroupBuilder& GroupBuilder::endgroup() +GroupBuilder Cubos::group(const std::string& grouptag) { - mDispatcher.addGroup(""); - return *this; -} - -TagBuilder Cubos::startupTag(const std::string& tag) -{ - mStartupDispatcher.addTag(tag); - TagBuilder builder(mStartupDispatcher, mStartupTags); + mMainDispatcher.groupAddGroup(); + GroupBuilder builder(mMainDispatcher, grouptag); return builder; } diff --git a/core/src/cubos/core/ecs/system/dispatcher.cpp b/core/src/cubos/core/ecs/system/dispatcher.cpp index 0db8ce89c2..cc4b5ca9c5 100644 --- a/core/src/cubos/core/ecs/system/dispatcher.cpp +++ b/core/src/cubos/core/ecs/system/dispatcher.cpp @@ -28,30 +28,7 @@ void Dispatcher::addTag(const std::string& tag) { ENSURE_TAG_SETTINGS(tag); mCurrTag = tag; -} - -void Dispatcher::addGroup(const std::string& tag) -{ - if (tag == "") - { - mCurrGroup = nullptr; - return; - } - - Group newGroup = Group({}, {}, {}, {}, {}); - if (mCurrGroup == nullptr) - { - newGroup.tags.push_back(tag); - mUnorderedGroups.push_back(newGroup); - mCurrGroup = &mUnorderedGroups.back(); - } - else - { - newGroup.tags.insert(newGroup.tags.end(), mCurrGroup->tags.begin(), mCurrGroup->tags.end()); - newGroup.tags.push_back(tag); - mCurrGroup->groups.push_back(newGroup); - mCurrGroup = &mCurrGroup->groups.back(); - } + mCurrGroup = mMainStep; } void Dispatcher::tagInheritTag(const std::string& tag) @@ -64,6 +41,11 @@ void Dispatcher::tagInheritTag(const std::string& tag) CUBOS_INFO("Tag already inherits from '{}'", tag); } mTagSettings[mCurrTag]->inherits.push_back(tag); + mCurrGroup = mMainStep->FindGroup(tag); + if (mCurrGroup == nullptr) + { + mCurrGroup = mMainStep; + } } void Dispatcher::tagSetAfterTag(const std::string& tag) @@ -86,11 +68,28 @@ void Dispatcher::tagSetBeforeTag(const std::string& tag) mTagSettings[tag]->after.tag.push_back(mCurrTag); } +void Dispatcher::groupAddGroup() +{ + mCurrGroup = mCurrGroup->addGroupStep(mCurrTag, mCurrGroup); +} + void Dispatcher::systemAddTag(const std::string& tag) { ENSURE_CURR_SYSTEM(); ENSURE_TAG_SETTINGS(tag); mCurrSystem->tags.insert(tag); + std::shared_ptr group = mMainStep->FindGroup(tag); + if (group != nullptr) + { + mCurrSystem->grouptag = tag; + mCurrGroup = group; + } +} + +void Dispatcher::systemAddGroup(const std::string& grouptag) +{ + ENSURE_CURR_SYSTEM(); + mCurrSystem->grouptag = grouptag; } void Dispatcher::systemSetAfterTag(const std::string& tag) @@ -181,40 +180,6 @@ void Dispatcher::compileChain() mTagSettings.clear(); } -// If the system is in the group return true and put its pointer in the group -bool Dispatcher::FindGroup(Group& group, Group* parent_group, System* system) -{ - std::set tagsSet(group.tags.begin(), group.tags.end()); - - // if the group has the exact same tags as the system - if (std::equal(tagsSet.begin(), tagsSet.end(), system->tags.begin(), system->tags.end())) - { - group.systems.push_back(system); - if (parent_group != nullptr) - { - if (parent_group->systems.size() > 0) - { - parent_group->before_subgroups.push_back(group); - } - else - { - parent_group->after_subgroups.push_back(group); - } - } - else - return true; - } - - for (auto& subgroup : group.groups) - { - if (FindGroup(subgroup, &group, system)) - { - return true; - } - } - return false; -} - bool Dispatcher::dfsVisit(DFSNode& node, std::vector& nodes) { switch (node.m) @@ -279,22 +244,8 @@ bool Dispatcher::dfsVisit(DFSNode& node, std::vector& nodes) if (node.s != nullptr) { // mSystems.push_back(node.s); - bool not_in_group = true; - for (auto& group : mUnorderedGroups) - { - if (FindGroup(group, nullptr, node.s)) - { - not_in_group = false; - mGroups.push_back(group); // See if system belongs to group and put it the right order - } - } - if (not_in_group) - { - Group newGroup = - Group({}, {}, {}, {}, {}); // Create a group with a singular system just for implementation to work - newGroup.systems.push_back(node.s); - mGroups.push_back(newGroup); - } + CUBOS_WARN("{}", node.s->grouptag); + mMainStep->QueueSystem(node.s->grouptag, node.s); } return false; } @@ -302,79 +253,119 @@ bool Dispatcher::dfsVisit(DFSNode& node, std::vector& nodes) return false; } -void Dispatcher::runGroup(Group group, World& world, CommandBuffer& cmds) +void Dispatcher::SystemStep::run(World& world, CommandBuffer& cmds, + std::vector>> mConditions, + std::bitset mRunConditions, + std::bitset mRetConditions) { - if (group.before_subgroups.size() > 0) + bool canRun = true; + if (system->settings != nullptr) { - for (Group child : group.before_subgroups) + auto conditionsMask = system->settings->conditions; + std::size_t i = 0; + while (conditionsMask.any()) { - runGroup(child, world, cmds); + if (conditionsMask.test(0)) + { + // We have a condition, check if it has run already + if (!mRunConditions.test(i)) + { + mRunConditions.set(i); + if (mConditions[i]->call(world, cmds)) + { + mRetConditions.set(i); + } + } + // Check if the condition returned true + if (!mRetConditions.test(i)) + { + canRun = false; + break; + } + } + + i += 1; + conditionsMask >>= 1; } } - for (auto& system : group.systems) + if (canRun) + { + system->system->call(world, cmds); + } + + // TODO: Check synchronization concerns when this gets multithreaded + cmds.commit(); +} + +void Dispatcher::GroupStep::run(World& world, CommandBuffer& cmds, + std::vector>> mConditions, + std::bitset mRunConditions, + std::bitset mRetConditions) +{ + for (auto& step : steps) { - // Query for conditions - bool canRun = true; - if (system->settings != nullptr) + if (auto groupStepPtr = std::dynamic_pointer_cast(step)) { - auto conditionsMask = system->settings->conditions; - std::size_t i = 0; - while (conditionsMask.any()) + bool canRun = true; + while (canRun) { - if (conditionsMask.test(0)) + + auto conditionsMask = groupStepPtr->conditions; + std::size_t i = 0; + while (conditionsMask.any()) { - // We have a condition, check if it has run already - if (!mRunConditions.test(i)) + if (conditionsMask.test(0)) { - mRunConditions.set(i); + // We have a condition, check if it has run already + if (!mRunConditions.test(i)) + { + mRunConditions.set(i); + } if (mConditions[i]->call(world, cmds)) { mRetConditions.set(i); } + else{ + mRetConditions.reset(i); + } + // Check if the condition returned true + if (!mRetConditions.test(i)) + { + canRun = false; + break; + } } - // Check if the condition returned true - if (!mRetConditions.test(i)) - { - canRun = false; - break; - } - } - i += 1; - conditionsMask >>= 1; + i += 1; + conditionsMask >>= 1; + } + + if (canRun) + { + groupStepPtr->run(world, cmds, mConditions, mRunConditions, mRetConditions); + } } } - - if (canRun) + else if (auto SystemStepPtr = std::dynamic_pointer_cast(step)) { - system->system->call(world, cmds); + SystemStepPtr->run(world, cmds, mConditions, mRunConditions, mRetConditions); } - - // TODO: Check synchronization concerns when this gets multithreaded - cmds.commit(); } + // step->run(world, cmds, mConditions, mRunConditions, mRetConditions); +} - if (group.after_subgroups.size() > 0) - { - for (Group child : group.after_subgroups) - { - runGroup(child, world, cmds); - } - } +void Dispatcher::SystemStep::prepare(World& world) +{ + system->system->prepare(world); } -void Dispatcher::prepareGroup(Group& group, World& world) +void Dispatcher::GroupStep::prepare(World& world) { - for (auto& system : group.systems){ - system->system->prepare(world); - } - for (auto& subgroup : group.before_subgroups){ - prepareGroup(subgroup, world); - } - for (auto& subgroup : group.after_subgroups){ - prepareGroup(subgroup, world); + for (auto& step : steps) + { + step->prepare(world); } } @@ -384,10 +375,7 @@ void Dispatcher::callSystems(World& world, CommandBuffer& cmds) // We can't multi-thread this as the systems require exclusive access to the world to prepare. if (!mPrepared) { - for (auto group : mGroups) - { - prepareGroup(group, world); - } + mMainStep->prepare(world); for (auto& condition : mConditions) { @@ -401,8 +389,5 @@ void Dispatcher::callSystems(World& world, CommandBuffer& cmds) mRunConditions.reset(); mRetConditions.reset(); - for (auto group : mGroups) - { - runGroup(group, world, cmds); - } -} + mMainStep->run(world, cmds, mConditions, mRunConditions, mRetConditions); +} \ No newline at end of file diff --git a/engine/include/cubos/engine/physics/resources/substeps.hpp b/engine/include/cubos/engine/physics/resources/substeps.hpp index dc0a531643..79b3e19197 100644 --- a/engine/include/cubos/engine/physics/resources/substeps.hpp +++ b/engine/include/cubos/engine/physics/resources/substeps.hpp @@ -11,5 +11,6 @@ namespace cubos::engine struct Substeps { int value = 1; + int repeat_times = 3; }; } // namespace cubos::engine diff --git a/engine/src/cubos/engine/physics/plugin.cpp b/engine/src/cubos/engine/physics/plugin.cpp index 837b0e035f..ef1cb21dc9 100644 --- a/engine/src/cubos/engine/physics/plugin.cpp +++ b/engine/src/cubos/engine/physics/plugin.cpp @@ -102,6 +102,17 @@ static void updateVelocitySystem(Query query) { for (auto [velocity, mass] : query) @@ -136,6 +147,8 @@ void cubos::engine::physicsPlugin(Cubos& cubos) // executed every frame cubos.system(increaseAccumulator).tagged("cubos.physics.simulation.prepare"); + cubos.tag("substeps").repeatWhile(repeatThree); + cubos.tag("cubos.physics.apply_forces") .after("cubos.physics.simulation.prepare") .before("cubos.physics.simulation.substeps.integrate") @@ -150,14 +163,17 @@ void cubos::engine::physicsPlugin(Cubos& cubos) .tagged("cubos.physics.simulation.substeps.integrate") .after("cubos.physics.simulation.prepare") .runIf(simulatePhysicsStep); + //.tagged("substeps"); cubos.system(applyCorrectionSystem) .tagged("cubos.physics.simulation.substeps.correct_position") .after("cubos.physics.simulation.substeps.integrate") .runIf(simulatePhysicsStep); + //.tagged("substeps"); cubos.system(updateVelocitySystem) .tagged("cubos.physics.simulation.substeps.update_velocity") .after("cubos.physics.simulation.substeps.correct_position") .runIf(simulatePhysicsStep); + //.tagged("substeps"); cubos.system(clearForcesSystem) .tagged("cubos.physics.simulation.clear_forces") .after("cubos.physics.simulation.substeps.update_velocity")