Hazel游戏引擎(089)添加删除实体和组件

文中若有代码、术语等错误,欢迎指正

前言

  • 目的

    此节需要完成像Unity那样

    • 右键实体可以弹出菜单可以删除实体,右键空白地方可以弹出菜单添加实体
    • 在属性面板显示实体的组件,有添加组件按钮,点击弹出菜单项可以添加相应组件。
    • 在属性面板显示实体的组件,每个组件的下拉有按钮,点击弹出菜单项可以删除这个组件
  • 有点需要注意

    给实体添加摄像机组件后,并不会立即显示画面,因为投影矩阵的aspect ratio宽高比是0,投影矩阵无,所以应在添加摄像机实体的时候就设置当前视口的宽高比,从而计算投影矩阵。

关键代码

  • 删除、添加实体

    void SceneHierarchyPanel::OnImGuiRender()
    {
          
          
        // 判断当前点击的实体是否存在
        ImGui::Begin("Properties");
        if (m_SelectionContext) {
          
           // operator uint32_t() 的是const,不然不会调用operator bool(),而是调用uint32_t()
            DrawComponents(m_SelectionContext);
            // 弹出菜单: 在属性面板显示添加组件按钮
            if (ImGui::Button("Add Component")) {
          
          
                ImGui::OpenPopup("AddComponent");// AddComponent只是id
            }
            if (ImGui::BeginPopup("AddComponent")) {
          
          
                if (ImGui::MenuItem("Camera")) {
          
          
                    m_SelectionContext.AddComponent<CameraComponent>();
                    ImGui::CloseCurrentPopup();
                }
                if (ImGui::MenuItem("Sprite Renderer")) {
          
          
                    m_SelectionContext.AddComponent<SpriteRendererComponent>();
                }
                ImGui::EndPopup();
            }
        }
        ImGui::End();
    }
    void SceneHierarchyPanel::DrawEntityNode(Entity entity)
    {
          
          
        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; // 记录当前点击的实体
        }
        // 右键实体 弹出菜单:删除实体
        bool entityDeleted = false;
        if (ImGui::BeginPopupContextItem()) {
          
          
            if (ImGui::MenuItem("Delete Entity")) {
          
          
                entityDeleted = true;
            }
            ImGui::EndPopup();
        }
    
  • ImGui弹出菜单与延迟删除

    void SceneHierarchyPanel::OnImGuiRender()
    {
          
          
        // 右击空白面板-弹出菜单。0是ID 1是右键
        if (ImGui::BeginPopupContextWindow(0, 1, false)) {
          
          
            if (ImGui::MenuItem("Create Empty Entity")) {
          
          
                m_Context->CreateEntity("Empty Entity");
            }
            ImGui::EndPopup();
        }
        ImGui::End();
    .......
    void SceneHierarchyPanel::DrawComponents(Entity entity)
    {
          
          
        // 点击按钮-弹出菜单
        if (ImGui::Button("+", ImVec2{
          
          20, 20})) {
          
          
            ImGui::OpenPopup("ComponentSettings");// ComponentSettings只是id
        }
        bool removeComponent = false;
        if (ImGui::BeginPopup("ComponentSettings")) {
          
          
            if (ImGui::MenuItem("Remove component")) {
          
          
                removeComponent = true;
            }
            ImGui::EndPopup();
        }
        // 延迟删除
        if (removeComponent) {
          
          
            entity.RemoveComponent<SpriteRendererComponent>();
        }
    
  • 添加摄像机组件的时候,设置视口大小计算投影矩阵

    Scene.h
    private:
        template<typename T>
        void OnComponentAdded(Entity entity, T& component);
    Scene.cpp
    // 模板类定义在cpp中
    template<typename T>
    void Scene::OnComponentAdded(Entity entity, T& component)
    {
          
          
        // 静态断言:false,代表在编译前就会执行, 但是编译器这里不会报错,说明这段代码不会编译吧。。
        // 而且打了断点,也不行,证明这段代码只是声明作用吧。
        static_assert(false);
    }
    template<>
    void Scene::OnComponentAdded<CameraComponent>(Entity entity, CameraComponent& component)
    {
          
          
        entity.GetComponent<TransformComponent>().Translation = {
          
           0, 0, 5.0f };
        component.camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight);
    }
    
    

效果

image-20230730185043197

请添加图片描述

场景有绿色的quad,是因为删除了绿色的实体,opengl却还有缓存

自己遇到的bug

  • 问题描述

    删除实体或者实体的sprite,场景还是会绘制最后删除的quad,应该是没清除缓存还是啥。

  • 尝试解决

    可以在scene代码加上,如果没有spriteer要绘制就清空(好像也没用)

    if (mainCamera) {
          
          
        Renderer2D::BeginScene(*mainCamera, cameraTransform);
        auto group = m_Registry.group<TransformComponent>(entt::get<SpriteRendererComponent>);
        for (auto entity : group) {
          
          
            // get返回的tuple里本是引用
            auto [tfc, sprite] = group.get<TransformComponent, SpriteRendererComponent>(entity);
            Renderer2D::DrawQuad(tfc.GetTransform(), sprite.Color);
        }
        if (group.size() <= 0) {
          
          
            Renderer2D::Shutdown();
        }
        Renderer2D::EndScene();
    }
    

猜你喜欢

转载自blog.csdn.net/qq_34060370/article/details/132241260