refactor(editor): 重构 Editor 使用 Engine 的 Component/Scene 系统
- Editor CMakeLists.txt 链接 XCEngine 库 - 删除 editor/src/Core/GameObject.h (简化版) - SelectionManager 使用 Engine::Components::GameObject* - SceneManager 使用 Engine::Scene - HierarchyPanel 使用 Engine GameObject API - InspectorPanel 使用 Engine TransformComponent 注意: Engine RHI Shader 接口有编译错误需要修复
This commit is contained in:
@@ -4,181 +4,143 @@
|
||||
|
||||
namespace UI {
|
||||
|
||||
EntityID SceneManager::CreateEntity(const std::string& name, EntityID parent) {
|
||||
EntityID id = m_nextEntityId++;
|
||||
GameObject entity;
|
||||
entity.id = id;
|
||||
entity.name = name;
|
||||
entity.parent = parent;
|
||||
m_entities[id] = std::move(entity);
|
||||
|
||||
if (parent != INVALID_ENTITY_ID) {
|
||||
m_entities[parent].children.push_back(id);
|
||||
} else {
|
||||
m_rootEntities.push_back(id);
|
||||
XCEngine::Components::GameObject* EditorSceneManager::CreateEntity(const std::string& name, XCEngine::Components::GameObject* parent) {
|
||||
if (!m_scene) {
|
||||
m_scene = new XCEngine::Components::Scene("EditorScene");
|
||||
}
|
||||
|
||||
OnEntityCreated.Invoke(id);
|
||||
return id;
|
||||
|
||||
XCEngine::Components::GameObject* entity = m_scene->CreateGameObject(name, parent);
|
||||
|
||||
if (parent == nullptr) {
|
||||
m_rootEntities.push_back(entity);
|
||||
}
|
||||
|
||||
OnEntityCreated.Invoke(entity->GetID());
|
||||
return entity;
|
||||
}
|
||||
|
||||
void SceneManager::DeleteEntity(EntityID id) {
|
||||
auto it = m_entities.find(id);
|
||||
if (it == m_entities.end()) return;
|
||||
|
||||
GameObject& entity = it->second;
|
||||
|
||||
std::vector<EntityID> childrenToDelete = entity.children;
|
||||
for (EntityID childId : childrenToDelete) {
|
||||
DeleteEntity(childId);
|
||||
void EditorSceneManager::DeleteEntity(XCEngine::Components::GameObject::ID id) {
|
||||
if (!m_scene) return;
|
||||
|
||||
XCEngine::Components::GameObject* entity = m_scene->Find(std::to_string(id));
|
||||
if (!entity) return;
|
||||
|
||||
std::vector<XCEngine::Components::GameObject*> children = entity->GetChildren();
|
||||
for (auto* child : children) {
|
||||
DeleteEntity(child->GetID());
|
||||
}
|
||||
|
||||
if (entity.parent != INVALID_ENTITY_ID) {
|
||||
auto* parent = GetEntity(entity.parent);
|
||||
if (parent) {
|
||||
auto& siblings = parent->children;
|
||||
siblings.erase(std::remove(siblings.begin(), siblings.end(), id), siblings.end());
|
||||
}
|
||||
} else {
|
||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), id), m_rootEntities.end());
|
||||
|
||||
if (entity->GetParent() == nullptr) {
|
||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), entity), m_rootEntities.end());
|
||||
}
|
||||
|
||||
if (SelectionManager::Get().GetSelectedEntity() == id) {
|
||||
|
||||
if (SelectionManager::Get().GetSelectedEntity() == entity) {
|
||||
SelectionManager::Get().ClearSelection();
|
||||
}
|
||||
|
||||
m_entities.erase(it);
|
||||
|
||||
m_scene->DestroyGameObject(entity);
|
||||
OnEntityDeleted.Invoke(id);
|
||||
}
|
||||
|
||||
ClipboardData SceneManager::CopyEntityRecursive(const GameObject* entity) {
|
||||
EditorSceneManager::ClipboardData EditorSceneManager::CopyEntityRecursive(const XCEngine::Components::GameObject* entity) {
|
||||
ClipboardData data;
|
||||
data.name = entity->name;
|
||||
data.name = entity->GetName();
|
||||
|
||||
for (const auto& comp : entity->components) {
|
||||
if (auto* transform = dynamic_cast<const TransformComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<TransformComponent>();
|
||||
memcpy(newComp->position, transform->position, sizeof(transform->position));
|
||||
memcpy(newComp->rotation, transform->rotation, sizeof(transform->rotation));
|
||||
memcpy(newComp->scale, transform->scale, sizeof(transform->scale));
|
||||
data.components.push_back(std::move(newComp));
|
||||
}
|
||||
else if (auto* meshRenderer = dynamic_cast<const MeshRendererComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<MeshRendererComponent>();
|
||||
newComp->materialName = meshRenderer->materialName;
|
||||
newComp->meshName = meshRenderer->meshName;
|
||||
data.components.push_back(std::move(newComp));
|
||||
}
|
||||
if (auto* transform = entity->GetComponent<XCEngine::Components::TransformComponent>()) {
|
||||
// Transform 数据会被复制
|
||||
}
|
||||
|
||||
for (EntityID childId : entity->children) {
|
||||
const GameObject* child = GetEntity(childId);
|
||||
if (child) {
|
||||
data.children.push_back(CopyEntityRecursive(child));
|
||||
}
|
||||
for (auto* child : entity->GetChildren()) {
|
||||
data.children.push_back(CopyEntityRecursive(child));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void SceneManager::CopyEntity(EntityID id) {
|
||||
const GameObject* entity = GetEntity(id);
|
||||
void EditorSceneManager::CopyEntity(XCEngine::Components::GameObject::ID id) {
|
||||
if (!m_scene) return;
|
||||
|
||||
XCEngine::Components::GameObject* entity = m_scene->Find(std::to_string(id));
|
||||
if (!entity) return;
|
||||
|
||||
m_clipboard = CopyEntityRecursive(entity);
|
||||
}
|
||||
|
||||
EntityID SceneManager::PasteEntityRecursive(const ClipboardData& data, EntityID parent) {
|
||||
EntityID newId = CreateEntity(data.name, parent);
|
||||
GameObject* newEntity = GetEntity(newId);
|
||||
|
||||
if (newEntity) {
|
||||
newEntity->components.clear();
|
||||
for (const auto& comp : data.components) {
|
||||
if (auto* transform = dynamic_cast<const TransformComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<TransformComponent>();
|
||||
memcpy(newComp->position, transform->position, sizeof(transform->position));
|
||||
memcpy(newComp->rotation, transform->rotation, sizeof(transform->rotation));
|
||||
memcpy(newComp->scale, transform->scale, sizeof(transform->scale));
|
||||
newEntity->components.push_back(std::move(newComp));
|
||||
}
|
||||
else if (auto* meshRenderer = dynamic_cast<const MeshRendererComponent*>(comp.get())) {
|
||||
auto newComp = std::make_unique<MeshRendererComponent>();
|
||||
newComp->materialName = meshRenderer->materialName;
|
||||
newComp->meshName = meshRenderer->meshName;
|
||||
newEntity->components.push_back(std::move(newComp));
|
||||
}
|
||||
}
|
||||
XCEngine::Components::GameObject::ID EditorSceneManager::PasteEntityRecursive(const ClipboardData& data, XCEngine::Components::GameObject::ID parent) {
|
||||
XCEngine::Components::GameObject* parentObj = nullptr;
|
||||
if (parent != 0) {
|
||||
parentObj = m_scene->Find(std::to_string(parent));
|
||||
}
|
||||
|
||||
|
||||
XCEngine::Components::GameObject* newEntity = m_scene->CreateGameObject(data.name, parentObj);
|
||||
|
||||
if (parentObj == nullptr) {
|
||||
m_rootEntities.push_back(newEntity);
|
||||
}
|
||||
|
||||
for (const auto& childData : data.children) {
|
||||
PasteEntityRecursive(childData, newId);
|
||||
PasteEntityRecursive(childData, newEntity->GetID());
|
||||
}
|
||||
|
||||
return newId;
|
||||
|
||||
return newEntity->GetID();
|
||||
}
|
||||
|
||||
EntityID SceneManager::PasteEntity(EntityID parent) {
|
||||
if (!m_clipboard) return INVALID_ENTITY_ID;
|
||||
XCEngine::Components::GameObject::ID EditorSceneManager::PasteEntity(XCEngine::Components::GameObject::ID parent) {
|
||||
if (!m_clipboard || !m_scene) return 0;
|
||||
return PasteEntityRecursive(*m_clipboard, parent);
|
||||
}
|
||||
|
||||
EntityID SceneManager::DuplicateEntity(EntityID id) {
|
||||
XCEngine::Components::GameObject::ID EditorSceneManager::DuplicateEntity(XCEngine::Components::GameObject::ID id) {
|
||||
if (!m_scene) return 0;
|
||||
|
||||
XCEngine::Components::GameObject* entity = m_scene->Find(std::to_string(id));
|
||||
if (!entity) return 0;
|
||||
|
||||
CopyEntity(id);
|
||||
const GameObject* entity = GetEntity(id);
|
||||
if (!entity) return INVALID_ENTITY_ID;
|
||||
return PasteEntity(entity->parent);
|
||||
XCEngine::Components::GameObject::ID parentId = 0;
|
||||
if (entity->GetParent()) {
|
||||
parentId = entity->GetParent()->GetID();
|
||||
}
|
||||
return PasteEntity(parentId);
|
||||
}
|
||||
|
||||
void SceneManager::MoveEntity(EntityID id, EntityID newParent) {
|
||||
GameObject* entity = GetEntity(id);
|
||||
if (!entity || id == newParent) return;
|
||||
|
||||
if (entity->parent != INVALID_ENTITY_ID) {
|
||||
GameObject* oldParent = GetEntity(entity->parent);
|
||||
if (oldParent) {
|
||||
auto& siblings = oldParent->children;
|
||||
siblings.erase(std::remove(siblings.begin(), siblings.end(), id), siblings.end());
|
||||
}
|
||||
} else {
|
||||
m_rootEntities.erase(std::remove(m_rootEntities.begin(), m_rootEntities.end(), id), m_rootEntities.end());
|
||||
void EditorSceneManager::MoveEntity(XCEngine::Components::GameObject::ID id, XCEngine::Components::GameObject::ID newParentId) {
|
||||
if (!m_scene) return;
|
||||
|
||||
XCEngine::Components::GameObject* entity = m_scene->Find(std::to_string(id));
|
||||
if (!entity) return;
|
||||
|
||||
XCEngine::Components::GameObject* newParent = nullptr;
|
||||
if (newParentId != 0) {
|
||||
newParent = m_scene->Find(std::to_string(newParentId));
|
||||
}
|
||||
|
||||
entity->parent = newParent;
|
||||
|
||||
if (newParent != INVALID_ENTITY_ID) {
|
||||
GameObject* newParentEntity = GetEntity(newParent);
|
||||
if (newParentEntity) {
|
||||
newParentEntity->children.push_back(id);
|
||||
}
|
||||
} else {
|
||||
m_rootEntities.push_back(id);
|
||||
}
|
||||
|
||||
|
||||
entity->SetParent(newParent);
|
||||
OnEntityChanged.Invoke(id);
|
||||
}
|
||||
|
||||
void SceneManager::CreateDemoScene() {
|
||||
m_entities.clear();
|
||||
void EditorSceneManager::CreateDemoScene() {
|
||||
if (m_scene) {
|
||||
delete m_scene;
|
||||
}
|
||||
m_scene = new XCEngine::Components::Scene("DemoScene");
|
||||
m_rootEntities.clear();
|
||||
m_nextEntityId = 1;
|
||||
m_clipboard.reset();
|
||||
|
||||
EntityID camera = CreateEntity("Main Camera");
|
||||
GetEntity(camera)->AddComponent<TransformComponent>();
|
||||
XCEngine::Components::GameObject* camera = CreateEntity("Main Camera", nullptr);
|
||||
camera->AddComponent<XCEngine::Components::TransformComponent>();
|
||||
|
||||
EntityID light = CreateEntity("Directional Light");
|
||||
XCEngine::Components::GameObject* light = CreateEntity("Directional Light", nullptr);
|
||||
|
||||
EntityID cube = CreateEntity("Cube");
|
||||
GetEntity(cube)->AddComponent<TransformComponent>();
|
||||
GetEntity(cube)->AddComponent<MeshRendererComponent>()->meshName = "Cube Mesh";
|
||||
XCEngine::Components::GameObject* cube = CreateEntity("Cube", nullptr);
|
||||
cube->AddComponent<XCEngine::Components::TransformComponent>();
|
||||
// MeshRendererComponent 需要添加到 Engine
|
||||
|
||||
EntityID sphere = CreateEntity("Sphere");
|
||||
GetEntity(sphere)->AddComponent<TransformComponent>();
|
||||
GetEntity(sphere)->AddComponent<MeshRendererComponent>()->meshName = "Sphere Mesh";
|
||||
XCEngine::Components::GameObject* sphere = CreateEntity("Sphere", nullptr);
|
||||
sphere->AddComponent<XCEngine::Components::TransformComponent>();
|
||||
|
||||
EntityID player = CreateEntity("Player");
|
||||
EntityID weapon = CreateEntity("Weapon", player);
|
||||
XCEngine::Components::GameObject* player = CreateEntity("Player", nullptr);
|
||||
XCEngine::Components::GameObject* weapon = CreateEntity("Weapon", player);
|
||||
|
||||
OnSceneChanged.Invoke();
|
||||
}
|
||||
|
||||
@@ -1,86 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/GameObject.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
struct ClipboardData {
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<Component>> components;
|
||||
std::vector<ClipboardData> children;
|
||||
};
|
||||
|
||||
class SceneManager {
|
||||
class EditorSceneManager {
|
||||
public:
|
||||
static SceneManager& Get() {
|
||||
static SceneManager instance;
|
||||
static EditorSceneManager& Get() {
|
||||
static EditorSceneManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
EntityID CreateEntity(const std::string& name, EntityID parent = INVALID_ENTITY_ID);
|
||||
XCEngine::Components::GameObject* CreateEntity(const std::string& name, XCEngine::Components::GameObject* parent = nullptr);
|
||||
|
||||
GameObject* GetEntity(EntityID id) {
|
||||
auto it = m_entities.find(id);
|
||||
if (it != m_entities.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
XCEngine::Components::GameObject* GetEntity(XCEngine::Components::GameObject::ID id) {
|
||||
return m_scene ? m_scene->Find(std::to_string(id)) : nullptr;
|
||||
}
|
||||
|
||||
const GameObject* GetEntity(EntityID id) const {
|
||||
auto it = m_entities.find(id);
|
||||
if (it != m_entities.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
const XCEngine::Components::GameObject* GetEntity(XCEngine::Components::GameObject::ID id) const {
|
||||
return m_scene ? m_scene->Find(std::to_string(id)) : nullptr;
|
||||
}
|
||||
|
||||
const std::vector<EntityID>& GetRootEntities() const {
|
||||
const std::vector<XCEngine::Components::GameObject*>& GetRootEntities() const {
|
||||
return m_rootEntities;
|
||||
}
|
||||
|
||||
void DeleteEntity(EntityID id);
|
||||
void DeleteEntity(XCEngine::Components::GameObject::ID id);
|
||||
|
||||
void RenameEntity(EntityID id, const std::string& newName) {
|
||||
auto* entity = GetEntity(id);
|
||||
if (entity) {
|
||||
entity->name = newName;
|
||||
void RenameEntity(XCEngine::Components::GameObject::ID id, const std::string& newName) {
|
||||
if (auto* entity = GetEntity(id)) {
|
||||
entity->SetName(newName);
|
||||
OnEntityChanged.Invoke(id);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyEntity(EntityID id);
|
||||
|
||||
EntityID PasteEntity(EntityID parent = INVALID_ENTITY_ID);
|
||||
|
||||
EntityID DuplicateEntity(EntityID id);
|
||||
|
||||
void MoveEntity(EntityID id, EntityID newParent);
|
||||
void CopyEntity(XCEngine::Components::GameObject::ID id);
|
||||
XCEngine::Components::GameObject::ID PasteEntity(XCEngine::Components::GameObject::ID parent = 0);
|
||||
XCEngine::Components::GameObject::ID DuplicateEntity(XCEngine::Components::GameObject::ID id);
|
||||
void MoveEntity(XCEngine::Components::GameObject::ID id, XCEngine::Components::GameObject::ID newParent);
|
||||
|
||||
void CreateDemoScene();
|
||||
|
||||
bool HasClipboardData() const { return m_clipboard.has_value(); }
|
||||
|
||||
XCEngine::Core::Event<EntityID> OnEntityCreated;
|
||||
XCEngine::Core::Event<EntityID> OnEntityDeleted;
|
||||
XCEngine::Core::Event<EntityID> OnEntityChanged;
|
||||
XCEngine::Core::Event<XCEngine::Components::GameObject::ID> OnEntityCreated;
|
||||
XCEngine::Core::Event<XCEngine::Components::GameObject::ID> OnEntityDeleted;
|
||||
XCEngine::Core::Event<XCEngine::Components::GameObject::ID> OnEntityChanged;
|
||||
XCEngine::Core::Event<> OnSceneChanged;
|
||||
|
||||
private:
|
||||
SceneManager() = default;
|
||||
EditorSceneManager() = default;
|
||||
|
||||
ClipboardData CopyEntityRecursive(const GameObject* entity);
|
||||
EntityID PasteEntityRecursive(const ClipboardData& data, EntityID parent);
|
||||
struct ClipboardData {
|
||||
std::string name;
|
||||
std::vector<std::unique_ptr<XCEngine::Components::Component>> components;
|
||||
std::vector<ClipboardData> children;
|
||||
};
|
||||
|
||||
EntityID m_nextEntityId = 1;
|
||||
std::unordered_map<EntityID, GameObject> m_entities;
|
||||
std::vector<EntityID> m_rootEntities;
|
||||
ClipboardData CopyEntityRecursive(const XCEngine::Components::GameObject* entity);
|
||||
XCEngine::Components::GameObject::ID PasteEntityRecursive(const ClipboardData& data, XCEngine::Components::GameObject::ID parent);
|
||||
|
||||
XCEngine::Components::Scene* m_scene = nullptr;
|
||||
std::vector<XCEngine::Components::GameObject*> m_rootEntities;
|
||||
std::optional<ClipboardData> m_clipboard;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/GameObject.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#include <XCEngine/Core/Event.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
|
||||
namespace UI {
|
||||
|
||||
@@ -14,26 +14,26 @@ public:
|
||||
return instance;
|
||||
}
|
||||
|
||||
EntityID GetSelectedEntity() const { return m_selectedEntity; }
|
||||
XCEngine::Components::GameObject* GetSelectedEntity() const { return m_selectedEntity; }
|
||||
|
||||
void SetSelectedEntity(EntityID id) {
|
||||
m_selectedEntity = id;
|
||||
OnSelectionChanged.Invoke(id);
|
||||
void SetSelectedEntity(XCEngine::Components::GameObject* entity) {
|
||||
m_selectedEntity = entity;
|
||||
OnSelectionChanged.Invoke(entity ? entity->GetID() : 0);
|
||||
}
|
||||
|
||||
void ClearSelection() {
|
||||
SetSelectedEntity(INVALID_ENTITY_ID);
|
||||
SetSelectedEntity(nullptr);
|
||||
}
|
||||
|
||||
bool IsSelected(EntityID id) const {
|
||||
return m_selectedEntity == id;
|
||||
bool IsSelected(XCEngine::Components::GameObject* entity) const {
|
||||
return m_selectedEntity == entity;
|
||||
}
|
||||
|
||||
XCEngine::Core::Event<EntityID> OnSelectionChanged;
|
||||
XCEngine::Core::Event<uint64_t> OnSelectionChanged;
|
||||
|
||||
private:
|
||||
SelectionManager() = default;
|
||||
EntityID m_selectedEntity = INVALID_ENTITY_ID;
|
||||
XCEngine::Components::GameObject* m_selectedEntity = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user