2026-03-20 17:08:06 +08:00
|
|
|
#include "HierarchyPanel.h"
|
|
|
|
|
#include "Managers/SceneManager.h"
|
|
|
|
|
#include "Managers/SelectionManager.h"
|
2026-03-25 01:23:08 +08:00
|
|
|
#include <XCEngine/Core/Math/Vector3.h>
|
|
|
|
|
#include <XCEngine/Core/Math/Quaternion.h>
|
2026-03-20 17:08:06 +08:00
|
|
|
#include <imgui.h>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
2026-03-24 20:02:38 +08:00
|
|
|
namespace XCEngine {
|
|
|
|
|
namespace Editor {
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
HierarchyPanel::HierarchyPanel() : Panel("Hierarchy") {
|
2026-03-24 20:02:38 +08:00
|
|
|
EditorSceneManager::Get().CreateDemoScene();
|
2026-03-20 17:08:06 +08:00
|
|
|
|
2026-03-24 18:38:01 +08:00
|
|
|
m_selectionHandlerId = SelectionManager::Get().OnSelectionChanged.Subscribe([this](uint64_t) {
|
2026-03-20 17:08:06 +08:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HierarchyPanel::~HierarchyPanel() {
|
|
|
|
|
SelectionManager::Get().OnSelectionChanged.Unsubscribe(m_selectionHandlerId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HierarchyPanel::Render() {
|
|
|
|
|
ImGui::Begin(m_name.c_str(), nullptr, ImGuiWindowFlags_None);
|
|
|
|
|
|
|
|
|
|
RenderSearchBar();
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
|
|
HandleKeyboardShortcuts();
|
|
|
|
|
|
|
|
|
|
std::string filter = m_searchBuffer;
|
|
|
|
|
|
|
|
|
|
ImGui::BeginChild("EntityList");
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
for (auto* gameObject : EditorSceneManager::Get().GetRootEntities()) {
|
|
|
|
|
RenderEntity(gameObject, filter);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsWindowHovered() && ImGui::IsMouseDown(0) && !ImGui::IsAnyItemHovered()) {
|
|
|
|
|
if (!m_renaming) {
|
|
|
|
|
SelectionManager::Get().ClearSelection();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::BeginPopupContextWindow("HierarchyContextMenu", ImGuiPopupFlags_MouseButtonRight)) {
|
2026-03-24 18:38:01 +08:00
|
|
|
RenderCreateMenu(nullptr);
|
2026-03-20 17:08:06 +08:00
|
|
|
ImGui::EndPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::InvisibleButton("##DragTarget", ImVec2(-1, -1));
|
|
|
|
|
if (ImGui::BeginDragDropTarget()) {
|
2026-03-24 18:38:01 +08:00
|
|
|
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_PTR")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
::XCEngine::Components::GameObject* sourceGameObject = *(::XCEngine::Components::GameObject**)payload->Data;
|
|
|
|
|
if (sourceGameObject && sourceGameObject->GetParent() != nullptr) {
|
|
|
|
|
EditorSceneManager::Get().MoveEntity(sourceGameObject->GetID(), 0);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndDragDropTarget();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::EndChild();
|
|
|
|
|
|
|
|
|
|
ImGui::End();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HierarchyPanel::RenderSearchBar() {
|
|
|
|
|
ImGui::SetNextItemWidth(-1);
|
|
|
|
|
ImGui::InputTextWithHint("##Search", "Search...", m_searchBuffer, sizeof(m_searchBuffer));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
void HierarchyPanel::RenderEntity(::XCEngine::Components::GameObject* gameObject, const std::string& filter) {
|
|
|
|
|
if (!gameObject) return;
|
2026-03-20 17:08:06 +08:00
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (!filter.empty() && !PassesFilter(gameObject, filter)) {
|
2026-03-20 17:08:06 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
ImGui::PushID(static_cast<int>(gameObject->GetID()));
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (gameObject->GetChildCount() == 0) {
|
2026-03-20 17:08:06 +08:00
|
|
|
flags |= ImGuiTreeNodeFlags_Leaf;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (SelectionManager::Get().IsSelected(gameObject)) {
|
2026-03-20 17:08:06 +08:00
|
|
|
flags |= ImGuiTreeNodeFlags_Selected;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (m_renaming && m_renamingEntity == gameObject) {
|
2026-03-20 17:08:06 +08:00
|
|
|
if (m_renameJustStarted) {
|
|
|
|
|
ImGui::SetKeyboardFocusHere();
|
|
|
|
|
m_renameJustStarted = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::SetNextItemWidth(-1);
|
|
|
|
|
if (ImGui::InputText("##Rename", m_renameBuffer, sizeof(m_renameBuffer), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
|
|
|
|
if (strlen(m_renameBuffer) > 0) {
|
2026-03-25 01:23:08 +08:00
|
|
|
EditorSceneManager::Get().RenameEntity(gameObject->GetID(), m_renameBuffer);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
m_renaming = false;
|
2026-03-24 18:38:01 +08:00
|
|
|
m_renamingEntity = nullptr;
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) {
|
|
|
|
|
if (strlen(m_renameBuffer) > 0) {
|
2026-03-25 01:23:08 +08:00
|
|
|
EditorSceneManager::Get().RenameEntity(gameObject->GetID(), m_renameBuffer);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
m_renaming = false;
|
2026-03-24 18:38:01 +08:00
|
|
|
m_renamingEntity = nullptr;
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
} else {
|
2026-03-25 01:23:08 +08:00
|
|
|
bool isOpen = ImGui::TreeNodeEx((void*)gameObject->GetUUID(), flags, "%s", gameObject->GetName().c_str());
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
|
2026-03-25 01:23:08 +08:00
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
|
if (io.KeyCtrl) {
|
|
|
|
|
if (!SelectionManager::Get().IsSelected(gameObject)) {
|
|
|
|
|
SelectionManager::Get().AddToSelection(gameObject);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
SelectionManager::Get().SetSelectedEntity(gameObject);
|
|
|
|
|
}
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
|
|
|
|
m_renaming = true;
|
2026-03-25 01:23:08 +08:00
|
|
|
m_renamingEntity = gameObject;
|
|
|
|
|
strcpy_s(m_renameBuffer, gameObject->GetName().c_str());
|
2026-03-20 17:08:06 +08:00
|
|
|
m_renameJustStarted = true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
HandleDragDrop(gameObject);
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
if (ImGui::BeginPopupContextItem("EntityContextMenu")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
RenderContextMenu(gameObject);
|
2026-03-20 17:08:06 +08:00
|
|
|
ImGui::EndPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isOpen) {
|
2026-03-25 01:23:08 +08:00
|
|
|
for (size_t i = 0; i < gameObject->GetChildCount(); i++) {
|
|
|
|
|
RenderEntity(gameObject->GetChild(i), filter);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
ImGui::TreePop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::PopID();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
void HierarchyPanel::RenderContextMenu(::XCEngine::Components::GameObject* gameObject) {
|
2026-03-24 20:02:38 +08:00
|
|
|
auto& sceneManager = EditorSceneManager::Get();
|
2026-03-20 17:08:06 +08:00
|
|
|
auto& selectionManager = SelectionManager::Get();
|
|
|
|
|
|
|
|
|
|
if (ImGui::BeginMenu("Create")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
RenderCreateMenu(gameObject);
|
2026-03-20 17:08:06 +08:00
|
|
|
ImGui::EndMenu();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (gameObject != nullptr && ImGui::MenuItem("Create Child")) {
|
|
|
|
|
auto* child = sceneManager.CreateEntity("GameObject", gameObject);
|
|
|
|
|
selectionManager.SetSelectedEntity(child);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:08:06 +08:00
|
|
|
ImGui::Separator();
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (gameObject != nullptr && gameObject->GetParent() != nullptr) {
|
|
|
|
|
if (ImGui::MenuItem("Detach from Parent")) {
|
|
|
|
|
gameObject->DetachFromParent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:08:06 +08:00
|
|
|
if (ImGui::MenuItem("Rename", "F2")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
if (gameObject) {
|
2026-03-20 17:08:06 +08:00
|
|
|
m_renaming = true;
|
2026-03-25 01:23:08 +08:00
|
|
|
m_renamingEntity = gameObject;
|
|
|
|
|
strcpy_s(m_renameBuffer, gameObject->GetName().c_str());
|
2026-03-20 17:08:06 +08:00
|
|
|
m_renameJustStarted = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Delete", "Delete")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
sceneManager.DeleteEntity(gameObject->GetID());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Copy", "Ctrl+C")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
sceneManager.CopyEntity(gameObject->GetID());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Paste", "Ctrl+V", false, sceneManager.HasClipboardData())) {
|
2026-03-25 01:23:08 +08:00
|
|
|
sceneManager.PasteEntity(gameObject->GetID());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Duplicate", "Ctrl+D")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
uint64_t newId = sceneManager.DuplicateEntity(gameObject->GetID());
|
2026-03-24 18:38:01 +08:00
|
|
|
if (newId != 0) {
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 20:02:38 +08:00
|
|
|
void HierarchyPanel::RenderCreateMenu(::XCEngine::Components::GameObject* parent) {
|
|
|
|
|
auto& sceneManager = EditorSceneManager::Get();
|
2026-03-20 17:08:06 +08:00
|
|
|
auto& selectionManager = SelectionManager::Get();
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Empty Object")) {
|
2026-03-24 18:38:01 +08:00
|
|
|
auto* newEntity = sceneManager.CreateEntity("GameObject", parent);
|
|
|
|
|
selectionManager.SetSelectedEntity(newEntity);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Camera")) {
|
2026-03-24 18:38:01 +08:00
|
|
|
auto* newEntity = sceneManager.CreateEntity("Camera", parent);
|
2026-03-24 20:02:38 +08:00
|
|
|
newEntity->AddComponent<::XCEngine::Components::TransformComponent>();
|
2026-03-24 18:38:01 +08:00
|
|
|
selectionManager.SetSelectedEntity(newEntity);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Light")) {
|
2026-03-24 18:38:01 +08:00
|
|
|
auto* newEntity = sceneManager.CreateEntity("Light", parent);
|
|
|
|
|
selectionManager.SetSelectedEntity(newEntity);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Cube")) {
|
2026-03-24 18:38:01 +08:00
|
|
|
auto* newEntity = sceneManager.CreateEntity("Cube", parent);
|
2026-03-24 20:02:38 +08:00
|
|
|
newEntity->AddComponent<::XCEngine::Components::TransformComponent>();
|
2026-03-24 18:38:01 +08:00
|
|
|
selectionManager.SetSelectedEntity(newEntity);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Sphere")) {
|
2026-03-24 18:38:01 +08:00
|
|
|
auto* newEntity = sceneManager.CreateEntity("Sphere", parent);
|
2026-03-24 20:02:38 +08:00
|
|
|
newEntity->AddComponent<::XCEngine::Components::TransformComponent>();
|
2026-03-24 18:38:01 +08:00
|
|
|
selectionManager.SetSelectedEntity(newEntity);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::MenuItem("Plane")) {
|
2026-03-24 18:38:01 +08:00
|
|
|
auto* newEntity = sceneManager.CreateEntity("Plane", parent);
|
2026-03-24 20:02:38 +08:00
|
|
|
newEntity->AddComponent<::XCEngine::Components::TransformComponent>();
|
2026-03-24 18:38:01 +08:00
|
|
|
selectionManager.SetSelectedEntity(newEntity);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
void HierarchyPanel::HandleDragDrop(::XCEngine::Components::GameObject* gameObject) {
|
2026-03-24 20:02:38 +08:00
|
|
|
auto& sceneManager = EditorSceneManager::Get();
|
|
|
|
|
|
2026-03-20 17:08:06 +08:00
|
|
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
2026-03-25 01:23:08 +08:00
|
|
|
ImGui::SetDragDropPayload("ENTITY_PTR", &gameObject, sizeof(::XCEngine::Components::GameObject*));
|
|
|
|
|
ImGui::Text("%s", gameObject->GetName().c_str());
|
2026-03-20 17:08:06 +08:00
|
|
|
ImGui::EndDragDropSource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::BeginDragDropTarget()) {
|
2026-03-24 18:38:01 +08:00
|
|
|
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_PTR")) {
|
2026-03-25 01:23:08 +08:00
|
|
|
::XCEngine::Components::GameObject* sourceGameObject = *(::XCEngine::Components::GameObject**)payload->Data;
|
|
|
|
|
if (sourceGameObject != gameObject && sourceGameObject != nullptr) {
|
2026-03-20 17:08:06 +08:00
|
|
|
bool isValidMove = true;
|
2026-03-25 01:23:08 +08:00
|
|
|
::XCEngine::Components::GameObject* checkParent = gameObject;
|
2026-03-24 18:38:01 +08:00
|
|
|
while (checkParent != nullptr) {
|
2026-03-25 01:23:08 +08:00
|
|
|
if (checkParent == sourceGameObject) {
|
2026-03-20 17:08:06 +08:00
|
|
|
isValidMove = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-03-24 18:38:01 +08:00
|
|
|
checkParent = checkParent->GetParent();
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-24 18:38:01 +08:00
|
|
|
if (isValidMove) {
|
2026-03-25 01:23:08 +08:00
|
|
|
auto* srcTransform = sourceGameObject->GetTransform();
|
|
|
|
|
Math::Vector3 worldPos = srcTransform->GetPosition();
|
|
|
|
|
Math::Quaternion worldRot = srcTransform->GetRotation();
|
|
|
|
|
Math::Vector3 worldScale = srcTransform->GetScale();
|
|
|
|
|
|
|
|
|
|
sceneManager.MoveEntity(sourceGameObject->GetID(), gameObject->GetID());
|
|
|
|
|
|
|
|
|
|
srcTransform->SetPosition(worldPos);
|
|
|
|
|
srcTransform->SetRotation(worldRot);
|
|
|
|
|
srcTransform->SetScale(worldScale);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ImGui::EndDragDropTarget();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HierarchyPanel::HandleKeyboardShortcuts() {
|
2026-03-24 20:02:38 +08:00
|
|
|
auto& sceneManager = EditorSceneManager::Get();
|
2026-03-20 17:08:06 +08:00
|
|
|
auto& selectionManager = SelectionManager::Get();
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
::XCEngine::Components::GameObject* selectedGameObject = selectionManager.GetSelectedEntity();
|
2026-03-20 17:08:06 +08:00
|
|
|
|
|
|
|
|
if (ImGui::IsWindowFocused()) {
|
|
|
|
|
if (ImGui::IsKeyPressed(ImGuiKey_Delete)) {
|
2026-03-25 01:23:08 +08:00
|
|
|
if (selectedGameObject != nullptr) {
|
|
|
|
|
sceneManager.DeleteEntity(selectedGameObject->GetID());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsKeyPressed(ImGuiKey_F2)) {
|
2026-03-25 01:23:08 +08:00
|
|
|
if (selectedGameObject != nullptr) {
|
2026-03-24 18:38:01 +08:00
|
|
|
m_renaming = true;
|
2026-03-25 01:23:08 +08:00
|
|
|
m_renamingEntity = selectedGameObject;
|
|
|
|
|
strcpy_s(m_renameBuffer, selectedGameObject->GetName().c_str());
|
2026-03-24 18:38:01 +08:00
|
|
|
m_renameJustStarted = true;
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
|
if (io.KeyCtrl) {
|
|
|
|
|
if (ImGui::IsKeyPressed(ImGuiKey_C)) {
|
2026-03-25 01:23:08 +08:00
|
|
|
if (selectedGameObject != nullptr) {
|
|
|
|
|
sceneManager.CopyEntity(selectedGameObject->GetID());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsKeyPressed(ImGuiKey_V)) {
|
|
|
|
|
if (sceneManager.HasClipboardData()) {
|
2026-03-25 01:23:08 +08:00
|
|
|
sceneManager.PasteEntity(selectedGameObject ? selectedGameObject->GetID() : 0);
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
|
2026-03-25 01:23:08 +08:00
|
|
|
if (selectedGameObject != nullptr) {
|
|
|
|
|
sceneManager.DuplicateEntity(selectedGameObject->GetID());
|
2026-03-20 17:08:06 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
bool HierarchyPanel::PassesFilter(::XCEngine::Components::GameObject* gameObject, const std::string& filter) {
|
|
|
|
|
if (!gameObject) return false;
|
2026-03-20 17:08:06 +08:00
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
if (gameObject->GetName().find(filter) != std::string::npos) {
|
2026-03-20 17:08:06 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 01:23:08 +08:00
|
|
|
for (size_t i = 0; i < gameObject->GetChildCount(); i++) {
|
|
|
|
|
if (PassesFilter(gameObject->GetChild(i), filter)) {
|
2026-03-20 17:08:06 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 18:38:01 +08:00
|
|
|
}
|
2026-03-24 20:02:38 +08:00
|
|
|
}
|