Kaynağa Gözat

helper: added a shortcut to invoke members on components from callbacks (close #385)

Michele Caini 6 yıl önce
ebeveyn
işleme
6ffaf11226
3 değiştirilmiş dosya ile 50 ekleme ve 1 silme
  1. 15 0
      docs/md/entity.md
  2. 19 1
      src/entt/entity/helper.hpp
  3. 16 0
      test/entt/entity/helper.cpp

+ 15 - 0
docs/md/entity.md

@@ -19,6 +19,7 @@
   * [Helpers](#helpers)
     * [Null entity](#null-entity)
     * [Dependencies](#dependencies)
+    * [Invoke](#invoke)
     * [Actor](#actor)
     * [Context variables](#context-variables)
   * [Meet the runtime](#meet-the-runtime)
@@ -606,6 +607,20 @@ There are many other types of dependencies. In general, most of the functions
 that accept an entity as the first argument are good candidates for this
 purpose.
 
+### Invoke
+
+Sometimes it's useful to be able to directly invoke a member function of a
+component as a callback. It's already possible in practice but requires users to
+_extend_ their classes and this may not always be possible.<br/>
+The `invoke` helper allows to _propagate_ the signal in these cases:
+
+```cpp
+registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
+```
+
+All it does is pick up the _right_ component for the received entity and invoke
+the requested method, passing on the arguments if necessary.
+
 ### Actor
 
 The `actor` class is designed for those who don't feel immediately comfortable

+ 19 - 1
src/entt/entity/helper.hpp

@@ -3,8 +3,9 @@
 
 
 #include <type_traits>
-#include "../core/type_traits.hpp"
 #include "../config/config.h"
+#include "../core/type_traits.hpp"
+#include "../signal/delegate.hpp"
 #include "registry.hpp"
 #include "fwd.hpp"
 
@@ -111,6 +112,23 @@ template<typename Entity>
 as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>;
 
 
+
+/**
+ * @brief Helper to create a listener that directly invokes a member function.
+ * @tparam Member Member function to invoke on a component of the given type.
+ * @tparam Entity A valid entity type (see entt_traits for more details).
+ * @param reg A registry that contains the given entity and its components.
+ * @param entt Entity from which to get the component.
+ */
+template<auto Member, typename Entity = entity>
+void invoke(basic_registry<Entity> &reg, const Entity entt) {
+    static_assert(std::is_member_function_pointer_v<decltype(Member)>);
+    delegate<void(basic_registry<Entity> &, const Entity)> func;
+    func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
+    func(reg, entt);
+}
+
+
 }
 
 

+ 16 - 0
test/entt/entity/helper.cpp

@@ -1,9 +1,15 @@
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/entity/helper.hpp>
+#include <entt/entity/entity.hpp>
 #include <entt/entity/registry.hpp>
 #include <entt/core/type_traits.hpp>
 
+struct clazz {
+    void func(entt::registry &, entt::entity curr) { entt = curr; }
+    entt::entity entt{entt::null};
+};
+
 TEST(Helper, AsView) {
     entt::registry registry;
     const entt::registry cregistry;
@@ -22,3 +28,13 @@ TEST(Helper, AsGroup) {
     ([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, double>) {})(entt::as_group{registry});
     ([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, const double>) {})(entt::as_group{registry});
 }
+
+TEST(Invoke, MemberFunction) {
+    entt::registry registry;
+    const auto entity = registry.create();
+
+    registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
+    registry.assign<clazz>(entity);
+
+    ASSERT_EQ(entity, registry.get<clazz>(entity).entt);
+}