diff --git a/Editor/HumanoidWindow.cpp b/Editor/HumanoidWindow.cpp index 3af041ce9..4d8c1d10f 100644 --- a/Editor/HumanoidWindow.cpp +++ b/Editor/HumanoidWindow.cpp @@ -60,7 +60,19 @@ void HumanoidWindow::Create(EditorComponent* _editor) })); AddWidget(&lookatEntityCombo); - ragdollCheckBox.Create("Ragdoll: "); + ragdollDisabledCheckBox.Create("Ragdoll Disabled: "); + ragdollDisabledCheckBox.SetTooltip("Completely disable ragdoll physics creation for this humanoid.\nUseful for cases where the humanoid skeleton should not have any physics interaction."); + ragdollDisabledCheckBox.OnClick(forEachSelected([this] (auto humanoid, auto args) { + humanoid->SetRagdollDisabled(args.bValue); + if (args.bValue) + { + humanoid->ragdoll = {}; // immediately delete ragdoll if disabled + } + ragdollCheckBox.SetEnabled(!args.bValue); + })); + AddWidget(&ragdollDisabledCheckBox); + + ragdollCheckBox.Create("Ragdoll Physics Enabled: "); ragdollCheckBox.SetTooltip("Activate dynamic ragdoll physics.\nNote that kinematic ragdoll physics is always active (ragdoll is animation-driven/kinematic by default).\nNote that scaling humanoid will disable ragdoll physics and you need to re-enable if you want to."); ragdollCheckBox.OnClick(forEachSelected([] (auto humanoid, auto args) { humanoid->SetRagdollPhysicsEnabled(args.bValue); @@ -318,7 +330,9 @@ void HumanoidWindow::SetEntity(Entity entity) if (humanoid != nullptr) { lookatCheckBox.SetCheck(humanoid->IsLookAtEnabled()); + ragdollDisabledCheckBox.SetCheck(humanoid->IsRagdollDisabled()); ragdollCheckBox.SetCheck(humanoid->IsRagdollPhysicsEnabled()); + ragdollCheckBox.SetEnabled(!humanoid->IsRagdollDisabled()); capsuleShadowCheckBox.SetCheck(humanoid->IsCapsuleShadowDisabled()); headRotMaxXSlider.SetValue(wi::math::RadiansToDegrees(humanoid->head_rotation_max.x)); headRotMaxYSlider.SetValue(wi::math::RadiansToDegrees(humanoid->head_rotation_max.y)); @@ -602,6 +616,7 @@ void HumanoidWindow::ResizeLayout() layout.add_right(lookatCheckBox); lookatMouseCheckBox.SetPos(XMFLOAT2(lookatCheckBox.GetPos().x - 120, lookatCheckBox.GetPos().y)); layout.add(lookatEntityCombo); + layout.add_right(ragdollDisabledCheckBox); layout.add_right(ragdollCheckBox); layout.add_right(capsuleShadowCheckBox); layout.add(headRotMaxXSlider); diff --git a/Editor/HumanoidWindow.h b/Editor/HumanoidWindow.h index a0d3425bc..dcec9fbfd 100644 --- a/Editor/HumanoidWindow.h +++ b/Editor/HumanoidWindow.h @@ -17,6 +17,7 @@ public: wi::gui::CheckBox lookatMouseCheckBox; wi::gui::CheckBox lookatCheckBox; wi::gui::ComboBox lookatEntityCombo; + wi::gui::CheckBox ragdollDisabledCheckBox; wi::gui::CheckBox ragdollCheckBox; wi::gui::CheckBox capsuleShadowCheckBox; wi::gui::Slider headRotMaxXSlider; diff --git a/WickedEngine/wiPhysics_Jolt.cpp b/WickedEngine/wiPhysics_Jolt.cpp index fc19612a3..1a1f877ee 100644 --- a/WickedEngine/wiPhysics_Jolt.cpp +++ b/WickedEngine/wiPhysics_Jolt.cpp @@ -2175,6 +2175,11 @@ namespace wi::physics }); wi::jobsystem::Dispatch(ctx, (uint32_t)scene.humanoids.GetCount(), 1, [&scene](wi::jobsystem::JobArgs args) { HumanoidComponent& humanoid = scene.humanoids[args.jobIndex]; + if (humanoid.IsRagdollDisabled()) + { + humanoid.ragdoll = {}; // delete ragdoll if it was previously created + return; + } Entity humanoidEntity = scene.humanoids.GetEntity(args.jobIndex); float scale = 1; if (scene.transforms.Contains(humanoidEntity)) diff --git a/WickedEngine/wiScene_BindLua.cpp b/WickedEngine/wiScene_BindLua.cpp index 3b2596d59..4722a0ce2 100644 --- a/WickedEngine/wiScene_BindLua.cpp +++ b/WickedEngine/wiScene_BindLua.cpp @@ -7767,6 +7767,8 @@ Luna::FunctionType HumanoidComponent_BindLua::methods lunamethod(HumanoidComponent_BindLua, SetLookAt), lunamethod(HumanoidComponent_BindLua, SetRagdollPhysicsEnabled), lunamethod(HumanoidComponent_BindLua, IsRagdollPhysicsEnabled), + lunamethod(HumanoidComponent_BindLua, SetRagdollDisabled), + lunamethod(HumanoidComponent_BindLua, IsRagdollDisabled), lunamethod(HumanoidComponent_BindLua, SetIntersectionDisabled), lunamethod(HumanoidComponent_BindLua, IsIntersectionDisabled), lunamethod(HumanoidComponent_BindLua, SetRagdollFatness), @@ -7860,6 +7862,24 @@ int HumanoidComponent_BindLua::IsRagdollPhysicsEnabled(lua_State* L) wi::lua::SSetBool(L, component->IsRagdollPhysicsEnabled()); return 1; } +int HumanoidComponent_BindLua::SetRagdollDisabled(lua_State* L) +{ + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + component->SetRagdollDisabled(wi::lua::SGetBool(L, 1)); + } + else + { + wi::lua::SError(L, "SetRagdollDisabled(bool value) not enough arguments!"); + } + return 0; +} +int HumanoidComponent_BindLua::IsRagdollDisabled(lua_State* L) +{ + wi::lua::SSetBool(L, component->IsRagdollDisabled()); + return 1; +} int HumanoidComponent_BindLua::SetIntersectionDisabled(lua_State* L) { int argc = wi::lua::SGetArgCount(L); diff --git a/WickedEngine/wiScene_BindLua.h b/WickedEngine/wiScene_BindLua.h index deefbd1f8..c62fea205 100644 --- a/WickedEngine/wiScene_BindLua.h +++ b/WickedEngine/wiScene_BindLua.h @@ -1919,6 +1919,8 @@ namespace wi::lua::scene int SetLookAt(lua_State* L); int SetRagdollPhysicsEnabled(lua_State* L); int IsRagdollPhysicsEnabled(lua_State* L); + int SetRagdollDisabled(lua_State* L); + int IsRagdollDisabled(lua_State* L); int SetIntersectionDisabled(lua_State* L); int IsIntersectionDisabled(lua_State* L); int SetRagdollFatness(lua_State* L); diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 70693385c..21c7a94ec 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -2229,6 +2229,7 @@ namespace wi::scene RAGDOLL_PHYSICS = 1 << 1, DISABLE_INTERSECTION = 1 << 2, DISABLE_CAPSULE_SHADOW = 1 << 3, + RAGDOLL_DISABLED = 1 << 4, }; uint32_t _flags = LOOKAT; @@ -2308,11 +2309,13 @@ namespace wi::scene constexpr bool IsRagdollPhysicsEnabled() const { return _flags & RAGDOLL_PHYSICS; } constexpr bool IsIntersectionDisabled() const { return _flags & DISABLE_INTERSECTION; } constexpr bool IsCapsuleShadowDisabled() const { return _flags & DISABLE_CAPSULE_SHADOW; } + constexpr bool IsRagdollDisabled() const { return _flags & RAGDOLL_DISABLED; } constexpr void SetLookAtEnabled(bool value = true) { if (value) { _flags |= LOOKAT; } else { _flags &= ~LOOKAT; } } constexpr void SetRagdollPhysicsEnabled(bool value = true) { if (value) { _flags |= RAGDOLL_PHYSICS; } else { _flags &= ~RAGDOLL_PHYSICS; } } constexpr void SetIntersectionDisabled(bool value = true) { if (value) { _flags |= DISABLE_INTERSECTION; } else { _flags &= ~DISABLE_INTERSECTION; } } constexpr void SetCapsuleShadowDisabled(bool value = true) { if (value) { _flags |= DISABLE_CAPSULE_SHADOW; } else { _flags &= ~DISABLE_CAPSULE_SHADOW; } } + constexpr void SetRagdollDisabled(bool value = true) { if (value) { _flags |= RAGDOLL_DISABLED; } else { _flags &= ~RAGDOLL_DISABLED; } } XMFLOAT2 head_rotation_max = XMFLOAT2(XM_PI / 3.0f, XM_PI / 6.0f); XMFLOAT2 eye_rotation_max = XMFLOAT2(XM_PI / 20.0f, XM_PI / 20.0f);