CreateRagdoll.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Urho3D/Urho3D.h>
  23. #include <Urho3D/Graphics/AnimatedModel.h>
  24. #include <Urho3D/IO/Log.h>
  25. #include <Urho3D/Physics/PhysicsEvents.h>
  26. #include <Urho3D/Physics/RigidBody.h>
  27. #include <Urho3D/Scene/Node.h>
  28. #include "CreateRagdoll.h"
  29. #include <Urho3D/DebugNew.h>
  30. CreateRagdoll::CreateRagdoll(Context* context) :
  31. Component(context)
  32. {
  33. }
  34. void CreateRagdoll::OnNodeSet(Node* node)
  35. {
  36. // If the node pointer is non-null, this component has been created into a scene node. Subscribe to physics collisions that
  37. // concern this scene node
  38. if (node)
  39. SubscribeToEvent(node, E_NODECOLLISION, HANDLER(CreateRagdoll, HandleNodeCollision));
  40. }
  41. void CreateRagdoll::HandleNodeCollision(StringHash eventType, VariantMap& eventData)
  42. {
  43. using namespace NodeCollision;
  44. // Get the other colliding body, make sure it is moving (has nonzero mass)
  45. RigidBody* otherBody = static_cast<RigidBody*>(eventData[P_OTHERBODY].GetPtr());
  46. if (otherBody->GetMass() > 0.0f)
  47. {
  48. // We do not need the physics components in the AnimatedModel's root scene node anymore
  49. node_->RemoveComponent<RigidBody>();
  50. node_->RemoveComponent<CollisionShape>();
  51. // Create RigidBody & CollisionShape components to bones
  52. CreateRagdollBone("Bip01_Pelvis", SHAPE_BOX, Vector3(0.3f, 0.2f, 0.25f), Vector3(0.0f, 0.0f, 0.0f),
  53. Quaternion(0.0f, 0.0f, 0.0f));
  54. CreateRagdollBone("Bip01_Spine1", SHAPE_BOX, Vector3(0.35f, 0.2f, 0.3f), Vector3(0.15f, 0.0f, 0.0f),
  55. Quaternion(0.0f, 0.0f, 0.0f));
  56. CreateRagdollBone("Bip01_L_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f),
  57. Quaternion(0.0f, 0.0f, 90.0f));
  58. CreateRagdollBone("Bip01_R_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f),
  59. Quaternion(0.0f, 0.0f, 90.0f));
  60. CreateRagdollBone("Bip01_L_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f),
  61. Quaternion(0.0f, 0.0f, 90.0f));
  62. CreateRagdollBone("Bip01_R_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f),
  63. Quaternion(0.0f, 0.0f, 90.0f));
  64. CreateRagdollBone("Bip01_Head", SHAPE_BOX, Vector3(0.2f, 0.2f, 0.2f), Vector3(0.1f, 0.0f, 0.0f),
  65. Quaternion(0.0f, 0.0f, 0.0f));
  66. CreateRagdollBone("Bip01_L_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f),
  67. Quaternion(0.0f, 0.0f, 90.0f));
  68. CreateRagdollBone("Bip01_R_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f),
  69. Quaternion(0.0f, 0.0f, 90.0f));
  70. CreateRagdollBone("Bip01_L_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f),
  71. Quaternion(0.0f, 0.0f, 90.0f));
  72. CreateRagdollBone("Bip01_R_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f),
  73. Quaternion(0.0f, 0.0f, 90.0f));
  74. // Create Constraints between bones
  75. CreateRagdollConstraint("Bip01_L_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD,
  76. Vector2(45.0f, 45.0f), Vector2::ZERO);
  77. CreateRagdollConstraint("Bip01_R_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD,
  78. Vector2(45.0f, 45.0f), Vector2::ZERO);
  79. CreateRagdollConstraint("Bip01_L_Calf", "Bip01_L_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  80. Vector2(90.0f, 0.0f), Vector2::ZERO);
  81. CreateRagdollConstraint("Bip01_R_Calf", "Bip01_R_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  82. Vector2(90.0f, 0.0f), Vector2::ZERO);
  83. CreateRagdollConstraint("Bip01_Spine1", "Bip01_Pelvis", CONSTRAINT_HINGE, Vector3::FORWARD, Vector3::FORWARD,
  84. Vector2(45.0f, 0.0f), Vector2(-10.0f, 0.0f));
  85. CreateRagdollConstraint("Bip01_Head", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::LEFT, Vector3::LEFT,
  86. Vector2(0.0f, 30.0f), Vector2::ZERO);
  87. CreateRagdollConstraint("Bip01_L_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP,
  88. Vector2(45.0f, 45.0f), Vector2::ZERO, false);
  89. CreateRagdollConstraint("Bip01_R_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP,
  90. Vector2(45.0f, 45.0f), Vector2::ZERO, false);
  91. CreateRagdollConstraint("Bip01_L_Forearm", "Bip01_L_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  92. Vector2(90.0f, 0.0f), Vector2::ZERO);
  93. CreateRagdollConstraint("Bip01_R_Forearm", "Bip01_R_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  94. Vector2(90.0f, 0.0f), Vector2::ZERO);
  95. // Disable keyframe animation from all bones so that they will not interfere with the ragdoll
  96. AnimatedModel* model = GetComponent<AnimatedModel>();
  97. Skeleton& skeleton = model->GetSkeleton();
  98. for (unsigned i = 0; i < skeleton.GetNumBones(); ++i)
  99. skeleton.GetBone(i)->animated_ = false;
  100. // Finally remove self from the scene node. Note that this must be the last operation performed in the function
  101. Remove();
  102. }
  103. }
  104. void CreateRagdoll::CreateRagdollBone(const String& boneName, ShapeType type, const Vector3& size, const Vector3& position,
  105. const Quaternion& rotation)
  106. {
  107. // Find the correct child scene node recursively
  108. Node* boneNode = node_->GetChild(boneName, true);
  109. if (!boneNode)
  110. {
  111. LOGWARNING("Could not find bone " + boneName + " for creating ragdoll physics components");
  112. return;
  113. }
  114. RigidBody* body = boneNode->CreateComponent<RigidBody>();
  115. // Set mass to make movable
  116. body->SetMass(1.0f);
  117. // Set damping parameters to smooth out the motion
  118. body->SetLinearDamping(0.05f);
  119. body->SetAngularDamping(0.85f);
  120. // Set rest thresholds to ensure the ragdoll rigid bodies come to rest to not consume CPU endlessly
  121. body->SetLinearRestThreshold(1.5f);
  122. body->SetAngularRestThreshold(2.5f);
  123. CollisionShape* shape = boneNode->CreateComponent<CollisionShape>();
  124. // We use either a box or a capsule shape for all of the bones
  125. if (type == SHAPE_BOX)
  126. shape->SetBox(size, position, rotation);
  127. else
  128. shape->SetCapsule(size.x_, size.y_, position, rotation);
  129. }
  130. void CreateRagdoll::CreateRagdollConstraint(const String& boneName, const String& parentName, ConstraintType type,
  131. const Vector3& axis, const Vector3& parentAxis, const Vector2& highLimit, const Vector2& lowLimit,
  132. bool disableCollision)
  133. {
  134. Node* boneNode = node_->GetChild(boneName, true);
  135. Node* parentNode = node_->GetChild(parentName, true);
  136. if (!boneNode)
  137. {
  138. LOGWARNING("Could not find bone " + boneName + " for creating ragdoll constraint");
  139. return;
  140. }
  141. if (!parentNode)
  142. {
  143. LOGWARNING("Could not find bone " + parentName + " for creating ragdoll constraint");
  144. return;
  145. }
  146. Constraint* constraint = boneNode->CreateComponent<Constraint>();
  147. constraint->SetConstraintType(type);
  148. // Most of the constraints in the ragdoll will work better when the connected bodies don't collide against each other
  149. constraint->SetDisableCollision(disableCollision);
  150. // The connected body must be specified before setting the world position
  151. constraint->SetOtherBody(parentNode->GetComponent<RigidBody>());
  152. // Position the constraint at the child bone we are connecting
  153. constraint->SetWorldPosition(boneNode->GetWorldPosition());
  154. // Configure axes and limits
  155. constraint->SetAxis(axis);
  156. constraint->SetOtherAxis(parentAxis);
  157. constraint->SetHighLimit(highLimit);
  158. constraint->SetLowLimit(lowLimit);
  159. }