Hazel Game Engine (085) Properties Panel

If there are errors in the code, terminology, etc. in the text, please correct me

Article directory

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

Please add a picture description

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

    Please add a picture description

  • 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 .

Guess you like

Origin blog.csdn.net/qq_34060370/article/details/132137503