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

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -57,16 +57,16 @@ namespace Hazel
public:
void OnUpdate(const TimeStep ts)
{
auto& transform = GetComponent<TransformComponent>().Transform;
auto& translation = GetComponent<TransformComponent>().Translation;
static const auto state = SDL_GetKeyboardState(nullptr);
if (state[SDL_SCANCODE_A])
transform[3][0] -= ts * speed;
translation.x -= ts * speed;
if (state[SDL_SCANCODE_D])
transform[3][0] += ts * speed;
translation.x += ts * speed;
if (state[SDL_SCANCODE_W])
transform[3][1] += ts * speed;
translation.y += ts * speed;
if (state[SDL_SCANCODE_S])
transform[3][1] -= ts * speed;
translation.y -= ts * speed;
}
private:
float speed = 2.0f;
@ -175,6 +175,8 @@ namespace Hazel
// Submit the DockSpace
ImGuiIO& io = ImGui::GetIO();
ImGuiStyle& style = ImGui::GetStyle();
style.WindowMinSize.x = 350.0f;
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");

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));
});
}
}

View File

@ -10,7 +10,7 @@ namespace Hazel
{
public:
HazelEditor()
: Application("Hazel Editor", 1280, 720)
: Application("Hazel Editor", 1600, 900)
{
PushLayer(new EditorLayer());
}