CreateRagdoll.cpp 11 KB

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