Просмотр исходного кода

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

Michele Caini 6 лет назад
Родитель
Сommit
6ffaf11226
3 измененных файлов с 50 добавлено и 1 удалено
  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)
   * [Helpers](#helpers)
     * [Null entity](#null-entity)
     * [Null entity](#null-entity)
     * [Dependencies](#dependencies)
     * [Dependencies](#dependencies)
+    * [Invoke](#invoke)
     * [Actor](#actor)
     * [Actor](#actor)
     * [Context variables](#context-variables)
     * [Context variables](#context-variables)
   * [Meet the runtime](#meet-the-runtime)
   * [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
 that accept an entity as the first argument are good candidates for this
 purpose.
 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
 ### Actor
 
 
 The `actor` class is designed for those who don't feel immediately comfortable
 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 <type_traits>
-#include "../core/type_traits.hpp"
 #include "../config/config.h"
 #include "../config/config.h"
+#include "../core/type_traits.hpp"
+#include "../signal/delegate.hpp"
 #include "registry.hpp"
 #include "registry.hpp"
 #include "fwd.hpp"
 #include "fwd.hpp"
 
 
@@ -111,6 +112,23 @@ template<typename Entity>
 as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, 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 <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/core/hashed_string.hpp>
 #include <entt/entity/helper.hpp>
 #include <entt/entity/helper.hpp>
+#include <entt/entity/entity.hpp>
 #include <entt/entity/registry.hpp>
 #include <entt/entity/registry.hpp>
 #include <entt/core/type_traits.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) {
 TEST(Helper, AsView) {
     entt::registry registry;
     entt::registry registry;
     const entt::registry cregistry;
     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>, double>) {})(entt::as_group{registry});
     ([](entt::group<entt::exclude_t<int>, entt::get_t<const char>, const 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);
+}