feat: Play-In-Editor (PIE) with in-memory scene snapshot
Editor toolbar gains Play/Stop (Ctrl+P) with UE semantics: - Play: serialize current scene to an in-memory YAML snapshot via new SceneSerializer::SerializeToString, switch display to kDisplayDirect (primary camera entity renders), unfreeze time (timeScale 0 -> 1) - Stop: DeserializeFromString atomically rebuilds the pre-play scene, back to kDisplayViewport (editor camera), refreeze time; selection cleared and gizmo drag reset since all entity handles dangle - SceneSerializer refactored: SerializeDoc/ParseRoot shared by file and memory variants; file Save/Load behavior unchanged - Running state disables gizmo + editor hotkeys in the viewport (input goes to game scripts), draws yellow PLAYING hint and a no-camera warning; File->Save/Load disabled while playing (UE behavior) Physics bodies/constraints/characters and script instances are reconciled automatically by the existing per-frame sync on restore.
This commit is contained in:
@@ -152,7 +152,10 @@ std::optional<entt::entity> ViewportPanel::Draw(const EditorContext &ctx,
|
||||
selected != entt::null
|
||||
? reg.try_get<ECS::TransformComponent>(selected)
|
||||
: nullptr;
|
||||
if (out.focused && !ImGui::GetIO().WantTextInput &&
|
||||
// PIE 运行态:输入归游戏(脚本读 GLFW 轮询),Gizmo/编辑器
|
||||
// 热键全部让位(UE Play 语义:Scene view 编辑操作冻结)
|
||||
const bool playing = ctx.playState && *ctx.playState;
|
||||
if (!playing && out.focused && !ImGui::GetIO().WantTextInput &&
|
||||
!ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_W)) gizmo.op = ImGuizmo::TRANSLATE;
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_E)) gizmo.op = ImGuizmo::ROTATE;
|
||||
@@ -169,7 +172,8 @@ std::optional<entt::entity> ViewportPanel::Draw(const EditorContext &ctx,
|
||||
// ---- Gizmo 操纵杆(ImGui drawlist 叠加,无 GPU pass)----
|
||||
// 选中实体 + 有 Transform 才出杆;矩阵分解直接写回
|
||||
// TransformComponent(与 Inspector 同源,下一帧数值自动跟随)
|
||||
if (tr != nullptr) {
|
||||
// PIE 运行态不出杆(编辑操作冻结)
|
||||
if (tr != nullptr && !playing) {
|
||||
// 相机矩阵:跟随渲染源(编辑器形态 = EditorCamera,游戏
|
||||
// 形态 = primary 相机实体;与 SceneRenderer::BuildFrame
|
||||
// 同一分派),参数与渲染侧一致(aspect = 渲染分辨率、
|
||||
@@ -277,14 +281,23 @@ std::optional<entt::entity> ViewportPanel::Draw(const EditorContext &ctx,
|
||||
}
|
||||
|
||||
// Gizmo 状态提示(左上角 drawlist 叠加,原因同下:不占布局行)
|
||||
// PIE 运行态 = 黄色 PLAYING 提示替代编辑状态
|
||||
{
|
||||
char tip[64];
|
||||
std::snprintf(tip, sizeof(tip), "Space: %s [T] Snap: Ctrl",
|
||||
gizmo.localSpace ? "Local" : "World");
|
||||
if (playing) {
|
||||
std::snprintf(tip, sizeof(tip),
|
||||
"PLAYING - Ctrl+P to stop");
|
||||
} else {
|
||||
std::snprintf(tip, sizeof(tip),
|
||||
"Space: %s [T] Snap: Ctrl",
|
||||
gizmo.localSpace ? "Local" : "World");
|
||||
}
|
||||
const ImVec2 imgMin = ImGui::GetItemRectMin();
|
||||
ImGui::GetWindowDrawList()->AddText(
|
||||
ImVec2(imgMin.x + 8.0f, imgMin.y + 8.0f),
|
||||
IM_COL32(255, 255, 255, 150), tip);
|
||||
playing ? IM_COL32(255, 184, 46, 220)
|
||||
: IM_COL32(255, 255, 255, 150),
|
||||
tip);
|
||||
}
|
||||
|
||||
// Dynamic 刚体提示:物理每帧把姿态写回 Transform,拖拽即刻
|
||||
@@ -292,6 +305,22 @@ std::optional<entt::entity> ViewportPanel::Draw(const EditorContext &ctx,
|
||||
// 用 drawlist 叠加而非 ImGui::TextDisabled:后者在 Image 下方
|
||||
// 占一行布局 → 滚动条出现/消失循环 → avail 抖动 → 渲染分辨率
|
||||
// 每帧重报(视口疯狂顶动);且默认字体无中文字形(显示 ?)
|
||||
if (playing) {
|
||||
// 运行态无 primary 相机实体 = 游戏画面黑屏(BuildFrame
|
||||
// 跳帧),提示补相机(Hierarchy 右键或 Add Component)
|
||||
ECS::TransformComponent *camT = nullptr;
|
||||
if (ViewCamera(ctx, camT) == nullptr) {
|
||||
const ImVec2 imgMin = ImGui::GetItemRectMin();
|
||||
ImGui::GetWindowDrawList()->AddText(
|
||||
ImVec2(imgMin.x + 8.0f,
|
||||
imgMin.y + size.y * 0.5f),
|
||||
IM_COL32(255, 120, 80, 230),
|
||||
"No primary camera entity - add a Camera "
|
||||
"component and check 'Primary'");
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic 刚体提示(drawlist 叠加,理由同上)
|
||||
if (selected != entt::null) {
|
||||
if (const auto *rb = reg.try_get<ECS::RigidBodyComponent>(selected);
|
||||
rb != nullptr &&
|
||||
|
||||
Reference in New Issue
Block a user