Files
DX12/Engine/EngineAPI/GameEntity.h
2026-03-19 18:27:49 +08:00

192 lines
5.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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<entity_script>;
#ifdef USESTDFUNC
/**
* @brief 基于 std::function 的脚本工厂签名。
*/
using script_creator = std::function<script_ptr(game_entity::entity entity)>;
#else
/**
* @brief 基于函数指针的脚本工厂签名。
*/
using script_creator = script_ptr(*)(game_entity::entity entity);
#endif // USESTDFUNC
/**
* @brief 脚本名哈希器类型。
*/
using string_hash = std::hash<std::string>;
/**
* @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<class script_class>
script_ptr create_script(game_entity::entity entity)
{
assert(entity.is_valid());
return std::make_unique<script_class>(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<TYPE>) }; \
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<TYPE>) }; \
}
#endif // USE_WITH_EDITOR
}//namespace detail
}//namespace script
}