添加场景在运行时会临时复制一个场景功能,添加克隆实体功能

This commit is contained in:
2025-06-18 20:59:26 +08:00
parent 99782ea11b
commit ea59c82f35
8 changed files with 185 additions and 22 deletions

View File

@ -44,7 +44,7 @@ namespace Hazel
ProjectionType GetProjectionType() const { return m_ProjectionType; }
void SetProjectionType(const ProjectionType type) { m_ProjectionType = type; RecalculateProjection(); }
void SetProjectionType(const ProjectionType type) { m_ProjectionType = type; }
private:
void RecalculateProjection();
private:

View File

@ -7,7 +7,6 @@
#include <Hazel/Renderer/Camera.h>
#include <Hazel/Renderer/ScenceCamera.h>
#include "ScriptableEntity.h"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/ext/matrix_transform.hpp>
@ -15,9 +14,18 @@
#include "glm/glm.hpp"
#include "glm/gtx/quaternion.hpp"
#include <box2d/types.h>
#include <Hazel/Core/UUID.h>
namespace Hazel
{
struct IDComponent
{
UUID ID;
IDComponent() = default;
IDComponent(const UUID& uuid) : ID(uuid) {}
IDComponent(const IDComponent&) = default;
};
struct TransformComponent
{
@ -77,6 +85,8 @@ namespace Hazel
CameraComponent(const CameraComponent&) = default;
};
// forward declaration
class ScriptableEntity;
struct NativeScriptComponent
{
ScriptableEntity* Instance = nullptr;

View File

@ -5,8 +5,9 @@
#ifndef ENTITY_H
#define ENTITY_H
#include <Hazel/Core/Log.h>
#include <Hazel/Core/UUID.h>
#include "Scene.h"
#include "Components.h"
@ -33,6 +34,14 @@ namespace Hazel
return component;
}
template<typename T, typename... Args>
T& AddOrRelpaceComponent(Args&&... args)
{
T& component = m_Scene->m_Registry.emplace_or_replace<T>(m_EntityHandle, std::forward<Args>(args)...);
m_Scene->OnComponentAdded<T>(*this, component);
return component;
}
template<typename T>
T& GetComponent()
{
@ -73,6 +82,9 @@ namespace Hazel
bool operator==(const Entity& other) const { return m_EntityHandle == other.m_EntityHandle && m_Scene == other.m_Scene; }
bool operator!=(const Entity& other) const { return !(*this==other); }
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
const std::string& GetName() { return GetComponent<TagComponent>().Tag; }
private:
entt::entity m_EntityHandle{ entt::null };
Scene* m_Scene = nullptr;

View File

@ -4,9 +4,11 @@
#include "Scene.h"
#include <spirv_common.hpp>
#include <Hazel/Renderer/Renderer2D.h>
#include "Components.h"
#include "ScriptableEntity.h"
#include "Entity.h"
#include "../../../vendor/box2d/src/physics_world.h"
@ -37,13 +39,79 @@ namespace Hazel
{
}
template<typename Component>
static void CopyComponent(entt::registry& dst, entt::registry& src, const std::unordered_map<UUID, entt::entity>& enttMap)
{
auto view = src.view<Component>();
for (auto e : view)
{
UUID uuid = src.get<IDComponent>(e).ID;
if (enttMap.find(uuid) == enttMap.end())
{
HZ_CORE_ERROR("ERROR");
assert(-1);
}
entt::entity entity = enttMap.at(uuid);
auto& component = view.get<Component>(e);
dst.emplace_or_replace<Component>(entity, component);
}
}
template<typename Component>
static void CopyComponentIfExists(Entity dst, Entity src)
{
if (src.HasComponent<Component>())
dst.AddOrRelpaceComponent<Component>(src.GetComponent<Component>());
}
Ref<Scene> Scene::Copy(Ref<Scene> other)
{
Ref<Scene> newScene = CreateRef<Scene>();
newScene->m_ViewportWidth = other->m_ViewportWidth;
newScene->m_ViewportHeight = other->m_ViewportHeight;
std::unordered_map<UUID, entt::entity> enttMap;
auto& srcSceneRegistry = other->m_Registry;
auto& dstSceneRegistry = newScene->m_Registry;
// Create entity in new Secne
auto idView = srcSceneRegistry.view<IDComponent>();
for (auto e : idView)
{
UUID uuid = srcSceneRegistry.get<IDComponent>(e).ID;
const auto& name = srcSceneRegistry.get<TagComponent>(e).Tag;
Entity newEntity = newScene->CreateEntityWithUUID(uuid, name);
enttMap[uuid] = (entt::entity)newEntity;
}
CopyComponent<TransformComponent>(dstSceneRegistry, srcSceneRegistry, enttMap);
CopyComponent<SpriteRendererComponent>(dstSceneRegistry, srcSceneRegistry, enttMap);
CopyComponent<CameraComponent>(dstSceneRegistry, srcSceneRegistry, enttMap);
CopyComponent<NativeScriptComponent>(dstSceneRegistry, srcSceneRegistry, enttMap);
CopyComponent<RigidBody2DComponent>(dstSceneRegistry, srcSceneRegistry, enttMap);
CopyComponent<BoxCollider2DComponent>(dstSceneRegistry, srcSceneRegistry, enttMap);
return newScene;
}
Entity Scene::CreateEntity(const std::string& name)
{
return CreateEntityWithUUID(UUID(), name);
}
Entity Scene::CreateEntityWithUUID(UUID uuid, const std::string& name)
{
Entity entity = {m_Registry.create(), this};
entity.AddComponent<IDComponent>(uuid);
entity.AddComponent<TransformComponent>();
entity.AddComponent<TagComponent>(name.empty() ? "Entity" : name);
return entity;
}
void Scene::DestoryEntity(const Entity entity)
@ -217,6 +285,18 @@ namespace Hazel
}
void Scene::DuplicateEntity(Entity entity)
{
Entity newEntity = CreateEntity(entity.GetName() + " copy");
CopyComponentIfExists<TransformComponent>(newEntity, entity);
CopyComponentIfExists<SpriteRendererComponent>(newEntity, entity);
CopyComponentIfExists<CameraComponent>(newEntity, entity);
CopyComponentIfExists<NativeScriptComponent>(newEntity, entity);
CopyComponentIfExists<RigidBody2DComponent>(newEntity, entity);
CopyComponentIfExists<BoxCollider2DComponent>(newEntity, entity);
}
Entity Scene::GetPrimaryCameraEntity()
{
auto view = m_Registry.view<CameraComponent>();
@ -232,9 +312,13 @@ namespace Hazel
template <typename T>
void Scene::OnComponentAdded(Entity entity, T& component)
{
static_assert(false);
}
template<>
void Scene::OnComponentAdded<IDComponent>(Entity entity, IDComponent& component)
{
}
template<>
void Scene::OnComponentAdded<TransformComponent>(Entity entity, TransformComponent& component)
{
@ -243,7 +327,8 @@ namespace Hazel
template<>
void Scene::OnComponentAdded<CameraComponent>(Entity entity, CameraComponent& component)
{
component.Camera.SetViewPortSize(m_ViewportWidth, m_ViewportHeight);
if (m_ViewportWidth > 0 && m_ViewportHeight > 0)
component.Camera.SetViewPortSize(m_ViewportWidth, m_ViewportHeight);
}
template<>
@ -272,6 +357,7 @@ namespace Hazel
}
template HAZEL_API void Scene::OnComponentAdded<IDComponent>(Entity, IDComponent&);
template HAZEL_API void Scene::OnComponentAdded<TransformComponent>(Entity, TransformComponent&);
template HAZEL_API void Scene::OnComponentAdded<CameraComponent>(Entity, CameraComponent&);
template HAZEL_API void Scene::OnComponentAdded<TagComponent>(Entity, TagComponent&);

View File

@ -8,6 +8,7 @@
#include <box2d/id.h>
#include <Hazel/Core/TimeStep.h>
#include <Hazel/Core/UUID.h>
#include <Hazel/Renderer/EditorCamera.h>
#include "entt.hpp"
@ -23,7 +24,10 @@ namespace Hazel
Scene();
~Scene();
Entity CreateEntity(const std::string& name = "");
static Ref<Scene> Copy(Ref<Scene> other);
Entity CreateEntity(const std::string& name = std::string());
Entity CreateEntityWithUUID(UUID uuid, const std::string& name = std::string());
void DestoryEntity(Entity entity);
@ -34,6 +38,8 @@ namespace Hazel
void OnUpdateEditor(TimeStep& ts, const EditorCamera& camera);
void OnViewportResize(uint32_t width, uint32_t height);
void DuplicateEntity(Entity entity);
Entity GetPrimaryCameraEntity();
private:

View File

@ -139,8 +139,14 @@ namespace Hazel
static void SerializeEntity(YAML::Emitter& out, Entity entity)
{
if (!entity.HasComponent<IDComponent>())
{
HZ_CORE_ERROR("Entity Could not find UUID!");
assert(-1);
}
out << YAML::BeginMap; // entity
out << YAML::Key << "Entity" << YAML::Value << "123479283"; // TODO: entity ID goes here
out << YAML::Key << "Entity" << YAML::Value << entity.GetUUID();
if (entity.HasComponent<TagComponent>())
{
@ -280,7 +286,7 @@ namespace Hazel
{
for (auto entity : entities)
{
uint64_t uuid = entity["Entity"].as<uint64_t>(); // TODO
uint64_t uuid = entity["Entity"].as<uint64_t>();
std::string name;
auto TagComponent = entity["TagComponent"];
@ -289,7 +295,7 @@ namespace Hazel
HZ_CORE_TRACE("Deserializing Entity: {0}:({1})", name, uuid);
Entity deserializedEntity = m_Scene->CreateEntity(name);
Entity deserializedEntity = m_Scene->CreateEntityWithUUID(uuid, name);
auto transformComponent = entity["TransformComponent"];
if (transformComponent)

View File

@ -280,7 +280,8 @@ namespace Hazel
const float windowWidth = ImGui::GetWindowWidth();
const float windowHeight = ImGui::GetWindowHeight();
const ImVec2 windowPos = ImGui::GetWindowPos();
ImVec2 windowPos = ImGui::GetWindowPos();
windowPos.y += m_ViewPortSize.y - windowsSize.y;
ImGuizmo::SetRect(windowPos.x, windowPos.y, windowWidth, windowHeight);
@ -366,12 +367,30 @@ namespace Hazel
void EditorLayer::OpenScene(const std::filesystem::path& scenePath)
{
if (m_SceneState != SceneState::Edit)
OnSceneStop();
Ref<Scene> newScene = CreateRef<Scene>();
SceneSerializer serializer(newScene);
if (serializer.Deserialize(scenePath.string()))
{
m_EditorScene = newScene;
m_EditorScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
m_ActiveScene = m_EditorScene;
m_SceneHierachyPanel.SetContext(m_ActiveScene);
}
/*
m_ActiveScene = CreateRef<Scene>();
m_ActiveScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
m_SceneHierachyPanel.SetContext(m_ActiveScene);
SceneSerializer serializer(m_ActiveScene);
serializer.Deserialize(scenePath.string());
*/
}
void EditorLayer::NewScene()
@ -381,6 +400,34 @@ namespace Hazel
m_SceneHierachyPanel.SetContext(m_ActiveScene);
}
void EditorLayer::OnDuplicateEntity()
{
if (m_SceneState != SceneState::Edit)
return;
Entity selectedEntity = m_SceneHierachyPanel.GetSelectedEntity();
if (selectedEntity)
m_EditorScene->DuplicateEntity(selectedEntity);
}
void EditorLayer::OnScenePlay()
{
m_SceneState = SceneState::Play;
m_ActiveScene = Scene::Copy(m_EditorScene);
m_ActiveScene->OnRuntimeStart();
m_SceneHierachyPanel.SetContext(m_ActiveScene);
}
void EditorLayer::OnSceneStop()
{
m_SceneState = SceneState::Edit;
m_ActiveScene->OnRuntimeStop();
m_ActiveScene = m_EditorScene;
m_SceneHierachyPanel.SetContext(m_ActiveScene);
}
void EditorLayer::ChangeOptMode(unsigned int mode)
{
if (m_ViewportHovered)
@ -401,11 +448,12 @@ namespace Hazel
#define SHORTCUT_NEW (SDL_KMOD_CTRL | SDLK_N)
#define SHORTCUT_OPEN (SDL_KMOD_CTRL | SDLK_O)
#define SHORTCUT_SAVE_ALL (SDL_KMOD_CTRL | SDL_KMOD_SHIFT | SDLK_S)
#define SHORTCUT_CTRL_D (SDL_KMOD_CTRL | SDLK_D)
const auto mod = SDL_GetModState();
const auto ctrl = (mod & SDL_KMOD_CTRL) ? SDL_KMOD_CTRL : 0;
const auto shift = (mod & SDL_KMOD_SHIFT) ? SDL_KMOD_SHIFT : 0;
if (e.key.down && e.key.repeat == 0)
switch (ctrl | shift | e.key.key)
{
case SHORTCUT_EXIT:
@ -420,6 +468,9 @@ namespace Hazel
case SHORTCUT_SAVE_ALL:
SaveScene();
break;
case SHORTCUT_CTRL_D:
OnDuplicateEntity();
break;
// GIZMO
case SDLK_Q:
@ -475,15 +526,4 @@ namespace Hazel
ImGui::End();
}
void EditorLayer::OnScenePlay()
{
m_SceneState = SceneState::Play;
m_ActiveScene->OnRuntimeStart();
}
void EditorLayer::OnSceneStop()
{
m_SceneState = SceneState::Edit;
m_ActiveScene->OnRuntimeStop();
}
}

View File

@ -34,6 +34,8 @@ namespace Hazel
void OpenScene(const std::filesystem::path& scenePath);
void NewScene();
void OnDuplicateEntity();
void ChangeOptMode(unsigned int mode);
private:
@ -44,6 +46,7 @@ namespace Hazel
Ref<Scene> m_ActiveScene;
Ref<Scene> m_EditorScene;
EditorCamera m_EditorCamera;
Entity m_HoveredEntity;