目录
前言
掌握Piccolo中反射宏和反射标签的用法,选择自己感兴趣的系统,给它管理的Component结构增加或修改一个属性,检查它及ComPonent结构的反射宏和反射标签,确保它能够被正确的反射。
一、代码框架说明
1.反射宏:
CLASS(class_name, tags···)
用以反射类型的声明,class_name参数填写类型名称,如果需要继承基类则直接按继承写法写在该参数内,tags参数填写传递给反射系统的反射标签,多个标签需要以','分隔
例:
STRUCT(struct_name, tags···)
用以反射结构体的声明,struct_name参数填写结构体名称,tags参数填写传递给反射系统的反射标签,多个标签需要以','分隔;
例:
META(tags···)
用以给类或结构体的属性增加反射信息标签,写在属性定义前,tags参数填写传递给反射系统的反射标签,多个标签需要以','分隔;
例:
REFLECTION_TYPE(class_name)
用以提供反射访问器的声明,配合CLASS使用,写在类型定义前,class_name填写类型名称
例:
REFLECTION_BODY(class_name)
对访问器进行友元声明,允许访问器访问其私有属性,写在类型定义内第一行,class_name填写类型名称,需配合REFLECTION_TYPE;、
例:
2.反射标签
Fields
表明类型或结构体中除特殊标记的属性外(如Disable),其余所有属性均需要反射,该标签需要在CLASS或STRUCT中声明。如下图中,PhysicsControllerConfig类型标记了Fields标签,因此其所有属性都支持反射
WhiteListFields
表明类型或结构体中只有标记过的属性才允许反射(即被设置为Enable标签),该标签需在CLASS或STRUCT中声明。如下图中,Motorcomponent类型标记了WhiteListField标签,因此只有被设定为Enable的才允许反射;
Disable
表明该属性无需反射,该标签需要在属性前以META参数的形式声明,且只有在CLASS或STRUCT中声明为Fields时有效。
Enable
表明该属性需要反射,该标签需要在属性前以META参数的形式声明,且只有在CLASS或STRUCT中声明为WhiteListFields时有效
3.反射功能类
4.反射生成面板过程
Piccolo中Components Details面板通过反射系统自动生成,显示场景中选中物体的所有component信息,如下图所示:
实现思路:
使用反射系统,将复杂类型拆解为UI控件可直接表示的原子类型,生成对应的UI控件,形成原子类型控件树,展示复杂类型信息
实现过程:
1.在editor_ui.cpp文件的showEditorDetailWindow方法中,获取选中物体的所有component对象
2.为每个component对象构造反射实例,并依次调用createComponentUI对反射实例进行类型拆解
3.在editor_ui.cpp文件的createComponentUI方法中,先获取该类型的所有基类反射实例,并递归调用该方法生成基类的UI,然后通过调用createLeafNodeUI方法生成该类型属性UI
4.在editor_ui.cpp文件的createLeafNodeUI方法中,获取到所有属性访问器
5.遍历所有属性访问器,使用属性类型名称查找对应的构建方法,传入属性名称和属性地址,进行最后的UI生成
6.UI生成过程中,需要对UI支持的原子类型进行数据和UI控件的绑定,因此需要建立原子类型的UI构建方法表,m_editor_ui_creator是一个map<std::string, std::function<const std::string&, void*>>,对于每一种UI支持的原子类类型,都需要注册其属性名及处理方法
7.除了原子类型外,对于复杂类型,需要继续调用createClassUI方法进行拆解
8.对于容器类型,如array,需要遍历array,对于每个元素进行;类型判断,原子类型则直接生成UI,非原子类型继续调用createClassUI进行类型拆解
二、使用反射系统实现功能
1.新增Struct
在motor_component.h中新增一个结构体MyStruct
value:表示实际值
min_value:表示最小值
max_value:表示最大值
2.新添加一个成员
在motorComponent中新加一个成员,表示自己的跳跃高度,默认值为1.0f,最小跳跃高度是0.5f,最大跳跃高度是10.0f
3.面板显示
在editor_ui.cpp中加入如下代码
//用于在编辑器界面创建一个用于编辑自定义结构体的UI元素
//将lambda函数绑定到m_editor_ui_creator
//该函数接受一个名称参数name和一个指向MyStruct对象的指针参数 并返回一个void类型
m_editor_ui_creator["MyStruct"] = [this](const std::string& name, void* value_ptr) -> void{
//检查当前节点的深度是否为-1,如果不是-1 表示当前正在渲染一个节点 可以继续创建UI元素
if(g_node_depth != -1)
{
//根据传入名称 创建一个用于标签的字符串
std::string label = "##" + name;
//使用ImGui库创建一个文本标签,显示传入的名称
ImGui::Text("%s", name.c_str());
//将下一个UI元素放在同一行
ImGui::SameLine();
//使用ImGui库创建一个滑动条UI元素,用于编辑MyStruct对象的value属性
//滑动条的标签为之前创建的label字符串,滑动条的范围由MyStruct对象的min_value
//和max_value属性决定
ImGui::SliderFloat(label.c_str(),
&static_cast<MyStruct*>(value_ptr)->value,
static_cast<MyStruct*>(value_ptr)->min_value,
static_cast<MyStruct*>(value_ptr)->max_value);
}
};
4.跳跃逻辑修改
将跳跃高度设置为MyStruct中value的高度,从而实现跳跃高度的修改
在motor_component.cpp中做如下修改:
三、结果展示
修改跳跃高度为区间[0.5, 10]