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.
121 lines
4.6 KiB
C++
121 lines
4.6 KiB
C++
//
|
||
// 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
|