PIE: viewport-embedded playback with UE-style main toolbar
Play no longer switches to fullscreen direct rendering: PIE now keeps the editor UI alive and renders the primary camera into the Viewport panel (new SceneRenderer::SetGameView flag; kDisplayDirect stays a manual fullscreen preview for later release form). Editor camera stops being driven during PIE, and viewport click-pick is gated off while playing (clicks are game input now). The Play/Stop buttons move out of the menu bar into a dedicated main toolbar row below it (centered, UE Main Toolbar semantics): green Play when idle; Pause (yellow, highlighted while paused) + Stop (orange) while playing. Ctrl+P hotkey kept. Stats "Pause Simulation" merged into the toolbar Pause; viewport overlay shows PAUSED accordingly.
This commit is contained in:
+111
-40
@@ -40,8 +40,9 @@ Editor::~Editor() = default;
|
||||
void Editor::Init(const EditorContext& ctx)
|
||||
{
|
||||
m_Ctx = ctx;
|
||||
// PIE 运行态指针:指向本对象成员(ctx 拷贝后补接,面板只读)
|
||||
// PIE 运行/暂停态指针:指向本对象成员(ctx 拷贝后补接,面板只读)
|
||||
m_Ctx.playState = &m_Playing;
|
||||
m_Ctx.pausedState = &m_Paused;
|
||||
|
||||
m_Hierarchy = std::make_unique<HierarchyPanel>();
|
||||
m_Inspector = std::make_unique<InspectorPanel>();
|
||||
@@ -78,7 +79,9 @@ void Editor::Init(const EditorContext& ctx)
|
||||
|
||||
// ---- PIE(Play-In-Editor)----
|
||||
|
||||
// Play:当前场景 → 内存 YAML 快照 → 切游戏渲染(primary 相机实体)
|
||||
// Play:当前场景 → 内存 YAML 快照 → 切 gameView(Viewport 面板内嵌
|
||||
// primary 相机渲染,UE PIE 语义——编辑器 UI 保持可用,不切全屏;
|
||||
// kDisplayDirect 全屏预览是后期发布形态,手动经 Stats 切换)
|
||||
// → 解冻时间(物理/脚本/动画开始跑)。快照失败不进 Play(现场不动)
|
||||
void Editor::DoPlay()
|
||||
{
|
||||
@@ -93,7 +96,9 @@ void Editor::DoPlay()
|
||||
}
|
||||
|
||||
m_Playing = true;
|
||||
m_Ctx.renderer->SetDisplayMode(kDisplayDirect);
|
||||
m_Paused = false;
|
||||
m_Gizmo.dragging = false; // 编辑态拖杆中点 Play:杆运行态不出,复位
|
||||
m_Ctx.renderer->SetGameView(true);
|
||||
Time::SetTimeScale(1.0f);
|
||||
ENGINE_INFO("PIE: playing (scene snapshot {} bytes)",
|
||||
m_PlaySnapshot.size());
|
||||
@@ -117,7 +122,8 @@ void Editor::DoStop()
|
||||
m_PlaySnapshot.clear();
|
||||
|
||||
m_Playing = false;
|
||||
m_Ctx.renderer->SetDisplayMode(kDisplayViewport);
|
||||
m_Paused = false;
|
||||
m_Ctx.renderer->SetGameView(false);
|
||||
Time::SetTimeScale(0.0f);
|
||||
SelectEntity(entt::null);
|
||||
m_Gizmo.dragging = false;
|
||||
@@ -129,6 +135,14 @@ void Editor::TogglePlay()
|
||||
m_Playing ? DoStop() : DoPlay();
|
||||
}
|
||||
|
||||
// PIE 暂停(UE Pause 语义):timeScale 0 ↔ 1。运行态才有意义
|
||||
//(编辑器态本来就冻结,Pause 按钮不出现)
|
||||
void Editor::TogglePause()
|
||||
{
|
||||
m_Paused = !m_Paused;
|
||||
Time::SetTimeScale(m_Paused ? 0.0f : 1.0f);
|
||||
}
|
||||
|
||||
void Editor::Draw()
|
||||
{
|
||||
// ImGuizmo 每帧首调(官方约定):内部会清 mbOverGizmoHotspot 等
|
||||
@@ -154,6 +168,7 @@ void Editor::Draw()
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
DrawMenuBar();
|
||||
DrawToolbar();
|
||||
DrawDockSpace();
|
||||
|
||||
ImGui::End();
|
||||
@@ -227,42 +242,6 @@ void Editor::DrawMenuBar()
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- PIE 工具栏(UE 主工具栏语义):Play/Stop 切换按钮 +
|
||||
// Ctrl+P 全局热键。运行态按钮变 Stop(黄底提示在视口内)----
|
||||
{
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
// Ctrl+P:文本输入中(改名/路径框)不触发,防打字误切 PIE
|
||||
if (!m_Playing && io.KeyCtrl && !io.WantTextInput &&
|
||||
ImGui::IsKeyPressed(ImGuiKey_P, false))
|
||||
{
|
||||
TogglePlay();
|
||||
}
|
||||
|
||||
if (m_Playing)
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
ImVec4(0.75f, 0.45f, 0.10f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
ImVec4(0.85f, 0.55f, 0.15f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||
ImVec4(0.90f, 0.62f, 0.20f, 1.0f));
|
||||
if (ImGui::SmallButton("Stop (Ctrl+P)"))
|
||||
{
|
||||
TogglePlay();
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.72f, 0.25f, 1.0f),
|
||||
"PLAYING - editor input disabled");
|
||||
}
|
||||
else if (ImGui::SmallButton("Play (Ctrl+P)"))
|
||||
{
|
||||
TogglePlay();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("File"))
|
||||
{
|
||||
// 运行态禁存取:Save 会把"玩出来的状态"当编辑结果落盘,
|
||||
@@ -298,6 +277,98 @@ void Editor::DrawMenuBar()
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
// 主工具栏(UE Main Toolbar 语义):菜单栏下方独立一行,Play 组水平
|
||||
// 居中。编辑态 = [Play](绿);PIE 运行态 = [Pause][Stop](暂停高亮黄 /
|
||||
// 停止橙红)。kDisplayDirect 全屏预览是发布形态预览,不在此处
|
||||
void Editor::DrawToolbar()
|
||||
{
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
// Ctrl+P:文本输入中(改名/路径框)不触发,防打字误切 PIE
|
||||
if (!m_Playing && io.KeyCtrl && !io.WantTextInput &&
|
||||
ImGui::IsKeyPressed(ImGuiKey_P, false))
|
||||
{
|
||||
TogglePlay();
|
||||
}
|
||||
|
||||
// 按钮加大触感(工具栏行高 = 一个按钮高;DockSpace avail 自适应)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 4.0f));
|
||||
const ImGuiStyle& st = ImGui::GetStyle();
|
||||
|
||||
// Play 组宽度 → 水平居中(编辑态 1 钮 / 运行态 2 钮)
|
||||
float groupW = 0.0f;
|
||||
if (m_Playing)
|
||||
{
|
||||
groupW = ImGui::CalcTextSize("Pause").x + ImGui::CalcTextSize("Stop").x +
|
||||
4.0f * st.FramePadding.x + st.ItemSpacing.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
groupW = ImGui::CalcTextSize("Play").x + 2.0f * st.FramePadding.x;
|
||||
}
|
||||
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - groupW) * 0.5f);
|
||||
|
||||
if (m_Playing)
|
||||
{
|
||||
// Pause:暂停中亮黄常驻(UE 按下态),运行中暗黄
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
m_Paused ? ImVec4(0.85f, 0.62f, 0.12f, 1.0f)
|
||||
: ImVec4(0.55f, 0.42f, 0.10f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
m_Paused ? ImVec4(0.92f, 0.70f, 0.18f, 1.0f)
|
||||
: ImVec4(0.65f, 0.50f, 0.14f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||
ImVec4(0.95f, 0.76f, 0.24f, 1.0f));
|
||||
if (ImGui::Button("Pause"))
|
||||
{
|
||||
TogglePause();
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip(m_Paused ? "Resume simulation"
|
||||
: "Pause simulation");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
// Stop:橙红(沿用视口 PLAYING 提示色系)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
ImVec4(0.75f, 0.45f, 0.10f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
ImVec4(0.85f, 0.55f, 0.15f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||
ImVec4(0.90f, 0.62f, 0.20f, 1.0f));
|
||||
if (ImGui::Button("Stop"))
|
||||
{
|
||||
TogglePlay();
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Stop and restore editor scene (Ctrl+P)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play:绿(UE Play 按钮语义)
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
ImVec4(0.22f, 0.48f, 0.26f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||
ImVec4(0.28f, 0.58f, 0.32f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||
ImVec4(0.34f, 0.66f, 0.38f, 1.0f));
|
||||
if (ImGui::Button("Play"))
|
||||
{
|
||||
TogglePlay();
|
||||
}
|
||||
ImGui::PopStyleColor(3);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Play in editor (Ctrl+P)");
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
void Editor::DrawDockSpace()
|
||||
{
|
||||
const ImGuiID dockspaceId = ImGui::GetID("EditorDockSpace");
|
||||
|
||||
Reference in New Issue
Block a user