添加简单物理模拟模式功能
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
|
||||
#ifdef HZ_PLATFORM_WINDOWS
|
||||
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -37,6 +37,7 @@ namespace Hazel
|
||||
|
||||
Scene::~Scene()
|
||||
{
|
||||
delete m_PhysicsWorld;
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
@ -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<RigidBody2DComponent>();
|
||||
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<BoxCollider2DComponent>())
|
||||
@ -169,8 +171,8 @@ namespace Hazel
|
||||
auto& cc2d = entity.GetComponent<CircleCollider2DComponent>();
|
||||
|
||||
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<TransformComponent>(entt::get<SpriteRendererComponent>);
|
||||
for (auto entity : group)
|
||||
{
|
||||
auto [transform, sprite] = group.get<TransformComponent, SpriteRendererComponent>(entity);
|
||||
|
||||
// Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color);
|
||||
Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity);
|
||||
}
|
||||
|
||||
// Draw Circles
|
||||
auto view = m_Registry.view<TransformComponent, CircleRendererComponent>();
|
||||
for (auto entity : view)
|
||||
{
|
||||
auto [transform, circle] = view.get<TransformComponent, CircleRendererComponent>(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<RigidBody2DComponent>();
|
||||
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<RigidBody2DComponent>();
|
||||
for (auto e : view)
|
||||
{
|
||||
Entity entity = {e, this};
|
||||
auto& transform = entity.GetComponent<TransformComponent>();
|
||||
auto& rb2D = entity.GetComponent<RigidBody2DComponent>();
|
||||
|
||||
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<TransformComponent>(entt::get<SpriteRendererComponent>);
|
||||
for (auto entity : group)
|
||||
{
|
||||
auto [transform, sprite] = group.get<TransformComponent, SpriteRendererComponent>(entity);
|
||||
|
||||
// Renderer2D::DrawQuad(transform.GetTransform(), sprite.Color);
|
||||
Renderer2D::DrawSprite(transform.GetTransform(), sprite, (int)entity);
|
||||
}
|
||||
|
||||
// Draw Circles
|
||||
auto view = m_Registry.view<TransformComponent, CircleRendererComponent>();
|
||||
for (auto entity : view)
|
||||
{
|
||||
auto [transform, circle] = view.get<TransformComponent, CircleRendererComponent>(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)
|
||||
|
||||
@ -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<typename T>
|
||||
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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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<Scene>();
|
||||
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();
|
||||
if (camera)
|
||||
Renderer2D::BeginScene(camera.GetComponent<CameraComponent>().Camera, camera.GetComponent<TransformComponent>().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<TransformComponent, BoxCollider2DComponent>();
|
||||
for (auto entity : bcview)
|
||||
{
|
||||
auto [tc, bc2D] = bcview.get<TransformComponent, BoxCollider2DComponent>(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<TransformComponent, BoxCollider2DComponent>();
|
||||
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<TransformComponent, CircleCollider2DComponent>();
|
||||
for (auto entity : ccview)
|
||||
@ -357,7 +407,7 @@ namespace Hazel
|
||||
|
||||
cameraProjection = camera.GetProjection();
|
||||
cameraView = glm::inverse(cameraEntity.GetComponent<TransformComponent>().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()
|
||||
{
|
||||
m_SceneState = SceneState::Edit;
|
||||
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 = 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,16 +658,28 @@ namespace Hazel
|
||||
// ImGui::Begin("##ToolBar", nullptr);
|
||||
|
||||
float size = ImGui::GetWindowHeight() - 10.0f;
|
||||
Ref<Texture2D> 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<Texture2D> 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<Texture2D> 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);
|
||||
|
||||
@ -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<Texture2D> m_PlayIcon, m_StopIcon;
|
||||
Ref<Texture2D> m_IconPlay, m_IconStop, m_IconSimulate;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user