From 79e6631c507ab4ac07671300d317209ee703bbd5 Mon Sep 17 00:00:00 2001 From: Atdunbg Date: Wed, 11 Mar 2026 16:13:38 +0800 Subject: [PATCH] add Physics2D class; For Physics2D add DistanceJoint RevoluteJoint PrismaticJoint WeldJoint Component and serialize/deserialize code; use template to Copy Component from entity to entity; remove useless code, fix some error code --- Editor/Editor/EditorLayer.cpp | 5 +- Editor/Editor/EditorLayer.h | 2 - .../Prism/Animation/AnimatorController.cpp | 9 + .../src/Prism/Animation/AnimatorController.h | 13 +- Prism/src/Prism/Editor/SceneHierachyPanel.cpp | 219 +++++++++- Prism/src/Prism/Editor/SceneHierachyPanel.h | 2 + Prism/src/Prism/Physics/Physics2D.cpp | 383 ++++++++++++++++++ Prism/src/Prism/Physics/Physics2D.h | 41 ++ Prism/src/Prism/Physics/PhysicsLayer.cpp | 2 +- Prism/src/Prism/Renderer/Mesh.h | 8 +- Prism/src/Prism/Renderer/Renderer3D.cpp | 1 - Prism/src/Prism/Scene/Components.h | 109 +++++ Prism/src/Prism/Scene/Scene.cpp | 220 ++-------- Prism/src/Prism/Scene/Scene.h | 7 + Prism/src/Prism/Scene/SceneSerializer.cpp | 188 +++++++++ 15 files changed, 1003 insertions(+), 206 deletions(-) create mode 100644 Prism/src/Prism/Physics/Physics2D.cpp create mode 100644 Prism/src/Prism/Physics/Physics2D.h diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 0bbda89..5a7c8ef 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -105,7 +105,7 @@ namespace Prism Renderer::BeginRenderPass(SceneRenderer::GetFinalRenderPass(), false); const auto viewProj = m_EditorCamera.GetViewProjection(); Renderer2D::BeginScene(viewProj, false); - Renderer2D::DrawRotatedRect({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y }, collider.Size * 2.0f, transform.Rotation.z, { 0.0f, 0.0f, 1.0f, 1.0f }); + Renderer2D::DrawRotatedRect({ transform.Translation.x + collider.Offset.x, transform.Translation.y + collider.Offset.y }, {transform.Scale.x * collider.Size.x, transform.Scale.y * collider.Size.y}, transform.Rotation.z, { 0.0f, 0.0f, 1.0f, 1.0f }); Renderer2D::EndScene(); Renderer::EndRenderPass(); } @@ -639,10 +639,9 @@ namespace Prism ImVec2 maxBound = { minBound.x + windowSize.x, minBound.y + windowSize.y }; m_ViewportBounds[0] = { minBound.x, minBound.y }; m_ViewportBounds[1] = { maxBound.x, maxBound.y }; - m_AllowViewportCameraEvents = ImGui::IsMouseHoveringRect(minBound, maxBound); // ImGuizmo - if (m_GizmoType != -1 && !m_SelectionContext.empty()) + if (m_GizmoType != -1 && !m_SelectionContext.empty() && m_SceneState == SceneState::Edit) { auto& selection = m_SelectionContext[0]; diff --git a/Editor/Editor/EditorLayer.h b/Editor/Editor/EditorLayer.h index 3ee1aa3..3e49676 100644 --- a/Editor/Editor/EditorLayer.h +++ b/Editor/Editor/EditorLayer.h @@ -136,8 +136,6 @@ namespace Prism Ref m_PlayButtonTex, m_StopButtonTex, m_PauseButtonTex; - // configure button - bool m_AllowViewportCameraEvents = false; bool m_UIShowBoundingBoxes = false; diff --git a/Prism/src/Prism/Animation/AnimatorController.cpp b/Prism/src/Prism/Animation/AnimatorController.cpp index 2e79a9b..7934c29 100644 --- a/Prism/src/Prism/Animation/AnimatorController.cpp +++ b/Prism/src/Prism/Animation/AnimatorController.cpp @@ -32,6 +32,15 @@ namespace Prism } + void AnimationController::SetSkeleton(const Ref& skeleton) + { + m_skeleton = skeleton; + if (m_skeleton) + { + ComputeBindPoseTransforms(); + } + } + void AnimationController::ComputeBoneTransforms(float time) { const auto boneCount = (uint32_t)m_skeleton->m_Bones.size(); diff --git a/Prism/src/Prism/Animation/AnimatorController.h b/Prism/src/Prism/Animation/AnimatorController.h index 1e8c275..c355831 100644 --- a/Prism/src/Prism/Animation/AnimatorController.h +++ b/Prism/src/Prism/Animation/AnimatorController.h @@ -28,16 +28,9 @@ namespace Prism const std::vector& GetFinalBoneTransforms() const { return m_FinalBoneTransforms; } - void AnimationController::SetSkeleton(const Ref& skeleton) - { - m_skeleton = skeleton; - if (m_skeleton) - { - ComputeBindPoseTransforms(); - } - } - void AnimationController::SetAnimationClip(const Ref& clip) { m_currentClip = clip; } - void AnimationController::SetGlobalInverseTransform(const glm::mat4& inv) { m_GlobalInverseTransform = inv; } + void SetSkeleton(const Ref& skeleton); + void SetAnimationClip(const Ref& clip) { m_currentClip = clip; } + void SetGlobalInverseTransform(const glm::mat4& inv) { m_GlobalInverseTransform = inv; } void Play() { m_State = PLAY; } void Pause() { m_State = PAUSE; } diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp index 2cb343c..2569882 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp @@ -26,6 +26,56 @@ namespace Prism glm::mat4 Mat4FromAssimpMat4(const aiMatrix4x4& matrix); + void SceneHierarchyPanel::DrawConnectedBodySelector(Entity currentEntity, UUID& connectedBody, Scene* context, const char* popupId) + { + Entity connectedEntity = context->FindEntityByUUID(connectedBody); + std::string connectedName = connectedEntity ? connectedEntity.GetComponent().Tag : "None"; + + ImGui::Text("Connected Body"); + ImGui::NextColumn(); + ImGui::PushItemWidth(-1); + const std::string buttonLabel = connectedName + "##" + std::to_string(currentEntity.GetUUID()); + if (ImGui::Button(buttonLabel.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) + { + ImGui::OpenPopup(popupId); + } + ImGui::PopItemWidth(); + ImGui::NextColumn(); + + if (ImGui::BeginPopup(popupId)) + { + ImGui::Text("Select Entity"); + ImGui::Separator(); + + context->m_Registry.view().each([&](auto entityID) + { + Entity e{entityID, context}; + if (e.HasComponent()) + { + const auto& tag = e.GetComponent().Tag; + if (e == currentEntity) return; // 排除自身 + + ImGui::PushID((const void*)(uintptr_t)(uint32_t)e); + if (ImGui::Selectable(tag.c_str(), e.GetUUID() == connectedBody)) + { + connectedBody = e.GetUUID(); + ImGui::CloseCurrentPopup(); + } + ImGui::PopID(); + } + }); + + ImGui::Separator(); + if (ImGui::Selectable("None", connectedBody == 0)) + { + connectedBody = 0; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + } + SceneHierarchyPanel::SceneHierarchyPanel(const Ref& context) : m_Context(context) { @@ -564,6 +614,12 @@ namespace Prism AddComponentPopup("BoxCollider2D"); AddComponentPopup("CircleCollider2D"); + ImGui::SeparatorText("2D Joint Component"); + AddComponentPopup("DistanceJoint2D"); + AddComponentPopup("RevoluteJoint2D"); + AddComponentPopup("PrismaticJoint2D"); + AddComponentPopup("WeldJoint2DComponent"); + ImGui::SeparatorText("3D Component"); AddComponentPopup("Mesh"); AddComponentPopup("Animation", [&](AnimationComponent& component) @@ -649,14 +705,169 @@ namespace Prism } + DrawComponent("DistanceJoint2D", entity, [&](DistanceJoint2DComponent& component) + { + UI::BeginPropertyGrid(); + + DrawConnectedBodySelector(entity, component.ConnectedBody, m_Context.Raw(), "SelectConnectedBodyDist"); + + + UI::Property("Local Anchor A", component.LocalAnchorA); + UI::Property("Local Anchor B", component.LocalAnchorB); + + UI::Property("Length", component.Length); + UI::Separator(); + UI::Property("Enable Spring", component.EnableSpring); + if (component.EnableSpring) + { + UI::Property("Lower Spring Force", component.LowerSpringForce); + UI::Property("Upper Spring Force", component.UpperSpringForce); + UI::Property("Hertz", component.Hertz); + UI::Property("Damping Ratio", component.DampingRatio); + } + UI::Separator(); + + UI::Property("Enable Limit", component.EnableLimit); + if (component.EnableLimit) + { + UI::Property("Min Length", component.MinLength); + UI::Property("Max Length", component.MaxLength); + } + UI::Separator(); + + + UI::Property("Enable Motor", component.EnableMotor); + if (component.EnableMotor) + { + UI::Property("Max Motor Force", component.MaxMotorForce); + UI::Property("Motor Speed", component.MotorSpeed); + } + UI::Separator(); + + + UI::EndPropertyGrid(); + }); + + DrawComponent("Revolute Joint 2D", entity, [&](RevoluteJoint2DComponent& component) + { + UI::BeginPropertyGrid(); + + // Connected Body selector + DrawConnectedBodySelector(entity, component.ConnectedBody, m_Context.Raw(), "SelectConnectedBodyDist"); + + + // 锚点 + UI::Property("Local Anchor A", component.LocalAnchorA); + UI::Property("Local Anchor B", component.LocalAnchorB); + UI::Separator(); + + // 弹簧参数 + UI::Property("Enable Spring", component.EnableSpring); + if (component.EnableSpring) + { + UI::Property("Target Angle (rad)", component.TargetAngle); + UI::Property("Hertz", component.Hertz); + UI::Property("Damping Ratio", component.DampingRatio); + } + UI::Separator(); + + // 限制参数 + UI::Property("Enable Limit", component.EnableLimit); + if (component.EnableLimit) + { + UI::Property("Lower Angle (rad)", component.LowerAngle); + UI::Property("Upper Angle (rad)", component.UpperAngle); + } + UI::Separator(); + + // 马达参数 + UI::Property("Enable Motor", component.EnableMotor); + if (component.EnableMotor) + { + UI::Property("Motor Speed (rad/s)", component.MotorSpeed); + UI::Property("Max Motor Torque", component.MaxMotorTorque); + } + UI::Separator(); + + UI::EndPropertyGrid(); + }); + + DrawComponent("Prismatic Joint 2D", entity, [&](PrismaticJoint2DComponent& component) + { + UI::BeginPropertyGrid(); + + // Connected Body selector + DrawConnectedBodySelector(entity, component.ConnectedBody, m_Context.Raw(), "SelectConnectedBodyDist"); + + // 锚点 + UI::Property("Local Anchor A", component.LocalAnchorA); + UI::Property("Local Anchor B", component.LocalAnchorB); + // 滑动轴 + UI::Property("Local Axis A", component.LocalAxisA); + UI::Separator(); + + // 弹簧参数 + UI::Property("Enable Spring", component.EnableSpring); + if (component.EnableSpring) + { + UI::Property("Target Translation", component.TargetTranslation); + UI::Property("Hertz", component.Hertz); + UI::Property("Damping Ratio", component.DampingRatio); + } + UI::Separator(); + + // 限制参数 + UI::Property("Enable Limit", component.EnableLimit); + if (component.EnableLimit) + { + UI::Property("Lower Translation", component.LowerTranslation); + UI::Property("Upper Translation", component.UpperTranslation); + } + UI::Separator(); + + // 马达参数 + UI::Property("Enable Motor", component.EnableMotor); + if (component.EnableMotor) + { + UI::Property("Motor Speed", component.MotorSpeed); + UI::Property("Max Motor Force", component.MaxMotorForce); + } + UI::Separator(); + + UI::EndPropertyGrid(); + }); + + DrawComponent("Weld Joint 2D", entity, [&](WeldJoint2DComponent& component) + { + UI::BeginPropertyGrid(); + + // Connected Body selector + DrawConnectedBodySelector(entity, component.ConnectedBody, m_Context.Raw(), "SelectConnectedBodyDist"); + + // 锚点 + UI::Property("Local Anchor A", component.LocalAnchorA); + UI::Property("Local Anchor B", component.LocalAnchorB); + UI::Separator(); + + // 焊接关节特有参数(线性和角度的 Hertz 和阻尼) + UI::Property("Linear Hertz", component.LinearHertz); + UI::Property("Angular Hertz", component.AngularHertz); + UI::Property("Linear Damping Ratio", component.LinearDampingRatio); + UI::Property("Angular Damping Ratio", component.AngularDampingRatio); + UI::Separator(); + + UI::EndPropertyGrid(); + }); + + DrawComponent("Mesh", entity, [](MeshComponent& meshComponent) { UI::BeginPropertyGrid(); UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh); - UI::Property("AnimationPlaying", meshComponent.Mesh->m_AnimationPlaying); - UI::Property("TimeMultiple", meshComponent.Mesh->m_TimeMultiplier); - UI::Property("AnimationTime", meshComponent.Mesh->m_AnimationTime); - UI::Property("WorldTime", meshComponent.Mesh->m_WorldTime); + // UI::Property("AnimationPlaying", meshComponent.Mesh->m_AnimationPlaying); + // UI::Property("TimeMultiple", meshComponent.Mesh->m_TimeMultiplier); + // UI::Property("AnimationTime", meshComponent.Mesh->m_AnimationTime); + // UI::Property("WorldTime", meshComponent.Mesh->m_WorldTime); UI::EndPropertyGrid(); }); diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.h b/Prism/src/Prism/Editor/SceneHierachyPanel.h index 45cec53..4d4ea2f 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.h +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.h @@ -34,6 +34,8 @@ namespace Prism template void AddComponentPopup(const char* componentName, Function function); + + static void DrawConnectedBodySelector(Entity currentEntity, UUID& connectedBody, Scene* context, const char* popupId); private: Ref m_Context; Entity m_SelectionContext; diff --git a/Prism/src/Prism/Physics/Physics2D.cpp b/Prism/src/Prism/Physics/Physics2D.cpp new file mode 100644 index 0000000..c4229f6 --- /dev/null +++ b/Prism/src/Prism/Physics/Physics2D.cpp @@ -0,0 +1,383 @@ +// +// Created by Atdunbg on 2026/3/11. +// + +#include "Physics2D.h" + +#include "Prism/Scene/Entity.h" +#include "Prism/Script/ScriptEngine.h" + +namespace Prism +{ + void Physics2D::CreateBody(Scene* scene) + { + auto sceneView = scene->m_Registry.view(); + auto& world = scene->m_Registry.get(sceneView.front()).World; + { + auto view = scene->m_Registry.view(); + scene->m_Physics2DBodyEntityBuffer = new Entity[view.size()]; + uint32_t physicsBodyEntityBufferIndex = 0; + for (auto entity : view) + { + Entity e = { entity, scene }; + auto& transform = e.Transform(); + auto& rigidBody2D = scene->m_Registry.get(entity); + + b2BodyDef bodyDef = b2DefaultBodyDef(); + if (rigidBody2D.BodyType == RigidBody2DComponent::Type::Static) + bodyDef.type = b2_staticBody; + else if (rigidBody2D.BodyType == RigidBody2DComponent::Type::Dynamic) + bodyDef.type = b2_dynamicBody; + else if (rigidBody2D.BodyType == RigidBody2DComponent::Type::Kinematic) + bodyDef.type = b2_kinematicBody; + bodyDef.position = {transform.Translation.x, transform.Translation.y}; + + float rotationZ = transform.Rotation.z; + bodyDef.rotation = b2Rot{cos(rotationZ), sin(rotationZ)}; + + // box2D fixRotation renamed to MotionLocks + bodyDef.motionLocks = b2MotionLocks{false, false, rigidBody2D.FixedRotation}; + + Entity* entityStorage = &scene->m_Physics2DBodyEntityBuffer[physicsBodyEntityBufferIndex++]; + *entityStorage = e; + bodyDef.userData = entityStorage; + + rigidBody2D.RuntimeBodyID = b2CreateBody(world, &bodyDef); + } + } + + // BoxCollider2DComponent + { + auto view = scene->m_Registry.view(); + for (auto entity : view) + { + Entity e = { entity, scene }; + + auto& boxCollider2D = scene->m_Registry.get(entity); + if (e.HasComponent()) + { + const auto& rigidBody2D = e.GetComponent(); + const auto& transform = e.GetComponent(); + PM_CORE_ASSERT(b2Body_IsValid(rigidBody2D.RuntimeBodyID)); + + b2BodyId bodyId = rigidBody2D.RuntimeBodyID; + + glm::vec2 halfSize = boxCollider2D.Size * 0.5f; + + b2Polygon boxShape = b2MakeOffsetBox(halfSize.x * transform.Scale.x, halfSize.y * transform.Scale.y, {boxCollider2D.Offset.x,boxCollider2D.Offset.y}, {1.0f, 0.0f}); + b2ShapeDef shapeDef = b2DefaultShapeDef(); + shapeDef.density = boxCollider2D.Density; + shapeDef.material.friction = boxCollider2D.Friction; + shapeDef.enableContactEvents = true; + + b2CreatePolygonShape(bodyId, &shapeDef, &boxShape); + } + } + } + + // CircleCollider2DComponent + { + auto view = scene->m_Registry.view(); + for (auto entity : view) + { + Entity e = { entity, scene }; + + auto& circleCollider2D = scene->m_Registry.get(entity); + if (e.HasComponent()) + { + auto& rigidBody2D = e.GetComponent(); + auto& transform = e.GetComponent(); + PM_CORE_ASSERT(b2Body_IsValid(rigidBody2D.RuntimeBodyID)); + + b2BodyId bodyId = rigidBody2D.RuntimeBodyID; + + b2Vec2 centor = {circleCollider2D.Offset.x, circleCollider2D.Offset.y}; + + b2Circle circleShape; + circleShape.center = centor; + circleShape.radius = circleCollider2D.Radius; + + b2ShapeDef shapeDef = b2DefaultShapeDef(); + + shapeDef.density = circleCollider2D.Density; + shapeDef.material.friction = circleCollider2D.Friction; + shapeDef.enableContactEvents = true; + + b2CreateCircleShape(bodyId, &shapeDef, &circleShape); + } + } + } + + // DistanceJoint2DComponent + { + auto view = scene->m_Registry.view(); + for (auto entity : view) + { + auto& jointComp = view.get(entity); + + // 验证实体引用 + Entity bodyA = { entity, scene }; + Entity bodyB = scene->FindEntityByUUID(jointComp.ConnectedBody); + if (!bodyA || !bodyB) + { + PM_CORE_WARN("DistanceJoint has invalid body references"); + continue; + } + + // TODO: temp solve + if (!bodyA.HasComponent() || !bodyB.HasComponent()) continue; + + auto& rbA = bodyA.GetComponent(); + auto& rbB = bodyB.GetComponent(); + + if (!b2Body_IsValid(rbA.RuntimeBodyID) || !b2Body_IsValid(rbB.RuntimeBodyID)) + { + PM_CORE_WARN("One of the bodies for DistanceJoint is not valid"); + continue; + } + + // 填充关节定义 + b2DistanceJointDef jointDef = b2DefaultDistanceJointDef(); + jointDef.base.bodyIdA = rbA.RuntimeBodyID; + jointDef.base.bodyIdB = rbB.RuntimeBodyID; + jointDef.base.localFrameA = { + { jointComp.LocalAnchorA.x, jointComp.LocalAnchorA.y }, + b2Rot_identity // 通常不需要旋转,保持单位即可 + }; + jointDef.base.localFrameB = { + { jointComp.LocalAnchorB.x, jointComp.LocalAnchorB.y }, + b2Rot_identity + }; + jointDef.base.collideConnected = jointComp.CollideConnected; + + // 设置距离关节特有参数 + jointDef.length = jointComp.Length; + jointDef.enableSpring = jointComp.EnableSpring; + jointDef.lowerSpringForce = jointComp.LowerSpringForce; + jointDef.upperSpringForce = jointComp.UpperSpringForce; + jointDef.hertz = jointComp.Hertz; + jointDef.dampingRatio = jointComp.DampingRatio; + jointDef.enableLimit = jointComp.EnableLimit; + jointDef.minLength = jointComp.MinLength; + jointDef.maxLength = jointComp.MaxLength; + jointDef.enableMotor = jointComp.EnableMotor; + jointDef.maxMotorForce = jointComp.MaxMotorForce; + jointDef.motorSpeed = jointComp.MotorSpeed; + + jointComp.RuntimeJointId = b2CreateDistanceJoint(world, &jointDef); + PM_CORE_ASSERT(b2Joint_IsValid(jointComp.RuntimeJointId)); + } + } + + // RevoluteJoint2DComponent + { + auto view = scene->m_Registry.view(); + for (auto entity : view) + { + auto& jointComp = view.get(entity); + + Entity bodyA = { entity, scene }; + Entity bodyB = scene->FindEntityByUUID(jointComp.ConnectedBody); + if (!bodyA || !bodyB) continue; + + // TODO: temp solve + if (!bodyA.HasComponent() || !bodyB.HasComponent()) continue; + + auto& rbA = bodyA.GetComponent(); + auto& rbB = bodyB.GetComponent(); + if (!b2Body_IsValid(rbA.RuntimeBodyID) || !b2Body_IsValid(rbB.RuntimeBodyID)) + continue; + + b2RevoluteJointDef jointDef = b2DefaultRevoluteJointDef(); + + // 通用属性(必须通过 base 访问) + jointDef.base.bodyIdA = rbA.RuntimeBodyID; + jointDef.base.bodyIdB = rbB.RuntimeBodyID; + jointDef.base.localFrameA = { + { jointComp.LocalAnchorA.x, jointComp.LocalAnchorA.y }, + b2Rot_identity + }; + jointDef.base.localFrameB = { + { jointComp.LocalAnchorB.x, jointComp.LocalAnchorB.y }, + b2Rot_identity + }; + jointDef.base.collideConnected = jointComp.CollideConnected; + + // 旋转关节特有属性 + jointDef.targetAngle = jointComp.TargetAngle; + jointDef.enableSpring = jointComp.EnableSpring; + jointDef.hertz = jointComp.Hertz; + jointDef.dampingRatio = jointComp.DampingRatio; + jointDef.enableLimit = jointComp.EnableLimit; + jointDef.lowerAngle = jointComp.LowerAngle; + jointDef.upperAngle = jointComp.UpperAngle; + jointDef.enableMotor = jointComp.EnableMotor; + jointDef.motorSpeed = jointComp.MotorSpeed; + jointDef.maxMotorTorque = jointComp.MaxMotorTorque; + + jointComp.RuntimeJointId = b2CreateRevoluteJoint(world, &jointDef); + PM_CORE_ASSERT(b2Joint_IsValid(jointComp.RuntimeJointId)); + } + } + + // PrismaticJoint2DComponent + { + auto view = scene->m_Registry.view(); + for (auto entity : view) + { + auto& jointComp = view.get(entity); + + Entity bodyA = { entity, scene }; + Entity bodyB = scene->FindEntityByUUID(jointComp.ConnectedBody); + if (!bodyA || !bodyB) continue; + + // TODO: temp solve + if (!bodyA.HasComponent() || !bodyB.HasComponent()) continue; + + auto& rbA = bodyA.GetComponent(); + auto& rbB = bodyB.GetComponent(); + if (!b2Body_IsValid(rbA.RuntimeBodyID) || !b2Body_IsValid(rbB.RuntimeBodyID)) + continue; + + b2PrismaticJointDef jointDef = b2DefaultPrismaticJointDef(); + + jointDef.base.bodyIdA = rbA.RuntimeBodyID; + jointDef.base.bodyIdB = rbB.RuntimeBodyID; + + float angle = atan2(jointComp.LocalAxisA.y, jointComp.LocalAxisA.x); + jointDef.base.localFrameA = { + { jointComp.LocalAnchorA.x, jointComp.LocalAnchorA.y }, + b2MakeRot(angle) + }; + + jointDef.base.localFrameB = { + { jointComp.LocalAnchorB.x, jointComp.LocalAnchorB.y }, + b2Rot_identity + }; + + jointDef.base.collideConnected = jointComp.CollideConnected; + + jointDef.enableSpring = jointComp.EnableSpring; + jointDef.hertz = jointComp.Hertz; + jointDef.dampingRatio = jointComp.DampingRatio; + jointDef.targetTranslation = jointComp.TargetTranslation; + jointDef.enableLimit = jointComp.EnableLimit; + jointDef.lowerTranslation = jointComp.LowerTranslation; + jointDef.upperTranslation = jointComp.UpperTranslation; + jointDef.enableMotor = jointComp.EnableMotor; + jointDef.motorSpeed = jointComp.MotorSpeed; + jointDef.maxMotorForce = jointComp.MaxMotorForce; + + jointComp.RuntimeJointId = b2CreatePrismaticJoint(world, &jointDef); + PM_CORE_ASSERT(b2Joint_IsValid(jointComp.RuntimeJointId)); + } + } + + // WeldJoint2DComponent + { + auto view = scene->m_Registry.view(); + for (auto entity : view) + { + auto& jointComp = view.get(entity); + + Entity bodyA = { entity, scene }; + Entity bodyB = scene->FindEntityByUUID(jointComp.ConnectedBody); + if (!bodyA || !bodyB) continue; + + // TODO: temp solve + if (!bodyA.HasComponent() || !bodyB.HasComponent()) continue; + + auto& rbA = bodyA.GetComponent(); + auto& rbB = bodyB.GetComponent(); + if (!b2Body_IsValid(rbA.RuntimeBodyID) || !b2Body_IsValid(rbB.RuntimeBodyID)) + continue; + + b2WeldJointDef jointDef = b2DefaultWeldJointDef(); + + jointDef.base.bodyIdA = rbA.RuntimeBodyID; + jointDef.base.bodyIdB = rbB.RuntimeBodyID; + jointDef.base.localFrameA = { + { jointComp.LocalAnchorA.x, jointComp.LocalAnchorA.y }, + b2Rot_identity + }; + jointDef.base.localFrameB = { + { jointComp.LocalAnchorB.x, jointComp.LocalAnchorB.y }, + b2Rot_identity + }; + jointDef.base.collideConnected = jointComp.CollideConnected; + + jointDef.linearHertz = jointComp.LinearHertz; + jointDef.angularHertz = jointComp.AngularHertz; + jointDef.linearDampingRatio = jointComp.LinearDampingRatio; + jointDef.angularDampingRatio = jointComp.AngularDampingRatio; + + jointComp.RuntimeJointId = b2CreateWeldJoint(world, &jointDef); + PM_CORE_ASSERT(b2Joint_IsValid(jointComp.RuntimeJointId)); + } + } + + } + + + + void Physics2D::ProcessContactEvents(const b2WorldId worldId) { + const b2ContactEvents contactEvents = b2World_GetContactEvents(worldId); + + // Contact Begin Touch + for (int i = 0; i < contactEvents.beginCount; ++i) { + const b2ContactBeginTouchEvent& event = contactEvents.beginEvents[i]; + + auto& entityA = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdA))); + auto& entityB = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdB))); + + if (entityA.HasComponent() && ScriptEngine::ModuleExists(entityA.GetComponent().ModuleName)) + ScriptEngine::OnCollision2DBegin(entityA); + + if (entityB.HasComponent() && ScriptEngine::ModuleExists(entityB.GetComponent().ModuleName)) + ScriptEngine::OnCollision2DBegin(entityB); + } + + + // Contact Begin Touch + for (int i = 0; i < contactEvents.endCount; ++i) { + const b2ContactEndTouchEvent& event = contactEvents.endEvents[i]; + + auto& entityA = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdA))); + auto& entityB = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdB))); + + if (entityA.HasComponent() && ScriptEngine::ModuleExists(entityA.GetComponent().ModuleName)) + ScriptEngine::OnCollision2DEnd(entityA); + + if (entityB.HasComponent() && ScriptEngine::ModuleExists(entityB.GetComponent().ModuleName)) + ScriptEngine::OnCollision2DEnd(entityB); + } + } + + void Physics2D::OnTransformConstruct(entt::registry& registry, entt::entity entity) + { + // PM_CORE_TRACE("Transform Component constructed!"); + } + + void Physics2D::OnScriptComponentConstruct(entt::registry& registry, entt::entity entity) + { + // Note: there should be exactly one scene component per registry + const auto sceneView = registry.view(); + const UUID sceneID = registry.get(sceneView.front()).SceneID; + + Scene* scene = Scene::s_ActiveScenes[sceneID]; + + const auto entityID = registry.get(entity).ID; + PM_CORE_ASSERT(scene->m_EntityIDMap.find(entityID) != scene->m_EntityIDMap.end()); + ScriptEngine::InitScriptEntity(scene->m_EntityIDMap.at(entityID)); + } + + void Physics2D::OnScriptComponentDestroy(entt::registry& registry, const entt::entity entity) + { + const auto sceneView = registry.view(); + const UUID sceneID = registry.get(sceneView.front()).SceneID; + + const auto entityID = registry.get(entity).ID; + ScriptEngine::OnScriptComponentDestroyed(sceneID, entityID); + } + +} diff --git a/Prism/src/Prism/Physics/Physics2D.h b/Prism/src/Prism/Physics/Physics2D.h new file mode 100644 index 0000000..af59d75 --- /dev/null +++ b/Prism/src/Prism/Physics/Physics2D.h @@ -0,0 +1,41 @@ +// +// Created by Atdunbg on 2026/3/11. +// + +#ifndef PRISM_PHYSICS2D_H +#define PRISM_PHYSICS2D_H + +#include + +#include "entt/entity/registry.hpp" +#include "Prism/Scene/Scene.h" + +namespace Prism +{ + struct Box2DWorldComponent + { + b2WorldId World{}; + + Box2DWorldComponent() = delete; + Box2DWorldComponent(const b2Vec2& gravity) { + b2WorldDef worldDef = b2DefaultWorldDef(); + worldDef.gravity = gravity; + World = b2CreateWorld(&worldDef); + } + }; + + class Physics2D + { + public: + + static void CreateBody(Scene* scene); + static void ProcessContactEvents(b2WorldId worldId); + static void OnTransformConstruct(entt::registry& registry, entt::entity entity); + static void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity); + static void OnScriptComponentDestroy(entt::registry& registry, entt::entity entity); + + }; +} + + +#endif //PRISM_PHYSICS2D_H \ No newline at end of file diff --git a/Prism/src/Prism/Physics/PhysicsLayer.cpp b/Prism/src/Prism/Physics/PhysicsLayer.cpp index 583b827..1cf6927 100644 --- a/Prism/src/Prism/Physics/PhysicsLayer.cpp +++ b/Prism/src/Prism/Physics/PhysicsLayer.cpp @@ -9,7 +9,7 @@ namespace Prism template static bool RemoveIfExists(std::vector& vector, ConditionFunction condition) { - for (std::vector::iterator it = vector.begin(); it != vector.end(); ++it) + for (auto it = vector.begin(); it != vector.end(); ++it) { if (condition(*it)) { diff --git a/Prism/src/Prism/Renderer/Mesh.h b/Prism/src/Prism/Renderer/Mesh.h index dd49fe6..918fa60 100644 --- a/Prism/src/Prism/Renderer/Mesh.h +++ b/Prism/src/Prism/Renderer/Mesh.h @@ -176,10 +176,10 @@ namespace Prism // Animation bool m_IsAnimated = false; - bool m_AnimationPlaying = false; - float m_AnimationTime = 0.0f; - float m_WorldTime = 0.0f; - float m_TimeMultiplier = 1.0f; + // bool m_AnimationPlaying = false; + // float m_AnimationTime = 0.0f; + // float m_WorldTime = 0.0f; + // float m_TimeMultiplier = 1.0f; std::string m_FilePath; private: diff --git a/Prism/src/Prism/Renderer/Renderer3D.cpp b/Prism/src/Prism/Renderer/Renderer3D.cpp index b9145f5..f00f3d3 100644 --- a/Prism/src/Prism/Renderer/Renderer3D.cpp +++ b/Prism/src/Prism/Renderer/Renderer3D.cpp @@ -432,7 +432,6 @@ namespace Prism s_Data.CompositeShader->SetFloat("u_Exposure", s_Data.AutoExposureData.EnableAutoExposure ? s_Data.AutoExposureData.CurrentExposure : s_Data.SceneData.SceneCamera.Camera.GetExposure()); s_Data.CompositeShader->SetInt("u_TextureSamples", s_Data.GeoPass->GetSpecification().TargetFramebuffer->GetSpecification().Samples); s_Data.CompositeShader->SetFloat("u_EnableBloom", s_Data.EnableBloom); - s_Data.CompositeShader->SetInt("u_DepthTexture", 1); s_Data.GeoPass->GetSpecification().TargetFramebuffer->BindTexture(); Renderer::Submit([]() diff --git a/Prism/src/Prism/Scene/Components.h b/Prism/src/Prism/Scene/Components.h index 2edbea4..55a3cc6 100644 --- a/Prism/src/Prism/Scene/Components.h +++ b/Prism/src/Prism/Scene/Components.h @@ -187,6 +187,99 @@ namespace Prism CircleCollider2DComponent(const CircleCollider2DComponent& other) = default; }; + struct DistanceJoint2DComponent + { + UUID ConnectedBody = 0; + bool CollideConnected = false; + + // 局部锚点(相对于刚体原点) + glm::vec2 LocalAnchorA = {0.0f, 0.0f}; + glm::vec2 LocalAnchorB = {0.0f, 0.0f}; + + // 距离关节特有参数(与b2DistanceJointDef对应) + float Length = 1.0f; + bool EnableSpring = false; + float LowerSpringForce = 0.0f; + float UpperSpringForce = 0.0f; + float Hertz = 0.0f; + float DampingRatio = 0.0f; + bool EnableLimit = false; + float MinLength = 0.0f; + float MaxLength = 1.0f; + bool EnableMotor = false; + float MaxMotorForce = 0.0f; + float MotorSpeed = 0.0f; + + b2JointId RuntimeJointId = b2_nullJointId; + }; + + struct RevoluteJoint2DComponent + { + UUID ConnectedBody = 0; + bool CollideConnected = false; + + glm::vec2 LocalAnchorA = {0.0f, 0.0f}; + glm::vec2 LocalAnchorB = {0.0f, 0.0f}; + + // 旋转关节特有属性(直接对应 b2RevoluteJointDef 成员) + float TargetAngle = 0.0f; // 弹簧驱动的目标角度(弧度) + bool EnableSpring = false; + float Hertz = 0.0f; + float DampingRatio = 0.0f; + bool EnableLimit = false; + float LowerAngle = 0.0f; + float UpperAngle = 0.0f; + bool EnableMotor = false; + float MotorSpeed = 0.0f; + float MaxMotorTorque = 0.0f; + + b2JointId RuntimeJointId = b2_nullJointId; + }; + + struct PrismaticJoint2DComponent + { + UUID ConnectedBody = 0; + bool CollideConnected = false; + + glm::vec2 LocalAnchorA = {0.0f, 0.0f}; // 局部锚点 A + glm::vec2 LocalAnchorB = {0.0f, 0.0f}; // 局部锚点 B + glm::vec2 LocalAxisA = {1.0f, 0.0f}; // 局部轴方向(在 BodyA 空间中,应归一化) + + // 弹簧参数 + bool EnableSpring = false; + float Hertz = 0.0f; + float DampingRatio = 0.0f; + float TargetTranslation = 0.0f; + + // 限制参数 + bool EnableLimit = false; + float LowerTranslation = 0.0f; + float UpperTranslation = 0.0f; + + // 马达参数 + bool EnableMotor = false; + float MotorSpeed = 0.0f; + float MaxMotorForce = 0.0f; + + b2JointId RuntimeJointId = b2_nullJointId; + }; + + struct WeldJoint2DComponent + { + UUID ConnectedBody = 0; + bool CollideConnected = false; + + glm::vec2 LocalAnchorA = {0.0f, 0.0f}; + glm::vec2 LocalAnchorB = {0.0f, 0.0f}; + + float LinearHertz = 0.0f; + float AngularHertz = 0.0f; + float LinearDampingRatio = 0.0f; + float AngularDampingRatio = 0.0f; + + b2JointId RuntimeJointId = b2_nullJointId; + }; + struct SphereColliderComponent { @@ -305,6 +398,22 @@ namespace Prism } }; + template + struct ComponentGroup + { + }; + using AllComponent = ComponentGroup< + TagComponent, RelationshipComponent, + TransformComponent, SpriteRendererComponent, + RigidBody2DComponent, BoxCollider2DComponent, CircleCollider2DComponent, + DistanceJoint2DComponent, RevoluteJoint2DComponent, PrismaticJoint2DComponent, WeldJoint2DComponent, + MeshComponent, + RigidBodyComponent, BoxColliderComponent, SphereColliderComponent, CapsuleColliderComponent, MeshColliderComponent, + AnimationComponent, + DirectionalLightComponent, SkyLightComponent, + ScriptComponent, + CameraComponent + >; } diff --git a/Prism/src/Prism/Scene/Scene.cpp b/Prism/src/Prism/Scene/Scene.cpp index 8f2d43b..ecd3119 100644 --- a/Prism/src/Prism/Scene/Scene.cpp +++ b/Prism/src/Prism/Scene/Scene.cpp @@ -8,7 +8,6 @@ #include "Entity.h" #include "Prism/Renderer/SceneRenderer.h" #include "Prism/Script/ScriptEngine.h" -#include #define GLM_ENABLE_EXPERIMENTAL #include @@ -22,102 +21,26 @@ #include "Prism/Asset/AssetsManager.h" #include "Prism/Core/Input.h" #include "Prism/Core/Math/Math.h" +#include "Prism/Physics/Physics2D.h" #include "Prism/Renderer/Renderer.h" namespace Prism { - std::unordered_map s_ActiveScenes; + std::unordered_map Scene::s_ActiveScenes; static uint32_t s_SceneIDCounter = 0; - struct SceneComponent - { - UUID SceneID; - }; - - struct Box2DWorldComponent - { - b2WorldId World; - - Box2DWorldComponent() = delete; - Box2DWorldComponent(const b2Vec2& gravity) { - b2WorldDef worldDef = b2DefaultWorldDef(); - worldDef.gravity = gravity; - World = b2CreateWorld(&worldDef); - } - }; - void ProcessContactEvents(const b2WorldId worldId) { - const b2ContactEvents contactEvents = b2World_GetContactEvents(worldId); - - // Contact Begin Touch - for (int i = 0; i < contactEvents.beginCount; ++i) { - const b2ContactBeginTouchEvent& event = contactEvents.beginEvents[i]; - - auto& entityA = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdA))); - auto& entityB = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdB))); - - if (entityA.HasComponent() && ScriptEngine::ModuleExists(entityA.GetComponent().ModuleName)) - ScriptEngine::OnCollision2DBegin(entityA); - - if (entityB.HasComponent() && ScriptEngine::ModuleExists(entityB.GetComponent().ModuleName)) - ScriptEngine::OnCollision2DBegin(entityB); - } - - - // Contact Begin Touch - for (int i = 0; i < contactEvents.endCount; ++i) { - const b2ContactEndTouchEvent& event = contactEvents.endEvents[i]; - - auto& entityA = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdA))); - auto& entityB = *static_cast(b2Body_GetUserData(b2Shape_GetBody(event.shapeIdB))); - - if (entityA.HasComponent() && ScriptEngine::ModuleExists(entityA.GetComponent().ModuleName)) - ScriptEngine::OnCollision2DEnd(entityA); - - if (entityB.HasComponent() && ScriptEngine::ModuleExists(entityB.GetComponent().ModuleName)) - ScriptEngine::OnCollision2DEnd(entityB); - } - } - - - - void OnTransformConstruct(entt::registry& registry, entt::entity entity) - { - // PM_CORE_TRACE("Transform Component constructed!"); - } - - void OnScriptComponentConstruct(entt::registry& registry, entt::entity entity) - { - // Note: there should be exactly one scene component per registry - const auto sceneView = registry.view(); - UUID sceneID = registry.get(sceneView.front()).SceneID; - - Scene* scene = s_ActiveScenes[sceneID]; - - auto entityID = registry.get(entity).ID; - PM_CORE_ASSERT(scene->m_EntityIDMap.find(entityID) != scene->m_EntityIDMap.end()); - ScriptEngine::InitScriptEntity(scene->m_EntityIDMap.at(entityID)); - } - - void OnScriptComponentDestroy(entt::registry& registry, entt::entity entity) - { - const auto sceneView = registry.view(); - const UUID sceneID = registry.get(sceneView.front()).SceneID; - - const auto entityID = registry.get(entity).ID; - ScriptEngine::OnScriptComponentDestroyed(sceneID, entityID); - } Scene::Scene(const std::string& debugName, const bool isEditorScene) : m_SceneID(++s_SceneIDCounter), m_DebugName(debugName) { - m_Registry.on_construct().connect<&OnTransformConstruct>(); - m_Registry.on_construct().connect<&OnScriptComponentConstruct>(); + m_Registry.on_construct().connect<&Physics2D::OnTransformConstruct>(); + m_Registry.on_construct().connect<&Physics2D::OnScriptComponentConstruct>(); m_SceneEntity = m_Registry.create(); m_Registry.emplace(m_SceneEntity, m_SceneID); @@ -152,14 +75,12 @@ namespace Prism m_CameraIcon = AssetsManager::GetAsset("assets/editor/Camera.png"); m_LightIcon = AssetsManager::GetAsset("assets/editor/light.png"); + } void Scene::OnShutdown() { - /* - auto b2WorldView = m_Registry.view(); b2DestroyWorld(m_Registry.get(m_SceneEntity).World); - */ } void Scene::OnUpdate(TimeStep ts) @@ -175,7 +96,7 @@ namespace Prism b2World_Step(box2DWorld, ts, positionIterations); // Process Contact Envents box2d version 3.0^ should impl contact event after b2World_Step - ProcessContactEvents(box2DWorld); + Physics2D::ProcessContactEvents(box2DWorld); { const auto view = m_Registry.view(); @@ -283,7 +204,7 @@ namespace Prism m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod); - SceneRenderer::BeginScene(this, { static_cast(camera), cameraViewMatrix }); + SceneRenderer::BeginScene(this, { static_cast(camera), cameraViewMatrix }, false); { const auto group = m_Registry.group(entt::get); for (const auto entity : group) @@ -367,8 +288,8 @@ namespace Prism m_SkyboxMaterial->Set("u_TextureLod", m_SkyboxLod); // TODO: this value should be storage and can modify - - SceneRenderer::BeginScene(this, { static_cast(editorCamera), editorCamera.GetViewMatrix(), 0.1f, 1000.0f, 45.0f}); + // TODO: Renderer2D cannot blend with Renderer3D + SceneRenderer::BeginScene(this, { static_cast(editorCamera), editorCamera.GetViewMatrix(), 0.1f, 1000.0f, 45.0f}, false); { const auto group = m_Registry.group(entt::get); { @@ -471,97 +392,7 @@ namespace Prism // Box2D physics - auto sceneView = m_Registry.view(); - auto& world = m_Registry.get(sceneView.front()).World; - { - auto view = m_Registry.view(); - m_Physics2DBodyEntityBuffer = new Entity[view.size()]; - uint32_t physicsBodyEntityBufferIndex = 0; - for (auto entity : view) - { - Entity e = { entity, this }; - auto& transform = e.Transform(); - auto& rigidBody2D = m_Registry.get(entity); - - b2BodyDef bodyDef = b2DefaultBodyDef(); - if (rigidBody2D.BodyType == RigidBody2DComponent::Type::Static) - bodyDef.type = b2_staticBody; - else if (rigidBody2D.BodyType == RigidBody2DComponent::Type::Dynamic) - bodyDef.type = b2_dynamicBody; - else if (rigidBody2D.BodyType == RigidBody2DComponent::Type::Kinematic) - bodyDef.type = b2_kinematicBody; - bodyDef.position = {transform.Translation.x, transform.Translation.y}; - - float rotationZ = transform.Rotation.z; - bodyDef.rotation = b2Rot{cos(rotationZ), sin(rotationZ)}; - - // box2D fixRotation renamed to motionlocks - bodyDef.motionLocks = b2MotionLocks{false, false, rigidBody2D.FixedRotation}; - - Entity* entityStorage = &m_Physics2DBodyEntityBuffer[physicsBodyEntityBufferIndex++]; - *entityStorage = e; - bodyDef.userData = entityStorage; - - rigidBody2D.RuntimeBodyID = b2CreateBody(world, &bodyDef); - } - } - - - { - auto view = m_Registry.view(); - for (auto entity : view) - { - Entity e = { entity, this }; - - auto& boxCollider2D = m_Registry.get(entity); - if (e.HasComponent()) - { - const auto& rigidBody2D = e.GetComponent(); - PM_CORE_ASSERT(b2Body_IsValid(rigidBody2D.RuntimeBodyID)); - - b2BodyId bodyId = rigidBody2D.RuntimeBodyID; - - b2Polygon boxShape = b2MakeOffsetBox(boxCollider2D.Size.x, boxCollider2D.Size.y, {boxCollider2D.Offset.x,boxCollider2D.Offset.y}, {1.0f, 0.0f}); - b2ShapeDef shapeDef = b2DefaultShapeDef(); - shapeDef.density = boxCollider2D.Density; - shapeDef.material.friction = boxCollider2D.Friction; - shapeDef.enableContactEvents = true; - - b2CreatePolygonShape(bodyId, &shapeDef, &boxShape); - } - } - } - - { - auto view = m_Registry.view(); - for (auto entity : view) - { - Entity e = { entity, this }; - - auto& circleCollider2D = m_Registry.get(entity); - if (e.HasComponent()) - { - auto& rigidBody2D = e.GetComponent(); - PM_CORE_ASSERT(b2Body_IsValid(rigidBody2D.RuntimeBodyID)); - - b2BodyId bodyId = rigidBody2D.RuntimeBodyID; - - b2Vec2 centor = {circleCollider2D.Offset.x, circleCollider2D.Offset.y}; - - b2Circle circleShape; - circleShape.center = centor; - circleShape.radius = circleCollider2D.Radius; - - b2ShapeDef shapeDef = b2DefaultShapeDef(); - - shapeDef.density = circleCollider2D.Density; - shapeDef.material.friction = circleCollider2D.Friction; - shapeDef.enableContactEvents = true; - - b2CreateCircleShape(bodyId, &shapeDef, &circleShape); - } - } - } + Physics2D::CreateBody(this); { auto view = m_Registry.view(); @@ -663,9 +494,14 @@ namespace Prism auto& destComponent = dstRegistry.emplace_or_replace(destEntity, srcComponent); } } + template + static void CopyComponent(ComponentGroup, entt::registry& dst, entt::registry& src, const std::unordered_map& enttMap) + { + (CopyComponent(dst, src, enttMap), ...); + } template - static void CopyComponentIfExists(entt::entity dst, entt::entity src, entt::registry& registry) + static void CopyComponentIfExists(const entt::entity dst, const entt::entity src, entt::registry& registry) { if (registry.storage().contains(src)) { @@ -673,6 +509,11 @@ namespace Prism registry.emplace_or_replace(dst, srcComponent); } } + template + static auto CopyComponentIfExists(ComponentGroup, const entt::entity dst, const entt::entity src, entt::registry& registry) -> void + { + (CopyComponentIfExists(dst, src, registry), ...); + } void Scene::DuplicateEntity(Entity entity) @@ -683,6 +524,8 @@ namespace Prism else newEntity = CreateEntity(); + CopyComponentIfExists(AllComponent{},newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + /* CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); @@ -701,6 +544,14 @@ namespace Prism CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + */ + + } Entity Scene::FindEntityByTag(const std::string &tag) { @@ -759,7 +610,8 @@ namespace Prism Entity e = target->CreateEntityWithID(uuid, "", true); enttMap[uuid] = e.m_EntityHandle; } - + CopyComponent(AllComponent{},target->m_Registry, m_Registry, enttMap); + /* CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); @@ -779,6 +631,12 @@ namespace Prism CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + */ const auto& entityInstanceMap = ScriptEngine::GetEntityInstanceMap(); if (entityInstanceMap.find(target->GetUUID()) != entityInstanceMap.end()) diff --git a/Prism/src/Prism/Scene/Scene.h b/Prism/src/Prism/Scene/Scene.h index c088766..fb6b79d 100644 --- a/Prism/src/Prism/Scene/Scene.h +++ b/Prism/src/Prism/Scene/Scene.h @@ -46,6 +46,11 @@ namespace Prism class Entity; using EntityMap = std::unordered_map; + struct SceneComponent + { + UUID SceneID; + }; + class PRISM_API Scene : public RefCounted { public: @@ -141,8 +146,10 @@ namespace Prism Ref m_CameraIcon; Ref m_LightIcon; + static std::unordered_map s_ActiveScenes; private: friend class Entity; + friend class Physics2D; friend class Renderer3D; friend class SceneRenderer; friend class SceneSerializer; diff --git a/Prism/src/Prism/Scene/SceneSerializer.cpp b/Prism/src/Prism/Scene/SceneSerializer.cpp index bbc240c..a4c7835 100644 --- a/Prism/src/Prism/Scene/SceneSerializer.cpp +++ b/Prism/src/Prism/Scene/SceneSerializer.cpp @@ -370,6 +370,109 @@ namespace Prism out << YAML::EndMap; // CircleCollider2DComponent } + if (entity.HasComponent()) + { + out << YAML::Key << "DistanceJoint2DComponent"; + out << YAML::BeginMap; // DistanceJoint2DComponent + + const auto& distanceJoint2DComponent = entity.GetComponent(); + out << YAML::Key << "ConnectedBody" << YAML::Value << distanceJoint2DComponent.ConnectedBody; + out << YAML::Key << "LocalAnchorA" << YAML::Value << distanceJoint2DComponent.LocalAnchorA; + out << YAML::Key << "LocalAnchorB" << YAML::Value << distanceJoint2DComponent.LocalAnchorB; + out << YAML::Key << "Length" << YAML::Value << distanceJoint2DComponent.Length; + + out << YAML::Key << "EnableSpring" << YAML::Value << distanceJoint2DComponent.EnableSpring; + out << YAML::Key << "LowerSpringForce" << YAML::Value << distanceJoint2DComponent.LowerSpringForce; + out << YAML::Key << "UpperSpringForce" << YAML::Value << distanceJoint2DComponent.UpperSpringForce; + out << YAML::Key << "Hertz" << YAML::Value << distanceJoint2DComponent.Hertz; + out << YAML::Key << "DampingRatio" << YAML::Value << distanceJoint2DComponent.DampingRatio; + + out << YAML::Key << "EnableLimit" << YAML::Value << distanceJoint2DComponent.EnableLimit; + out << YAML::Key << "MinLength" << YAML::Value << distanceJoint2DComponent.MinLength; + out << YAML::Key << "MaxLength" << YAML::Value << distanceJoint2DComponent.MaxLength; + + out << YAML::Key << "EnableMotor" << YAML::Value << distanceJoint2DComponent.EnableMotor; + out << YAML::Key << "MaxMotorForce" << YAML::Value << distanceJoint2DComponent.MaxMotorForce; + out << YAML::Key << "MotorSpeed" << YAML::Value << distanceJoint2DComponent.MotorSpeed; + + out << YAML::EndMap; // CircleBollider2DComponent + } + + if (entity.HasComponent()) + { + out << YAML::Key << "RevoluteJoint2DComponent"; + out << YAML::BeginMap; + + const auto& component = entity.GetComponent(); + out << YAML::Key << "ConnectedBody" << YAML::Value << component.ConnectedBody; + out << YAML::Key << "CollideConnected" << YAML::Value << component.CollideConnected; + out << YAML::Key << "LocalAnchorA" << YAML::Value << component.LocalAnchorA; + out << YAML::Key << "LocalAnchorB" << YAML::Value << component.LocalAnchorB; + + out << YAML::Key << "TargetAngle" << YAML::Value << component.TargetAngle; + out << YAML::Key << "EnableSpring" << YAML::Value << component.EnableSpring; + out << YAML::Key << "Hertz" << YAML::Value << component.Hertz; + out << YAML::Key << "DampingRatio" << YAML::Value << component.DampingRatio; + + out << YAML::Key << "EnableLimit" << YAML::Value << component.EnableLimit; + out << YAML::Key << "LowerAngle" << YAML::Value << component.LowerAngle; + out << YAML::Key << "UpperAngle" << YAML::Value << component.UpperAngle; + + out << YAML::Key << "EnableMotor" << YAML::Value << component.EnableMotor; + out << YAML::Key << "MotorSpeed" << YAML::Value << component.MotorSpeed; + out << YAML::Key << "MaxMotorTorque" << YAML::Value << component.MaxMotorTorque; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "PrismaticJoint2DComponent"; + out << YAML::BeginMap; + + const auto& component = entity.GetComponent(); + out << YAML::Key << "ConnectedBody" << YAML::Value << component.ConnectedBody; + out << YAML::Key << "CollideConnected" << YAML::Value << component.CollideConnected; + out << YAML::Key << "LocalAnchorA" << YAML::Value << component.LocalAnchorA; + out << YAML::Key << "LocalAnchorB" << YAML::Value << component.LocalAnchorB; + out << YAML::Key << "LocalAxisA" << YAML::Value << component.LocalAxisA; + + out << YAML::Key << "EnableSpring" << YAML::Value << component.EnableSpring; + out << YAML::Key << "Hertz" << YAML::Value << component.Hertz; + out << YAML::Key << "DampingRatio" << YAML::Value << component.DampingRatio; + out << YAML::Key << "TargetTranslation" << YAML::Value << component.TargetTranslation; + + out << YAML::Key << "EnableLimit" << YAML::Value << component.EnableLimit; + out << YAML::Key << "LowerTranslation" << YAML::Value << component.LowerTranslation; + out << YAML::Key << "UpperTranslation" << YAML::Value << component.UpperTranslation; + + out << YAML::Key << "EnableMotor" << YAML::Value << component.EnableMotor; + out << YAML::Key << "MotorSpeed" << YAML::Value << component.MotorSpeed; + out << YAML::Key << "MaxMotorForce" << YAML::Value << component.MaxMotorForce; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "WeldJoint2DComponent"; + out << YAML::BeginMap; + + const auto& component = entity.GetComponent(); + out << YAML::Key << "ConnectedBody" << YAML::Value << component.ConnectedBody; + out << YAML::Key << "CollideConnected" << YAML::Value << component.CollideConnected; + out << YAML::Key << "LocalAnchorA" << YAML::Value << component.LocalAnchorA; + out << YAML::Key << "LocalAnchorB" << YAML::Value << component.LocalAnchorB; + + out << YAML::Key << "LinearHertz" << YAML::Value << component.LinearHertz; + out << YAML::Key << "AngularHertz" << YAML::Value << component.AngularHertz; + out << YAML::Key << "LinearDampingRatio" << YAML::Value << component.LinearDampingRatio; + out << YAML::Key << "AngularDampingRatio" << YAML::Value << component.AngularDampingRatio; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) { out << YAML::Key << "RigidBodyComponent"; @@ -825,6 +928,91 @@ namespace Prism component.Friction = boxCollider2DComponent["Friction"] ? boxCollider2DComponent["Friction"].as() : 1.0f; } + if (auto distanceJoint2DComponent = entity["DistanceJoint2DComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.ConnectedBody = distanceJoint2DComponent["ConnectedBody"].as(); + component.LocalAnchorA = distanceJoint2DComponent["LocalAnchorA"].as(); + component.LocalAnchorB = distanceJoint2DComponent["LocalAnchorB"].as(); + + component.Length = distanceJoint2DComponent["Length"].as(); + + component.EnableSpring = distanceJoint2DComponent["EnableSpring"].as(); + + component.LowerSpringForce = distanceJoint2DComponent["LowerSpringForce"].as(); + component.UpperSpringForce = distanceJoint2DComponent["UpperSpringForce"].as(); + component.Hertz = distanceJoint2DComponent["Hertz"].as(); + component.DampingRatio = distanceJoint2DComponent["DampingRatio"].as(); + + component.EnableLimit = distanceJoint2DComponent["EnableLimit"].as(); + component.MinLength = distanceJoint2DComponent["MinLength"].as(); + component.MaxLength = distanceJoint2DComponent["MaxLength"].as(); + + component.EnableMotor = distanceJoint2DComponent["EnableMotor"].as(); + component.MaxMotorForce = distanceJoint2DComponent["MaxMotorForce"].as(); + component.MotorSpeed = distanceJoint2DComponent["MotorSpeed"].as(); + } + + if (auto revoluteJoint = entity["RevoluteJoint2DComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.ConnectedBody = revoluteJoint["ConnectedBody"].as(); + component.CollideConnected = revoluteJoint["CollideConnected"].as(); + component.LocalAnchorA = revoluteJoint["LocalAnchorA"].as(); + component.LocalAnchorB = revoluteJoint["LocalAnchorB"].as(); + + component.TargetAngle = revoluteJoint["TargetAngle"].as(); + component.EnableSpring = revoluteJoint["EnableSpring"].as(); + component.Hertz = revoluteJoint["Hertz"].as(); + component.DampingRatio = revoluteJoint["DampingRatio"].as(); + + component.EnableLimit = revoluteJoint["EnableLimit"].as(); + component.LowerAngle = revoluteJoint["LowerAngle"].as(); + component.UpperAngle = revoluteJoint["UpperAngle"].as(); + + component.EnableMotor = revoluteJoint["EnableMotor"].as(); + component.MotorSpeed = revoluteJoint["MotorSpeed"].as(); + component.MaxMotorTorque = revoluteJoint["MaxMotorTorque"].as(); + } + + if (auto prismaticJoint = entity["PrismaticJoint2DComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.ConnectedBody = prismaticJoint["ConnectedBody"].as(); + component.CollideConnected = prismaticJoint["CollideConnected"].as(); + component.LocalAnchorA = prismaticJoint["LocalAnchorA"].as(); + component.LocalAnchorB = prismaticJoint["LocalAnchorB"].as(); + component.LocalAxisA = prismaticJoint["LocalAxisA"].as(); + + component.EnableSpring = prismaticJoint["EnableSpring"].as(); + component.Hertz = prismaticJoint["Hertz"].as(); + component.DampingRatio = prismaticJoint["DampingRatio"].as(); + component.TargetTranslation = prismaticJoint["TargetTranslation"].as(); + + component.EnableLimit = prismaticJoint["EnableLimit"].as(); + component.LowerTranslation = prismaticJoint["LowerTranslation"].as(); + component.UpperTranslation = prismaticJoint["UpperTranslation"].as(); + + component.EnableMotor = prismaticJoint["EnableMotor"].as(); + component.MotorSpeed = prismaticJoint["MotorSpeed"].as(); + component.MaxMotorForce = prismaticJoint["MaxMotorForce"].as(); + } + + if (auto weldJoint = entity["WeldJoint2DComponent"]) + { + auto& component = deserializedEntity.AddComponent(); + component.ConnectedBody = weldJoint["ConnectedBody"].as(); + component.CollideConnected = weldJoint["CollideConnected"].as(); + component.LocalAnchorA = weldJoint["LocalAnchorA"].as(); + component.LocalAnchorB = weldJoint["LocalAnchorB"].as(); + + component.LinearHertz = weldJoint["LinearHertz"].as(); + component.AngularHertz = weldJoint["AngularHertz"].as(); + component.LinearDampingRatio = weldJoint["LinearDampingRatio"].as(); + component.AngularDampingRatio = weldJoint["AngularDampingRatio"].as(); + } + + if (auto circleCollider2DComponent = entity["CircleCollider2DComponent"]) { auto& component = deserializedEntity.AddComponent();