If there are errors in the code, terminology, etc. in the text, please correct me
foreword
-
of this program
Write like Unity clicks Cube, and an Inspector panel will be displayed , which displays all components of Cube: transform, Mesh, etc.
-
Implementation ideas
On the basis of the SceneHierarchyPanel class in the previous section, according to which entity is currently clicked, the component value of the entity is passed into the UI of ImGUI.
code flow
-
If the currently clicked entity is valid
void SceneHierarchyPanel::OnImGuiRender() { ImGui::Begin("Scene Hierarchy"); m_Context->m_Registry.each([&](auto entityID){ Entity entity{ entityID, m_Context.get()}; DrawEntityNode(entity); }); // 优化:若当前在hierarchy面板并且没点击到实体,属性面板清空 if (ImGui::IsMouseDown(0) && ImGui::IsWindowHovered()) { m_SelectionContext = { }; } ImGui::End(); // // 新添加一个ImGui面板 // 判断当前点击的实体是否存在 ImGui::Begin("Properties"); if (m_SelectionContext) { // operator uint32_t() 的是const,不然不会调用operator bool(),而是调用uint32_t() DrawComponents(m_SelectionContext); } ImGui::End(); } void SceneHierarchyPanel::DrawEntityNode(Entity entity) { // 要引入 Log头文件 auto& tag = entity.GetComponent<TagComponent>().Tag; // 若是被点击标记为选中状态|有下一级 ImGuiTreeNodeFlags flags = ((m_SelectionContext == entity) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow; // 第一个参数是唯一ID 64的, bool opened = ImGui::TreeNodeEx((void*)(uint64_t)(uint32_t)entity, flags, tag.c_str()); if (ImGui::IsItemClicked()) { m_SelectionContext = entity; // 记录当前点击的实体 } if (opened) { ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow; bool opened = ImGui::TreeNodeEx((void*)98476565, flags, tag.c_str()); if (opened) { ImGui::TreePop(); } ImGui::TreePop(); } }
-
Display the attributes in the Tag and Transform components of this entity
void SceneHierarchyPanel::DrawComponents(Entity entity) { // 实体名称 if (entity.HasComponent<TagComponent>()) { auto& tag = entity.GetComponent<TagComponent>().Tag; // 一个字符缓冲区,限制了大小,以免太长 char buffer[256]; memset(buffer, 0, sizeof(buffer)); strcpy(buffer, tag.c_str()); if (ImGui::InputText("Tag", buffer, sizeof(buffer))) { tag = std::string(buffer); } } // 实体transform组件 if (entity.HasComponent<TransformComponent>()) { if (ImGui::TreeNodeEx((void*)typeid(TransformComponent).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "Transform")) { auto& transform = entity.GetComponent<TransformComponent>().Transform; ImGui::DragFloat3("Position", glm::value_ptr(transform[3]), 0.1f);// 0.1f是拖动文本框的步幅 // 展开树节点 ImGui::TreePop(); } } }
Effect
Log bugs
-
problem statement
If no object is selected, m_SelectionContext still returns true to enter the conditional block.
-
problem lies in
Entity overloaded operators
operator bool() const { return m_EntityHandle != entt::null; } operator uint32_t() { return (uint32_t)m_EntityHandle; }
-
doubtful at first
The m_EntityHandle of m_SelectionContext is not assigned a value of null , thinking that entt::null = 0, and the debugger later knows that the value of entt::null is not 0
-
Then debug tracking
It is found that if(m_SelectionContext) does not execute operator bool(), but executes operator uint32_t() , thus returning a number of 4294967295 greater than 0, which will naturally enter the conditional block.
The operator bool() function will only be executed when the operator uint32_t() becomes operator uint32_t() const .