diff --git a/Hazel/src/Hazel/Core/EntryPoint.h b/Hazel/src/Hazel/Core/EntryPoint.h index 54316bd..7e7ade8 100644 --- a/Hazel/src/Hazel/Core/EntryPoint.h +++ b/Hazel/src/Hazel/Core/EntryPoint.h @@ -3,6 +3,7 @@ #ifdef HZ_PLATFORM_WINDOWS +#include extern Hazel::Application* Hazel::CreateApplication(); @@ -22,6 +23,8 @@ int main(int, char**) { HZ_PROFILE_BEGIN_SESSION("End", "End.json"); delete app; HZ_PROFILE_END_SESSION(); + + return 0; } #endif // HZ_PLATFORM_WINDOWS diff --git a/Hazel/src/Hazel/Renderer/ScenceCamera.h b/Hazel/src/Hazel/Renderer/ScenceCamera.h index f2616a9..4a52e38 100644 --- a/Hazel/src/Hazel/Renderer/ScenceCamera.h +++ b/Hazel/src/Hazel/Renderer/ScenceCamera.h @@ -44,7 +44,7 @@ namespace Hazel ProjectionType GetProjectionType() const { return m_ProjectionType; } - void SetProjectionType(const ProjectionType type) { m_ProjectionType = type; } + void SetProjectionType(const ProjectionType type) { m_ProjectionType = type; RecalculateProjection(); } private: void RecalculateProjection(); private: diff --git a/Hazel/src/Hazel/Scene/Scene.cpp b/Hazel/src/Hazel/Scene/Scene.cpp index 6233c1a..da1ba10 100644 --- a/Hazel/src/Hazel/Scene/Scene.cpp +++ b/Hazel/src/Hazel/Scene/Scene.cpp @@ -37,6 +37,7 @@ namespace Hazel Scene::~Scene() { + delete m_PhysicsWorld; } template @@ -123,11 +124,12 @@ namespace Hazel - void Scene::OnRuntimeStart() + + void Scene::OnPhysics2DStart() { b2WorldDef worldDef = b2DefaultWorldDef(); worldDef.gravity = b2Vec2(0.0f, -9.81f); - m_PhysicsWorld = b2CreateWorld( &worldDef ); + m_PhysicsWorld = new b2WorldId(b2CreateWorld( &worldDef )); auto view = m_Registry.view(); for (auto e : view) @@ -144,7 +146,7 @@ namespace Hazel // bodyDef.fixedRotation = true; - b2BodyId body = b2CreateBody(m_PhysicsWorld, &bodyDef); + b2BodyId body = b2CreateBody(*m_PhysicsWorld, &bodyDef); rb2D.RuntimeBody = body; if (entity.HasComponent()) @@ -169,8 +171,8 @@ namespace Hazel auto& cc2d = entity.GetComponent(); b2Circle circle; - circle.center.x = cc2d.Offset.x; - circle.center.y = cc2d.Offset.y; + circle.center.x = transform.Scale.x * cc2d.Offset.x; + circle.center.y = transform.Scale.y * cc2d.Offset.y; circle.radius = transform.Scale.x * cc2d.Radius; b2ShapeDef shapedef = b2DefaultShapeDef(); @@ -184,10 +186,58 @@ namespace Hazel } } + void Scene::OnPhysics2DStop() + { + b2DestroyWorld( *m_PhysicsWorld ); + + m_PhysicsWorld = nullptr; + } + + void Scene::RenderScene(const EditorCamera& camera) + { + Renderer2D::BeginScene(camera); + + // Draw Sprites + auto group = m_Registry.group(entt::get); + for (auto entity : group) + { + auto [transform, sprite] = group.get(entity); + + // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); + Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity); + } + + // Draw Circles + auto view = m_Registry.view(); + for (auto entity : view) + { + auto [transform, circle] = view.get(entity); + + // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); + Renderer2D::DrawCircle(transform.GetTransform(), circle.Color, circle.Thickness, circle.Fade, (int)entity); + } + + Renderer2D::EndScene(); + } + + void Scene::OnRuntimeStart() + { + OnPhysics2DStart(); + } + + void Scene::OnSimulationStart() + { + OnPhysics2DStart(); + } + + void Scene::OnSimulationStop() + { + OnPhysics2DStop(); + } + void Scene::OnRuntimeStop() { - - b2DestroyWorld( m_PhysicsWorld ); + OnPhysics2DStop(); } void Scene::OnUpdateRuntime(TimeStep& ts) @@ -212,10 +262,8 @@ namespace Hazel // Physics { - const int32_t velocityIteration = 6; - const int32_t positionIteration = 2; - b2World_Step(m_PhysicsWorld, ts, 4); + b2World_Step(*m_PhysicsWorld, ts, 4); auto view = m_Registry.view(); for (auto e : view) @@ -280,32 +328,38 @@ namespace Hazel } } + void Scene::OnUpdateSimulation(TimeStep& ts, const EditorCamera& camera) + { + // Physics + { + b2World_Step(*m_PhysicsWorld, ts, 4); + + auto view = m_Registry.view(); + for (auto e : view) + { + Entity entity = {e, this}; + auto& transform = entity.GetComponent(); + auto& rb2D = entity.GetComponent(); + + b2BodyId &body = rb2D.RuntimeBody; + + const auto& position = b2Body_GetPosition(body); + transform.Translation.x = position.x; + transform.Translation.y = position.y; + const float angle = b2Rot_GetAngle(b2Body_GetRotation(body)); + transform.Rotation.z = angle; + } + } + + // Render + RenderScene(camera); + } + void Scene::OnUpdateEditor(TimeStep & ts, const EditorCamera & camera) { - Renderer2D::BeginScene(camera); - - // Draw Sprites - auto group = m_Registry.group(entt::get); - for (auto entity : group) - { - auto [transform, sprite] = group.get(entity); - - // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); - Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity); - } - - // Draw Circles - auto view = m_Registry.view(); - for (auto entity : view) - { - auto [transform, circle] = view.get(entity); - - // Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color); - Renderer2D::DrawCircle(transform.GetTransform(), circle.Color, circle.Thickness, circle.Fade, (int)entity); - } - - Renderer2D::EndScene(); + // Render + RenderScene(camera); } void Scene::OnViewportResize(uint32_t width, uint32_t height) diff --git a/Hazel/src/Hazel/Scene/Scene.h b/Hazel/src/Hazel/Scene/Scene.h index 615e349..40096ce 100644 --- a/Hazel/src/Hazel/Scene/Scene.h +++ b/Hazel/src/Hazel/Scene/Scene.h @@ -34,7 +34,11 @@ namespace Hazel void OnRuntimeStart(); void OnRuntimeStop(); + void OnSimulationStart(); + void OnSimulationStop(); + void OnUpdateRuntime(TimeStep& ts); + void OnUpdateSimulation(TimeStep& ts, const EditorCamera& camera); void OnUpdateEditor(TimeStep& ts, const EditorCamera& camera); void OnViewportResize(uint32_t width, uint32_t height); @@ -49,6 +53,12 @@ namespace Hazel } private: + + void OnPhysics2DStart(); + void OnPhysics2DStop(); + + void RenderScene(const EditorCamera& camera); + template void OnComponentAdded(Entity entity, T& component); @@ -56,7 +66,7 @@ namespace Hazel entt::registry m_Registry; uint32_t m_ViewportWidth = 0, m_ViewportHeight = 0; - b2WorldId m_PhysicsWorld; + b2WorldId* m_PhysicsWorld = nullptr; friend class Entity; friend class SceneSerializer; diff --git a/Sandbox/CMakeLists.txt b/Sandbox/CMakeLists.txt index ead5bd2..7767edd 100644 --- a/Sandbox/CMakeLists.txt +++ b/Sandbox/CMakeLists.txt @@ -21,6 +21,6 @@ file(GLOB_RECURSE SOURCES src/logo/logo.rc ) -add_executable(${PROJECT_NAME} ${SOURCES}) +add_executable(${PROJECT_NAME} WIN32 ${SOURCES}) target_link_libraries(${PROJECT_NAME} PRIVATE Hazel) diff --git a/Sandbox/src/Editor/EditorLayer.cpp b/Sandbox/src/Editor/EditorLayer.cpp index 9704945..b39b9be 100644 --- a/Sandbox/src/Editor/EditorLayer.cpp +++ b/Sandbox/src/Editor/EditorLayer.cpp @@ -38,8 +38,9 @@ namespace Hazel m_LogoTexture = Texture2D::Create("assets/textures/iceLogo.png"); m_CheckerBoardTexture = Texture2D::Create("assets/textures/Checkerboard.png"); - m_PlayIcon = Texture2D::Create("Resources/Icons/PlayButton.png"); - m_StopIcon = Texture2D::Create("Resources/Icons/PauseButton.png"); + m_IconPlay = Texture2D::Create("Resources/Icons/PlayButton.png"); + m_IconStop = Texture2D::Create("Resources/Icons/PauseButton.png"); + m_IconSimulate = Texture2D::Create("Resources/Icons/SimulateButton.png"); m_EditorScene = CreateRef(); m_EditorScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y); @@ -94,6 +95,10 @@ namespace Hazel m_EditorCamera.OnUpdate(ts); m_ActiveScene->OnUpdateEditor(ts, m_EditorCamera); break; + case SceneState::Simulate: + m_EditorCamera.OnUpdate(ts); + m_ActiveScene->OnUpdateSimulation(ts, m_EditorCamera); + break; } @@ -127,8 +132,12 @@ namespace Hazel if (m_SceneState == SceneState::Play) { + Entity camera = m_ActiveScene->GetPrimaryCameraEntity(); - Renderer2D::BeginScene(camera.GetComponent().Camera, camera.GetComponent().GetTransform()); + if (camera) + Renderer2D::BeginScene(camera.GetComponent().Camera, camera.GetComponent().GetTransform()); + else + Renderer2D::BeginScene(m_EditorCamera); }else { Renderer2D::BeginScene(m_EditorCamera); @@ -137,6 +146,46 @@ namespace Hazel if (m_ShowPhysicsColliders) { // box collider + + auto bcview = m_ActiveScene->GetAllEntitiesWith(); + for (auto entity : bcview) + { + auto [tc, bc2D] = bcview.get(entity); + + glm::vec3 scaledOffset = glm::vec3( + bc2D.Offset.x * tc.Scale.x, + bc2D.Offset.y * tc.Scale.y, + 0.0f + ); + + glm::vec3 translation1 = tc.Translation + scaledOffset + glm::vec3(0.0f, 0.0f, 0.001f); + + + // 创建完整的模型变换矩阵 + glm::mat4 model = glm::translate(glm::mat4(1.0f), translation1) + * glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f)) + * glm::scale(glm::mat4(1.0f), tc.Scale); + + // 将 offset 从局部空间变换到世界空间 + glm::vec4 worldOffset = model * glm::vec4(bc2D.Offset.x, bc2D.Offset.y, 0.0f, 1.0f); + + // 最终位置 = 实体位置 + 变换后的offset + Z偏移 + glm::vec3 translation = glm::vec3(worldOffset) + glm::vec3(0.0f, 0.0f, 0.001f); + + // 计算缩放 (Size 是半宽半高,所以要乘2) + glm::vec3 scale = tc.Scale * glm::vec3(bc2D.Size * 2.0f, 1.0f); + + // 创建碰撞体变换矩阵 (包含旋转) + glm::mat4 transform = + glm::translate(glm::mat4(1.0f), translation) + * glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f)) + * glm::scale(glm::mat4(1.0f), scale); + + Renderer2D::DrawRect(transform, glm::vec4(0.2f, 1.0f, 0.2f, 1.0f)); + } + + + /* auto bcview = m_ActiveScene->GetAllEntitiesWith(); for (auto entity : bcview) { @@ -149,6 +198,7 @@ namespace Hazel Renderer2D::DrawRect(transform, glm::vec4(0.2, 1.0f, 0.2f, 1.0f)); } + */ // circle collider auto ccview = m_ActiveScene->GetAllEntitiesWith(); for (auto entity : ccview) @@ -357,7 +407,7 @@ namespace Hazel cameraProjection = camera.GetProjection(); cameraView = glm::inverse(cameraEntity.GetComponent().GetTransform()); - }else if (m_SceneState == SceneState::Edit) + }else { cameraProjection = m_EditorCamera.GetProjection(); cameraView = m_EditorCamera.GetViewMatrix(); @@ -477,6 +527,9 @@ namespace Hazel void EditorLayer::OnScenePlay() { + if (m_SceneState == SceneState::Simulate) + OnSceneStop(); + // SaveScene(); m_SceneState = SceneState::Play; @@ -488,9 +541,31 @@ namespace Hazel void EditorLayer::OnSceneStop() { + if (m_SceneState != SceneState::Play && m_SceneState != SceneState::Simulate) + { + HZ_CORE_WARN("Scene is not playing or simulating!"); + return; + } + + if (m_SceneState == SceneState::Play) + m_ActiveScene->OnRuntimeStop(); + else if (m_SceneState == SceneState::Simulate) + m_ActiveScene->OnSimulationStop(); + m_SceneState = SceneState::Edit; - m_ActiveScene->OnRuntimeStop(); m_ActiveScene = m_EditorScene; + m_SceneHierachyPanel.SetContext(m_ActiveScene); + } + + void EditorLayer::OnSceneSimulation() + { + if (m_SceneState == SceneState::Simulate) + OnSceneStop(); + // SaveScene(); + m_SceneState = SceneState::Simulate; + + m_ActiveScene = Scene::Copy(m_EditorScene); + m_ActiveScene->OnSimulationStart(); m_SceneHierachyPanel.SetContext(m_ActiveScene); } @@ -583,18 +658,30 @@ namespace Hazel // ImGui::Begin("##ToolBar", nullptr); float size = ImGui::GetWindowHeight() - 10.0f; - Ref icon = m_SceneState == SceneState::Edit ? m_PlayIcon : m_StopIcon; ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x * 0.5f - size * 0.5f); ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x * 0.5f - (size * 0.5f)); - if (ImGui::ImageButton("toolbar", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1})) + + Ref icon = (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Simulate)? m_IconPlay : m_IconStop; + if (ImGui::ImageButton("toolbar-play-edit", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1})) { - if (m_SceneState == SceneState::Edit) + if (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Simulate) OnScenePlay(); else if (m_SceneState == SceneState::Play) OnSceneStop(); - } + ImGui::SameLine(); + { + Ref icon = (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Play)? m_IconSimulate : m_IconStop; + if (ImGui::ImageButton("toolbar-simulate", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1})) + { + if (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Play) + OnSceneSimulation(); + else if (m_SceneState == SceneState::Simulate) + OnSceneStop(); + } + } + ImGui::PopStyleVar(2); ImGui::PopStyleColor(3); ImGui::End(); diff --git a/Sandbox/src/Editor/EditorLayer.h b/Sandbox/src/Editor/EditorLayer.h index 18617df..8180e50 100644 --- a/Sandbox/src/Editor/EditorLayer.h +++ b/Sandbox/src/Editor/EditorLayer.h @@ -27,8 +27,10 @@ namespace Hazel void UI_ToolBar(); void OnScenePlay(); + void OnSceneSimulation(); void OnSceneStop(); + void SaveSceneAs() const; void OpenScene(); void OpenScene(const std::filesystem::path& scenePath); @@ -76,12 +78,12 @@ namespace Hazel enum class SceneState { - Edit = 0, Play = 1 + Edit = 0, Play = 1, Simulate = 2 }; SceneState m_SceneState = SceneState::Edit; - Ref m_PlayIcon, m_StopIcon; + Ref m_IconPlay, m_IconStop, m_IconSimulate; }; }