添加场景的组件动态添加删除功能

This commit is contained in:
2025-05-31 13:30:54 +08:00
parent 31c77dcb5e
commit fdd13a8726
20 changed files with 340 additions and 59 deletions

View File

@ -3,8 +3,8 @@
//
#include "SceneHierachyPanel.h"
#include <imgui.h>
#include <imgui_internal.h>
#include <glm/gtc/type_ptr.hpp>
#include <Hazel/Scene/Components.h>
@ -34,6 +34,13 @@ namespace Hazel
m_SelectionContext = { };
}
if (ImGui::BeginPopupContextWindow(0, ImGuiPopupFlags_MouseButtonRight | ImGuiPopupFlags_NoOpenOverItems))
{
if (ImGui::MenuItem("Create Empty Entity"))
m_Context->CreateEntity("Empty Entity");
ImGui::EndPopup();
}
ImGui::End();
ImGui::Begin("Properties");
@ -48,18 +55,172 @@ namespace Hazel
void SceneHierachyPanel::DrawEntityNode(Entity entity)
{
auto& tag = entity.GetComponent<TagComponent>().Tag;
bool entityDeleted = false;
ImGuiTreeNodeFlags flags = ((m_SelectionContext == entity) ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow;
flags |= ImGuiTreeNodeFlags_SpanAvailWidth;
const bool isopened = ImGui::TreeNodeEx((void*)(uint64_t)(uint32_t)entity, flags, tag.c_str());
if (ImGui::IsItemClicked())
{
m_SelectionContext = entity;
}
if (ImGui::BeginPopupContextItem())
{
if (ImGui::MenuItem("Delete Entity"))
entityDeleted = true;
ImGui::EndPopup();
}
if (isopened)
{
ImGui::TreePop();
}
if (entityDeleted)
{
m_Context->DestoryEntity(entity);
if (m_SelectionContext == entity)
{
m_SelectionContext = {};
}
}
}
static bool DrawVec3Control(const std::string& label, glm::vec3& values, float resetValue = 0.0f, float columnWidth = 100.0f)
{
ImGuiIO& io = ImGui::GetIO();
auto boldFont = io.Fonts->Fonts[0];
bool isChanged = false;
ImGui::PushID(label.c_str());
const ImGuiContext* context = ImGui::GetCurrentContext();
ImGui::Columns(2);
ImGui::SetColumnWidth(0, columnWidth);
ImGui::Text(label.c_str());
ImGui::NextColumn();
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, {0.0f, 0.0f});
float lineHeight = context->Font->FontSize + context->Style.FramePadding.y * 2.0f;
// float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
ImVec2 buttonSize = {lineHeight + 3.0f, lineHeight};
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.8f, 0.1f, 0.15f, 1.0f});
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{0.9f, 0.2f, 0.2f, 1.0f});
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{0.8f, 0.1f, 0.15f, 1.0f});
ImGui::PushFont(boldFont);
if (ImGui::Button("X", buttonSize))
{
values.x = resetValue;
isChanged = true;
}
ImGui::PopFont();
ImGui::PopStyleColor(3);
ImGui::SameLine();
if (ImGui::DragFloat("##X", &values.x, 0.1f))
{
isChanged = true;
}
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.2f, 0.7f, 0.2f, 1.0f});
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{0.3f, 0.8f, 0.3f, 1.0f});
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{0.2f, 0.7f, 0.2f, 1.0f});
ImGui::PushFont(boldFont);
if (ImGui::Button("Y", buttonSize))
{
values.y = resetValue;
isChanged = true;
}
ImGui::PopFont();
ImGui::PopStyleColor(3);
ImGui::SameLine();
if (ImGui::DragFloat("##Y", &values.y, 0.1f))
{
isChanged = true;
}
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{0.1f, 0.25f, 0.8f, 1.0f});
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{0.2f, 0.35f, 0.9f, 1.0f});
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{0.1f, 0.25f, 0.8f, 1.0f});
ImGui::PushFont(boldFont);
if (ImGui::Button("Z", buttonSize))
{
values.z = resetValue;
isChanged = true;
}
ImGui::PopFont();
ImGui::PopStyleColor(3);
ImGui::SameLine();
if (ImGui::DragFloat("##Z", &values.z, 0.1f))
{
isChanged = true;
}
ImGui::PopItemWidth();
ImGui::PopStyleVar();
ImGui::Columns(1);
ImGui::PopID();
return isChanged;
}
template<typename T, typename UIfunction>
void DrawComponent(const std::string& name, Entity entity, UIfunction uiFunction)
{
constexpr ImGuiTreeNodeFlags treeNodeFlags = ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_FramePadding;;
if (entity.HasComponent<T>())
{
auto& component = entity.GetComponent<T>();
ImVec2 contextReginAvail = ImGui::GetContentRegionAvail();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {4.0f, 4.0f});
auto context = ImGui::GetCurrentContext();
float lineHeight = context->Font->FontSize + context->Style.FramePadding.y * 2.0f;
ImGui::Separator();
bool open = ImGui::TreeNodeEx((void*)(uint64_t)typeid(T).hash_code(), treeNodeFlags, name.c_str());
ImGui::PopStyleVar();
ImGui::SameLine(contextReginAvail.x - lineHeight * 0.5f);
if (ImGui::Button("+", ImVec2(lineHeight, lineHeight)))
{
ImGui::OpenPopup("ComponentSettings");
}
bool removeComponent = false;
if (ImGui::BeginPopup("ComponentSettings"))
{
if (ImGui::MenuItem("Remove Component"))
removeComponent = true;
ImGui::EndPopup();
}
if (open)
{
uiFunction(component);
ImGui::TreePop();
}
if (removeComponent)
entity.RemoveComponent<SpriteRendererComponent>();
}
}
void SceneHierachyPanel::DrawComponents(Entity entity)
@ -77,25 +238,44 @@ namespace Hazel
}
}
if (entity.HasComponent<TransformComponent>())
ImGui::SameLine();
ImGui::PushItemWidth(-1);
if (ImGui::Button("Add"))
ImGui::OpenPopup("Add");
if (ImGui::BeginPopup("Add"))
{
if (ImGui::TreeNodeEx((void*)(uint64_t)typeid(TransformComponent).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "Transform"))
if (ImGui::MenuItem("Camera"))
{
auto& transform = entity.GetComponent<TransformComponent>().Transform;
ImGui::DragFloat3("Position", glm::value_ptr(transform[3]), 0.01f);
ImGui::TreePop();
m_SelectionContext.AddComponent<CameraComponent>();
ImGui::CloseCurrentPopup();
}
}
if (entity.HasComponent<CameraComponent>())
{
if (ImGui::TreeNodeEx((void*)(uint64_t)typeid(CameraComponent).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "Transform"))
if (ImGui::MenuItem("Sprite"))
{
auto& cameraComponent = entity.GetComponent<CameraComponent>();
auto& camera = cameraComponent.Camera;
m_SelectionContext.AddComponent<SpriteRendererComponent>();
ImGui::CloseCurrentPopup();
}
ImGui::Checkbox("isPrimary", &cameraComponent.Primary);
ImGui::EndPopup();
}
ImGui::PopItemWidth();
DrawComponent<TransformComponent>("Transform", entity, [](auto& component)
{
DrawVec3Control("Translation", component.Translation);
glm::vec3 rotation = glm::degrees(component.Rotation);
if (DrawVec3Control("Rotation", rotation))
{
component.Rotation = glm::radians(rotation);
}
DrawVec3Control("Scale", component.Scale, 1.0f);
});
DrawComponent<CameraComponent>("Camera", entity, [](auto& component)
{
auto& camera = component.Camera;
ImGui::Checkbox("isPrimary", &component.Primary);
static const char* projectionTypeStrings[] = { "Perspective", "Orthographic" };
const char* currentProjectionTypeString = projectionTypeStrings[(int)camera.GetProjectionType()];
@ -146,23 +326,13 @@ namespace Hazel
if (ImGui::DragFloat("Far", &far))
camera.SetOrthographicFarClip(far);
ImGui::Checkbox("Fixed Aspect Ratio", &cameraComponent.FixedAspectRatio);
ImGui::Checkbox("Fixed Aspect Ratio", &component.FixedAspectRatio);
}
});
ImGui::TreePop();
}
}
if (entity.HasComponent<SpriteRendererComponent>())
DrawComponent<SpriteRendererComponent>("Sprite Renderer", entity, [](auto& component)
{
if (ImGui::TreeNodeEx((void*)(uint64_t)typeid(SpriteRendererComponent).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "Sprite Renderer"))
{
auto& spriteRendererComponent = entity.GetComponent<SpriteRendererComponent>();
ImGui::ColorEdit4("Color", glm::value_ptr(spriteRendererComponent.Color));
ImGui::TreePop();
}
}
ImGui::ColorEdit4("Color", glm::value_ptr(component.Color));
});
}
}