/** * @file GameEntity.h * @brief 实体句柄、脚本基类与脚本注册机制定义。 * @details * 该文件是引擎 ECS 对外脚本接口的核心入口: * - game_entity::entity 提供实体句柄及常用变换访问; * - script::entity_script 定义脚本生命周期与变换写接口; * - script::detail 提供脚本工厂注册、按名称哈希检索与宏封装。 */ #pragma once #include "..\Components\ComponentsCommon.h" #include "TransformComponent.h" #include "ScriptComponent.h" namespace XEngine{ namespace game_entity { /** * @brief 实体强类型标识符。 */ DEFINE_TYPED_ID(entity_id); /** * @brief 运行时实体句柄封装。 */ class entity { public: /** * @brief 由实体 ID 构造句柄。 */ constexpr explicit entity(entity_id id) : _id{ id } {} /** * @brief 构造无效实体句柄。 */ constexpr entity() : _id{ id::invalid_id } {} /** * @brief 获取实体 ID。 */ [[nodiscard]] constexpr entity_id get_id() const { return _id; } /** * @brief 判断实体句柄是否有效。 */ [[nodiscard]] constexpr bool is_valid() const { return id::is_valid(_id); } /** * @brief 获取实体变换组件句柄。 */ [[nodiscard]] transform::component transform() const; /** * @brief 获取实体脚本组件句柄。 */ [[nodiscard]] script::component script() const; [[nodiscard]] math::v4 rotation() const { return transform().rotation(); } [[nodiscard]] math::v3 orientation() const { return transform().orientation(); } [[nodiscard]] math::v3 position() const { return transform().position(); } [[nodiscard]] math::v3 scale() const { return transform().scale(); } private: entity_id _id; }; } namespace script { /** * @brief 实体脚本基类。 * @details * 派生类可覆盖 begin_play/update,并通过受保护接口修改实体变换。 */ class entity_script : public game_entity::entity { public: /** * @brief 析构脚本实例。 */ virtual ~entity_script() = default; /** * @brief 脚本启动回调。 */ virtual void begin_play() {} /** * @brief 脚本逐帧更新回调。 * @param dt 帧时间步长。 */ virtual void update(float) {} protected: constexpr explicit entity_script(game_entity::entity entity) : game_entity::entity{ entity.get_id() }{} void set_rotation(math::v4 rotation_quaternion) const {set_rotation(this, rotation_quaternion);} void set_orientation(math::v3 orientation_vector) const {set_orientation(this, orientation_vector);} void set_position(math::v3 position) const {set_position(this, position);} void set_scale(math::v3 scale) const { set_scale(this, scale); } static void set_rotation(const game_entity::entity *const entity, math::v4 rotation_quaternion); static void set_orientation(const game_entity::entity *const entity, math::v3 orientation_vector); static void set_position(const game_entity::entity *const entity, math::v3 position); static void set_scale(const game_entity::entity *const entity, math::v3 scale); }; namespace detail { /** * @brief 脚本实例智能指针类型。 */ using script_ptr = std::unique_ptr; #ifdef USESTDFUNC /** * @brief 基于 std::function 的脚本工厂签名。 */ using script_creator = std::function; #else /** * @brief 基于函数指针的脚本工厂签名。 */ using script_creator = script_ptr(*)(game_entity::entity entity); #endif // USESTDFUNC /** * @brief 脚本名哈希器类型。 */ using string_hash = std::hash; /** * @brief 注册脚本工厂到脚本注册表。 * @param tag 脚本哈希标签。 * @param creator 脚本工厂函数。 * @return 注册结果码。 */ u8 register_script(size_t tag, script_creator creator); #ifdef USE_WITH_EDITOR extern "C" __declspec(dllexport) #endif /** * @brief 按哈希标签查询脚本工厂。 * @param tag 脚本名哈希。 * @return 对应脚本工厂函数。 */ script_creator get_script_creator(size_t tag); /** * @brief 默认脚本工厂模板函数。 * @tparam script_class 脚本类型。 * @param entity 绑定实体。 * @return 新创建脚本实例。 */ template script_ptr create_script(game_entity::entity entity) { assert(entity.is_valid()); return std::make_unique(entity); } #ifdef USE_WITH_EDITOR /** * @brief 向编辑器导出脚本名称。 * @param name 脚本类名。 * @return 写入结果码。 */ u8 add_script_name(const char* name); #define REGISTER_SCRIPT(TYPE) \ namespace { \ u8 _reg_##TYPE{ \ XEngine::script::detail::register_script( \ XEngine::script::detail::string_hash()(#TYPE), \ &XEngine::script::detail::create_script) }; \ const u8 _name_##TYPE \ { XEngine::script::detail::add_script_name(#TYPE) }; \ } #else #define REGISTER_SCRIPT(TYPE) \ class TYPE; \ namespace { \ u8 _reg_##TYPE{ \ XEngine::script::detail::register_script( \ XEngine::script::detail::string_hash()(#TYPE), \ &XEngine::script::detail::create_script) }; \ } #endif // USE_WITH_EDITOR }//namespace detail }//namespace script }