Files
HelloVulkan/Engine/include/Engine/ECS/Scene.h
T
atdunbg 007d175314 serialization: scene save/load (Unity-style YAML + UE-style GUID registry)
Engine-layer SceneSerializer (yaml-cpp submodule): entities/components
to versioned YAML, atomic clear-and-rebuild on load with per-entity
fault tolerance, missing-field defaults, unknown-component skip and
UUID dedup. Asset references are {Guid, Path} pairs resolved through
the new AssetManager GUID registry (assets/asset_registry.yaml) with
path fallback; procedural:// pseudo-paths rebuild from parameters.
Editor File menu gets Save/Load Scene modals; app re-resolves stale
entity handles via onSceneLoaded callback.
2026-10-03 14:47:02 +08:00

121 lines
4.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// Created by atdunbg on 2026/9/22.
//
// Scene:世界容器 = entt::registry + 场景级设置 + 安全的生命周期封装。
//
// ECS 基于 entt(skypjack/entt,header-only,稀疏集实现):
// - Entity 即 entt::entity(内部自带版本号,悬空句柄由 valid() 拦截)
// - 组件池为稀疏集,O(1) 增删查;view 遍历自动取最小池
//
// 销毁策略:DestroyEntity 只入队,FlushDestroyQueue 在帧尾统一执行,
// 保证遍历过程中组件池结构不变——这是 ECS 正确性的关键约束。
//
#ifndef HELLOVULKAN_SCENE_H
#define HELLOVULKAN_SCENE_H
#include <Engine/Core/Types.h>
#include <Engine/Core/UUID.h>
#include <Engine/ECS/Components.h>
#include <entt/entt.hpp>
#include <string>
#include <vector>
namespace Engine::ECS {
// 实体句柄直接用 entt::entity:
// - 判空用 `e == entt::null`(不要用 Entity{} —— 那是 0 号实体!)
using Entity = entt::entity;
using Registry = entt::registry;
class EntityHandle; // 表皮:e.AddComponent<T>() 风格(见 EntityHandle.h)
class Scene {
public:
Scene() = default;
~Scene() = default;
Scene(const Scene&) = delete;
Scene& operator=(const Scene&) = delete;
// ---- 场景级设置 ----
struct Settings {
glm::vec4 ClearColor = {0.1, 0.1, 0.1, 1.0};
glm::vec4 AmbientColor{0.07f, 0.07f, 0.09f, 0.0f};
bool DrawSkybox = true;
};
Settings& GetSettings() { return m_Settings; }
const Settings& GetSettings() const { return m_Settings; } // 序列化只读
// ---- 实体 ----
// 返回句柄表皮:e.AddComponent<T>() / e.GetComponent<T>() / e.Destroy()
EntityHandle CreateEntity(std::string name = "new entity");
void DestroyEntity(Entity e); // 延迟:帧尾统一销毁
void FlushDestroyQueue(); // 每帧末尾由 Application 调用
// 整场景换血(序列化加载):立即销毁全部实体并清空延迟队列。
// 仅用于"校验通过后的原子替换"——调用方持有的 Entity/EntityHandle
// 全部悬空,必须自行重解析(GetEntityHandle 可从裸 entity 重建)
void Clear();
// 裸 entity → 句柄表皮(EntityHandle 构造私有 + friend Scene;
// 序列化加载后应用层重解析悬空句柄用)。无效 entity 返回空句柄
EntityHandle GetEntityHandle(Entity e);
// 帧循环统一重算脏 transform 的 world 矩阵(UE transform-update
// 阶段模式)——由 Application 在 OnUpdate 之后、渲染之前调用,
// 用户代码永远不需要手动 Compose
void UpdateTransforms();
bool IsAlive(Entity e) const { return m_Registry.valid(e); }
// 按稳定 UUID 查实体(序列化/跨引用场景);找不到返回 entt::null
Entity FindEntityByUUID(UUID uuid);
Registry& GetRegistry() { return m_Registry; }
const Registry& GetRegistry() const { return m_Registry; } // 序列化等只读遍历
// ---- 组件便捷接口(转发 entt)----
template<typename T, typename... Args>
T& AddComponent(Entity e, Args&&... args)
{
return m_Registry.emplace<T>(e, std::forward<Args>(args)...);
}
template<typename T>
T& GetComponent(Entity e) { return m_Registry.get<T>(e); }
template<typename T>
T* TryGetComponent(Entity e) { return m_Registry.try_get<T>(e); }
template<typename T>
bool HasComponent(Entity e) { return m_Registry.all_of<T>(e); }
template<typename T>
void RemoveComponent(Entity e) { m_Registry.remove<T>(e); }
// 遍历拥有全部 Ts 组件的实体:fn(Entity, Ts&...)
// entt view 自动以最小池为主表,复杂度 O(min pool)
// 注意:遍历中禁止结构变更(创建/销毁实体、增删组件)——销毁走延迟队列
template<typename... Ts, typename Fn>
void Each(Fn&& fn) { m_Registry.view<Ts...>().each(std::forward<Fn>(fn)); }
// ---- 常用查询 ----
// 主相机(primary=true,渲染视角来源);无则返回 nullptr。
// outTransform 可选:带出该实体的 TransformComponent
//(相机位姿的单一事实源)
CameraComponent* GetPrimaryCamera(TransformComponent** outTransform = nullptr);
private:
Registry m_Registry;
std::vector<Entity> m_PendingDestroy;
Settings m_Settings;
};
} // namespace Engine::ECS
#endif //HELLOVULKAN_SCENE_H