/// <summary> /// Ragdoll character /// </summary> private void RagdollIn() { ActivateRagdollParts(true); animator.enabled = false; ragdollState = RagdollState.Ragdolled; ApplyVelocity(controller.GetVelocity()); }
/// <summary> /// Smoothly translate to animator's bone positions when character stops falling /// </summary> private void RagdollOut() { if (_state == RagdollState.Ragdolled) { _state = RagdollState.WaitStablePosition; } }
// Unity method for physics update. void FixedUpdate() { // Apply animation following animFollow.FollowAnimation(); // print(currentNumberOfCollisions); // print(animFollow.forceCoefficient); state = GetRagdollState(); switch (state) { case RagdollState.DEAD: currentDeadStep += Time.fixedDeltaTime; if (currentDeadStep >= deadTime) { ComeAlive(); } break; case RagdollState.LOOSING_STRENGTH: LooseStrength(); break; case RagdollState.GAINING_STRENGTH: GainStrength(); break; case RagdollState.FOLLOWING_ANIMATION: break; default: break; } }
public void StartMecanim() { // if we're not in a ragdoll state if (state != RagdollState.ragdolled) { // no need to transition to mecanim return; } //Transition from ragdolled to animated through the blendToAnim state setKinematic(true); //disable gravity etc. ragdollingEndTime = Time.time; //store the state change time animator.enabled = true; //enable animation state = RagdollState.blendToAnim; //Store the ragdolled position for blending foreach (BodyPart b in bodyParts) { b.storedRotation = b.transform.rotation; b.storedPosition = b.transform.position; } //Remember some key positions ragdolledFeetPosition = 0.5f * (animator.GetBoneTransform(HumanBodyBones.LeftToes).position + animator.GetBoneTransform(HumanBodyBones.RightToes).position); ragdolledHeadPosition = animator.GetBoneTransform(HumanBodyBones.Head).position; ragdolledHipPosition = animator.GetBoneTransform(HumanBodyBones.Hips).position; }
public void StartRagdoll() { // if we're not in an animation state if (state != RagdollState.animated) { // no need to transition to ragdoll return; } //Transition from animated to ragdolled setKinematic(false); //allow the ragdoll RigidBodies to react to the environment animator.enabled = false; //disable animation // turn off NavMeshAgent if it exists if (GetComponent<NavMeshAgent>() != null) { GetComponent<NavMeshAgent>().enabled = false; // disable navigation agent } // turn off CapsuleCollider if it exists if (GetComponent<CapsuleCollider>() != null && GetComponent<CapsuleCollider>().enabled) { GetComponent<CapsuleCollider>().enabled = false; } // turn off CapsuleCollider if it exists if (GetComponent<Rigidbody>() != null) { GetComponent<Rigidbody>().isKinematic = true; } state = RagdollState.ragdolled; }
private void GetUp() { ragdollingEndTime = Time.time; animator.enabled = true; ragdollState = RagdollState.BlendToAnim; storedHipsPositionPrivAnim = Vector3.zero; storedHipsPositionPrivBlend = Vector3.zero; storedHipsPosition = hipsTransform.position; Vector3 shiftPos = hipsTransform.position - transform.position; shiftPos.y = GetDistanceToFloor(shiftPos.y); MoveNodeWithoutChildren(shiftPos); for (int i = 0; i < transformComponents.Count; i++) { TransformComponent tc = transformComponents[i]; tc.SetStoredRotation(tc.GetTransform().localRotation); tc.SetRotation(tc.GetTransform().localRotation); tc.SetStoredPosition(tc.GetTransform().localPosition); tc.SetPosition(tc.GetTransform().localPosition); } string getUpAnim = CheckIfLieOnBack() ? animationGetUpFromBack : animationGetUpFromBelly; animator.Play(getUpAnim, 0, 0); ActivateRagdollParts(false); }
void LateUpdate() { if (_state == RagdollState.Blending) { if (Time.time <= _ragdollEndTime + _toGetUpTransitionTime) { //If we are waiting for Mecanim to start playing the get up animations, update the root of the mecanim //character to the best match with the ragdoll Vector3 animatedToRagdolled = _ragdolledHipPosition - _animController.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition = transform.position + animatedToRagdolled; //Now cast a ray from the computed position downwards and find the highest hit that does not belong to the character RaycastHit[] hits = Physics.RaycastAll(new Ray(newRootPosition, Vector3.down)); newRootPosition.y = 0; foreach (RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position = newRootPosition; //Get body orientation in ground plane for both the ragdolled pose and the animated get up pose Vector3 ragdolledDirection = _ragdolledHeadPosition - _ragdolledFeetPosition; ragdolledDirection.y = 0; Vector3 meanFeetPosition = 0.5f * (_animController.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animController.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection = _animController.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y = 0; //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright, //hence setting the y components of the vectors to zero. transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdolledDirection.normalized); } float blend = Mathf.Clamp01(1.0f - (Time.time - _ragdollEndTime - _toGetUpTransitionTime) / BlendTime); foreach (var l in _limbs) { if (l.Transform != transform) //this if is to prevent us from modifying the root of the character, only the actual body parts //position is only interpolated for the hips { if (l.Transform == _animController.GetBoneTransform(HumanBodyBones.Hips)) { l.Transform.position = Vector3.Lerp(l.Transform.position, l.Position, blend); } //rotation is interpolated for all body parts l.Transform.rotation = Quaternion.Slerp(l.Transform.rotation, l.Rotation, blend); } } //if the ragdoll blend amount has decreased to zero, move to animated state if (blend == 0) { _state = RagdollState.Animated; return; } } }
void TransitionToAnimator() { if (Time.time <= ragdollingEndTime + mecanimToGetUpTransitionTime) { //If we are waiting for Mecanim to start playing the get up animations, update the root of the mecanim //character to the best match with the ragdoll Vector3 animatedToRagdolled = ragdolledHipPosition - animator.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition = transform.position + animatedToRagdolled; //Now cast a ray from the computed position downwards and find the highest hit that does not belong to the character RaycastHit[] hits = Physics.RaycastAll(new Ray(newRootPosition, Vector3.down)); newRootPosition.y = 0; foreach (RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position = newRootPosition; //Get body orientation in ground plane for both the ragdolled pose and the animated get up pose Vector3 ragdolledDirection = ragdolledHeadPosition - ragdolledFeetPosition; ragdolledDirection.y = 0; Vector3 meanFeetPosition = 0.5f * (animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + animator.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection = animator.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y = 0; //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright, //hence setting the y components of the vectors to zero. transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdolledDirection.normalized); } //compute the ragdoll blend amount in the range 0...1 float ragdollBlendAmount = 1.0f - (Time.time - ragdollingEndTime - mecanimToGetUpTransitionTime) / ragdollToMecanimBlendTime; ragdollBlendAmount = Mathf.Clamp01(ragdollBlendAmount); //In LateUpdate(), Mecanim has already updated the body pose according to the animations. //To enable smooth transitioning from a ragdoll to animation, we lerp the position of the hips //and slerp all the rotations towards the ones stored when ending the ragdolling foreach (BodyPart b in bodyParts) { if (b.transform != transform) { //this if is to prevent us from modifying the root of the character, only the actual body parts //position is only interpolated for the hips if (b.transform == animator.GetBoneTransform(HumanBodyBones.Hips)) b.transform.position = Vector3.Lerp(b.transform.position, b.storedPosition, ragdollBlendAmount); //rotation is interpolated for all body parts b.transform.rotation = Quaternion.Slerp(b.transform.rotation, b.storedRotation, ragdollBlendAmount); } } //if the ragdoll blend amount has decreased to zero, move to animated state if (ragdollBlendAmount == 0) { state = RagdollState.animated; } }
/// <summary> /// Ragdoll character /// </summary> private void RagdollIn() { //Transition from animated to ragdolled ActivateRagdollParts(true); // allow the ragdoll RigidBodies to react to the environment _anim.enabled = false; // disable animation _state = RagdollState.Ragdolled; ApplyVelocity(_bzRagdollCharacter.CharacterVelocity); }
public void changeState(RagdollState newState) { lock (stateLock) { if (rState != newState) { rState = newState; } } }
void LateUpdate() { anim.SetBool("GetUpFromBelly", false); anim.SetBool("GetUpFromBack", false); if (state == RagdollState.blendToAnim) { if (Time.time <= ragdollingEndTime + mecanimToGetUpTransitionTime) { Vector3 animatedToRagdolled = ragdolledHipPosition - anim.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition = transform.position + animatedToRagdolled; RaycastHit[] hits = Physics.RaycastAll(new Ray(newRootPosition, Vector3.down)); newRootPosition.y = 0; foreach (RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position = newRootPosition; Vector3 ragdolledDirection = ragdolledHeadPosition - ragdolledFeetPosition; ragdolledDirection.y = 0; Vector3 meanFeetPosition = 0.5f * (anim.GetBoneTransform(HumanBodyBones.LeftFoot).position + anim.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection = anim.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y = 0; transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdolledDirection.normalized); } float ragdollBlendAmount = 1.0f - (Time.time - ragdollingEndTime - mecanimToGetUpTransitionTime) / ragdollToMecanimBlendTime; ragdollBlendAmount = Mathf.Clamp01(ragdollBlendAmount); foreach (BodyPart b in bodyParts) { if (b.transform != transform) { if (b.transform == anim.GetBoneTransform(HumanBodyBones.Hips)) { b.transform.position = Vector3.Lerp(b.transform.position, b.storedPosition, ragdollBlendAmount); } b.transform.rotation = Quaternion.Slerp(b.transform.rotation, b.storedRotation, ragdollBlendAmount); } } if (ragdollBlendAmount == 0) { state = RagdollState.animated; return; } } }
public void FullRagdoll() { rState = RagdollState.Ragdoll; animationRate = animationRange.min; //animationRange.min; maxJointSpring = jointSpringRange.min; follow = false; force = false; torque = false; }
public void FullAnimated() { rState = RagdollState.Animated; animationRate = animationRange.max; maxJointSpring = jointSpringRange.max; follow = true; force = true; torque = true; }
void LateUpdate() { if (_state != RagdollState.BlendToAnim) { return; } float ragdollBlendAmount = 1f - Mathf.InverseLerp( _ragdollingEndTime, _ragdollingEndTime + RagdollToMecanimBlendTime, Time.time); // In LateUpdate(), Mecanim has already updated the body pose according to the animations. // To enable smooth transitioning from a ragdoll to animation, we lerp the position of the hips // and slerp all the rotations towards the ones stored when ending the ragdolling if (_storedHipsPositionPrivBlend != _hipsTransform.position) { _storedHipsPositionPrivAnim = _hipsTransform.position; } _storedHipsPositionPrivBlend = Vector3.Lerp(_storedHipsPositionPrivAnim, _storedHipsPosition, ragdollBlendAmount); _hipsTransform.position = _storedHipsPositionPrivBlend; foreach (TransformComponent trComp in _transforms) { //rotation is interpolated for all body parts if (trComp.PrivRotation != trComp.Transform.localRotation) { trComp.PrivRotation = Quaternion.Slerp(trComp.Transform.localRotation, trComp.StoredRotation, ragdollBlendAmount); trComp.Transform.localRotation = trComp.PrivRotation; } //position is interpolated for all body parts if (trComp.PrivPosition != trComp.Transform.localPosition) { trComp.PrivPosition = Vector3.Slerp(trComp.Transform.localPosition, trComp.StoredPosition, ragdollBlendAmount); trComp.Transform.localPosition = trComp.PrivPosition; } } //if the ragdoll blend amount has decreased to zero, move to animated state if (Mathf.Abs(ragdollBlendAmount) < Mathf.Epsilon) { _state = RagdollState.Animated; } }
/// <summary> /// LateUpdate is called after all Update functions have been called. /// </summary> private void LateUpdate() { if (ragdollState != RagdollState.BlendToAnim) { return; } float ragdollBlendAmount = 1f - Mathf.InverseLerp( ragdollingEndTime, ragdollingEndTime + RAGDOLL_TO_MECANIM_BLEND_TIME, Time.time); if (storedHipsPositionPrivBlend != hipsTransform.position) { storedHipsPositionPrivAnim = hipsTransform.position; } storedHipsPositionPrivBlend = Vector3.Lerp(storedHipsPositionPrivAnim, storedHipsPosition, ragdollBlendAmount); hipsTransform.position = storedHipsPositionPrivBlend; for (int i = 0; i < transformComponents.Count; i++) { TransformComponent tc = transformComponents[i]; if (tc.GetRotation() != tc.GetTransform().localRotation) { tc.SetRotation(Quaternion.Slerp(tc.GetTransform().localRotation, tc.GetStoredRotation(), ragdollBlendAmount)); tc.GetTransform().localRotation = tc.GetRotation(); } if (tc.GetPosition() != tc.GetTransform().localPosition) { tc.SetPosition(Vector3.Slerp(tc.GetTransform().localPosition, tc.GetStoredPosition(), ragdollBlendAmount)); tc.GetTransform().localPosition = tc.GetPosition(); } } if (Mathf.Abs(ragdollBlendAmount) < Mathf.Epsilon) { ragdollState = RagdollState.Animated; } }
private void GetUp() { //Transition from ragdolled to animated through the blendToAnim state _ragdollingEndTime = Time.time; //store the state change time //_anim.SetFloat(_animatorForward, 0f); //_anim.SetFloat(_animatorTurn, 0f); _anim.enabled = true; //enable animation _state = RagdollState.BlendToAnim; _storedHipsPositionPrivAnim = Vector3.zero; _storedHipsPositionPrivBlend = Vector3.zero; _storedHipsPosition = _hipsTransform.position; // get distanse to floor Vector3 shiftPos = _hipsTransform.position - transform.position; shiftPos.y = GetDistanceToFloor(shiftPos.y); // shift and rotate character node without children MoveNodeWithoutChildren(shiftPos); //Store the ragdolled position for blending foreach (TransformComponent trComp in _transforms) { trComp.StoredRotation = trComp.Transform.localRotation; trComp.PrivRotation = trComp.Transform.localRotation; trComp.StoredPosition = trComp.Transform.localPosition; trComp.PrivPosition = trComp.Transform.localPosition; } //Initiate the get up animation string getUpAnim = CheckIfLieOnBack() ? _animationGetUpFromBack : _animationGetUpFromBelly; _anim.Play(getUpAnim, 0, 0); // you have to set time to 0, or if your animation will interrupt, next time animation starts from previous position ActivateRagdollParts(false); // disable gravity on ragdollParts. }
void LateUpdate() { //check for errors in state if(anim == null) { state = RagdollState.ragdolled; } //check if we're currently in the state that we should be if(state == RagdollState.ragdolled && GetComponent<RagdollTransitions>().boneParent.collider.enabled == false) { //set to ragdoll again GetComponent<RagdollTransitions>().boneParent.SetActive(true); setKinematic(false); //allow the ragdoll RigidBodies to react to the environment } //get back to our parents position and rotation transform.position = Vector3.Lerp( transform.position, transform.parent.position, 0.5f ); transform.rotation = Quaternion.Lerp( transform.rotation, transform.parent.rotation, 0.1f); if(anim == null) { return; } //Clear the get up animation controls so that we don't end up repeating the animations indefinitely anim.SetBool("GetUpFromBelly",false); anim.SetBool("GetUpFromBack",false); //Blending from ragdoll back to animated if (state==RagdollState.blendToAnim) { if (Time.time<=ragdollingEndTime+mecanimToGetUpTransitionTime) { //If we are waiting for Mecanim to start playing the get up animations, update the root of the mecanim //character to the best match with the ragdoll Vector3 animatedToRagdolled=ragdolledHipPosition-anim.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition=transform.position + animatedToRagdolled; //Now cast a ray from the computed position downwards and find the highest hit that does not belong to the character RaycastHit[] hits=Physics.RaycastAll(new Ray(newRootPosition,Vector3.down)); newRootPosition.y=0; foreach(RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y=Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position=newRootPosition; //Get body orientation in ground plane for both the ragdolled pose and the animated get up pose Vector3 ragdolledDirection=ragdolledHeadPosition-ragdolledFeetPosition; ragdolledDirection.y=0; Vector3 meanFeetPosition=0.5f*(anim.GetBoneTransform(HumanBodyBones.LeftFoot).position + anim.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection=anim.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y=0; //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright, //hence setting the y components of the vectors to zero. transform.rotation*=Quaternion.FromToRotation(animatedDirection.normalized,ragdolledDirection.normalized); } //compute the ragdoll blend amount in the range 0...1 float ragdollBlendAmount=1.0f-(Time.time-ragdollingEndTime-mecanimToGetUpTransitionTime)/ragdollToMecanimBlendTime; ragdollBlendAmount=Mathf.Clamp01(ragdollBlendAmount); //In LateUpdate(), Mecanim has already updated the body pose according to the animations. //To enable smooth transitioning from a ragdoll to animation, we lerp the position of the hips //and slerp all the rotations towards the ones stored when ending the ragdolling foreach (BodyPart b in bodyParts) { if (b.transform!=transform){ //this if is to prevent us from modifying the root of the character, only the actual body parts //position is only interpolated for the hips if (b.transform==anim.GetBoneTransform(HumanBodyBones.Hips)) b.transform.position=Vector3.Lerp(b.transform.position, b.storedPosition, ragdollBlendAmount); //rotation is interpolated for all body parts b.transform.rotation=Quaternion.Slerp(b.transform.rotation, b.storedRotation, ragdollBlendAmount); } } //if the ragdoll blend amount has decreased to zero, move to animated state if (ragdollBlendAmount==0) { state=RagdollState.animated; return; } } }
void LateUpdate() { if (animator.GetCurrentAnimatorStateInfo (2).IsName ("StandUp@FromBack")) { if (animator.GetCurrentAnimatorStateInfo (2).normalizedTime > 0.1f) { tpController._rigidbody.useGravity = true; tpController._rigidbody.isKinematic = false; tpController.capsuleCollider.enabled = true; } if (animator.GetCurrentAnimatorStateInfo (2).normalizedTime > 0.9f) animator.SetBool("GetUpFromBack",false); } if (animator.GetCurrentAnimatorStateInfo (2).IsName ("StandUp@FromBelly")) { if (animator.GetCurrentAnimatorStateInfo (2).normalizedTime > 0.1f) { tpController._rigidbody.useGravity = true; tpController._rigidbody.isKinematic = false; tpController.capsuleCollider.enabled = true; } if (animator.GetCurrentAnimatorStateInfo (2).normalizedTime > 0.9f) animator.SetBool("GetUpFromBelly",false); } //Blending from ragdoll back to animated if (state == RagdollState.blendToAnim) { if (Time.time <= ragdollingEndTime + mecanimToGetUpTransitionTime) { //If we are waiting for Mecanim to start playing the get up animations, update the root of the mecanim //character to the best match with the ragdoll Vector3 animatedToRagdolled = ragdolledHipPosition - animator.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition = transform.position + animatedToRagdolled; //Now cast a ray from the computed position downwards and find the highest hit that does not belong to the character RaycastHit[] hits = Physics.RaycastAll(new Ray(newRootPosition + Vector3.up,Vector3.down)); newRootPosition.y = 0; foreach(RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position = newRootPosition; //Get body orientation in ground plane for both the ragdolled pose and the animated get up pose Vector3 ragdolledDirection = ragdolledHeadPosition - ragdolledFeetPosition; ragdolledDirection.y = 0; Vector3 meanFeetPosition = 0.5f * (animator.GetBoneTransform(HumanBodyBones.LeftFoot).position + animator.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection = animator.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y = 0; //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright, //hence setting the y components of the vectors to zero. transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized,ragdolledDirection.normalized); } //compute the ragdoll blend amount in the range 0...1 float ragdollBlendAmount = 1.0f - (Time.time - ragdollingEndTime - mecanimToGetUpTransitionTime)/ragdollToMecanimBlendTime; ragdollBlendAmount = Mathf.Clamp01(ragdollBlendAmount); //In LateUpdate(), Mecanim has already updated the body pose according to the animations. //To enable smooth transitioning from a ragdoll to animation, we lerp the position of the hips //and slerp all the rotations towards the ones stored when ending the ragdolling foreach (BodyPart b in bodyParts) { if (b.transform!=transform) { //this if is to prevent us from modifying the root of the character, only the actual body parts //position is only interpolated for the hips if (b.transform == animator.GetBoneTransform(HumanBodyBones.Hips)) b.transform.position = Vector3.Lerp(b.transform.position, b.storedPosition, ragdollBlendAmount); //rotation is interpolated for all body parts b.transform.rotation = Quaternion.Slerp(b.transform.rotation, b.storedRotation, ragdollBlendAmount); } } //if the ragdoll blend amount has decreased to zero, move to animated state if (ragdollBlendAmount == 0) { state=RagdollState.animated; return; } } }
readonly float fallThreshold = 120f; //When this threshold is reached by impact force character will lose all control void ControllRagdoll() { //Check whether ragdoll or animated switch (rState) { case RagdollState.Animated: //1.Check if character is colliding with something. If not colliding break case //2.Check forces applied to character. - total collision force - main limbs total collision force - arms legs collision per limb etc. //3.If total collision force is bigger than thershold set state as ragdoll (character false) || if there is too much force on one limb (something collided with high speed) set state as ragdoll (character false) //4.If character did not fall and main limbs total collision bigger than threshold go to set state as goingRagdoll //if checks condition character will fall.After fall character will not retain full force until conditions satisfied (check case RagdollState.Ragdoll:) if (collisionCount > 0) { /*if((totalCollisionSpeed > 100f || (totalCollisionSpeed / collisionCount > 15f))) * { * // Debug.LogWarning(totalCollisionSpeed / collisionCount); * // Debug.LogWarning(collisionCount + "\n"); * * rState = RagdollState.Ragdoll; * FullRagdoll(); * } * else */ bool totalForceExceeds = ((totalCollisionSpeed > 100f || (totalCollisionSpeed / collisionCount > 15f))); bool mainLimbForceExceeds = (mainLimbsCollisionCount > 0 && (mainLimbsCollisionSpd / mainLimbsCollisionCount > 5f)); if (totalForceExceeds || mainLimbForceExceeds) { rState = RagdollState.GoingRagdoll; maximumImpact = totalCollisionSpeed; impactForce = totalCollisionSpeed; } } break; case RagdollState.GoingRagdoll: //Check if the character is still colliding. If not colliding set state as goingAnimated and break //if colliding ease up the ragdoll smoothly according to speed of collision //if characters animationRate is reached 0 set state as ragdoll //When main limbs collided with some force ease up the character. Smoothly decrease applied force, torque and decrease animationRate if (mainLimbsCollisionCount > 0) { //if GoingRagdoll returns true character is ragdoll if (GoingRagdoll(maximumImpact) && maximumImpact > fallThreshold) //if not ragdoll yet continue setting impactforce and easing up { FullRagdoll(); rState = RagdollState.Ragdoll; } impactForce = totalCollisionSpeed; //update maximum applied impact force each frame maximumImpact = (impactForce > maximumImpact) ? impactForce : maximumImpact; } else //character stopped colliding when going to ragdoll. Set state as going animated and break case { rState = RagdollState.GoingAnimated; } break; case RagdollState.Ragdoll: //Character will retain full force if this conditions satisfies //if maximumImpact is bigger than threshold character will use control untill collided to ground if (maximumImpact > fallThreshold && (collisionCount > 2 && rootBone.velocity.magnitude < 1f)) { maximumImpact = 0f; rState = RagdollState.Animated; FullAnimated(); } break; case RagdollState.GoingAnimated: if (GoingAnimated(maximumImpact)) { rState = RagdollState.Animated; FullAnimated(); } break; default: break; } //Reset total collision in each fixedUpdate totalCollisionSpeed = 0f; mainLimbsCollisionSpd = 0f; }
void ControllRagdoll() { //Debug.Log(groundCollidingFoot); //Check whether ragdoll or animated switch (rState) { case RagdollState.Animated: //1.Check if character is colliding with something. If not colliding break case //2.Check forces applied to character. - total collision force - main limbs total collision force - arms legs collision per limb etc. //3.If total collision force is bigger than thershold set state as ragdoll (character false) || if there is too much force on one limb (something collided with high speed) set state as ragdoll (character false) //4.If character did not fall and main limbs total collision bigger than threshold go to set state as goingRagdoll //if checks condition character will fall.After fall character will not retain full force until conditions satisfied (check case RagdollState.Ragdoll:) if (collisionCount > 0) { rState = RagdollState.Ragdoll; //FullRagdoll(); } break; case RagdollState.Ragdoll: //Character will retain full force if this conditions satisfies if (collisionCount > 0) { if (animationRate > 0.1f) { animationRate = Mathf.Lerp(animationRate, animationRange.min, totalCollisionSpeed / 1000f); maxJointSpring = Mathf.Lerp(maxJointSpring, jointSpringRange.min, totalCollisionSpeed / 1000f); } else { FullRagdoll(); } } else { if (animationRate < animationRange.max - 0.1f) { animationRate = Mathf.Lerp(animationRate, animationRange.max, 0.05f); maxJointSpring = Mathf.Lerp(maxJointSpring, jointSpringRange.max, 0.05f); } else { FullAnimated(); } } //if maximumImpact is bigger than threshold character will use control untill collided to ground //Debug.Log(collisionCount); if (rootBone.velocity.magnitude < 0.5f) { rState = RagdollState.Animated; FullAnimated(); } break; default: break; } //Reset total collision in each fixedUpdate totalCollisionSpeed = 0f; }
void LateUpdate() { if (_state == RagdollState.Blending) { if (Time.time <= _ragdollEndTime + _toGetUpTransitionTime) { //If we are waiting for Mecanim to start playing the get up animations, update the root of the mecanim //character to the best match with the ragdoll Vector3 animatedToRagdolled = _ragdolledHipPosition - _animController.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition = transform.position + animatedToRagdolled; //Now cast a ray from the computed position downwards and find the highest hit that does not belong to the character RaycastHit[] hits = Physics.RaycastAll(new Ray(newRootPosition, Vector3.down)); newRootPosition.y = 0; foreach (RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position = newRootPosition; //Get body orientation in ground plane for both the ragdolled pose and the animated get up pose Vector3 ragdolledDirection = _ragdolledHeadPosition - _ragdolledFeetPosition; ragdolledDirection.y = 0; Vector3 meanFeetPosition = 0.5f * (_animController.GetBoneTransform(HumanBodyBones.LeftFoot).position + _animController.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection = _animController.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y = 0; //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright, //hence setting the y components of the vectors to zero. transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdolledDirection.normalized); } float blend = Mathf.Clamp01(1.0f - (Time.time - _ragdollEndTime - _toGetUpTransitionTime) / BlendTime); foreach (var l in _limbs) { if (l.Transform != transform) { //this if is to prevent us from modifying the root of the character, only the actual body parts //position is only interpolated for the hips if (l.Transform == _animController.GetBoneTransform(HumanBodyBones.Hips)) l.Transform.position = Vector3.Lerp(l.Transform.position, l.Position, blend); //rotation is interpolated for all body parts l.Transform.rotation = Quaternion.Slerp(l.Transform.rotation, l.Rotation, blend); } } //if the ragdoll blend amount has decreased to zero, move to animated state if (blend == 0) { _state = RagdollState.Animated; return; } } }
void LateUpdate() { //check for errors in state if (anim == null) { state = RagdollState.ragdolled; } //check if we're currently in the state that we should be if (state == RagdollState.ragdolled && GetComponent <RagdollTransitions>().boneParent.collider.enabled == false) { //set to ragdoll again GetComponent <RagdollTransitions>().boneParent.SetActive(true); setKinematic(false); //allow the ragdoll RigidBodies to react to the environment } //get back to our parents position and rotation transform.position = Vector3.Lerp(transform.position, transform.parent.position, 0.5f); transform.rotation = Quaternion.Lerp(transform.rotation, transform.parent.rotation, 0.1f); if (anim == null) { return; } //Clear the get up animation controls so that we don't end up repeating the animations indefinitely anim.SetBool("GetUpFromBelly", false); anim.SetBool("GetUpFromBack", false); //Blending from ragdoll back to animated if (state == RagdollState.blendToAnim) { if (Time.time <= ragdollingEndTime + mecanimToGetUpTransitionTime) { //If we are waiting for Mecanim to start playing the get up animations, update the root of the mecanim //character to the best match with the ragdoll Vector3 animatedToRagdolled = ragdolledHipPosition - anim.GetBoneTransform(HumanBodyBones.Hips).position; Vector3 newRootPosition = transform.position + animatedToRagdolled; //Now cast a ray from the computed position downwards and find the highest hit that does not belong to the character RaycastHit[] hits = Physics.RaycastAll(new Ray(newRootPosition, Vector3.down)); newRootPosition.y = 0; foreach (RaycastHit hit in hits) { if (!hit.transform.IsChildOf(transform)) { newRootPosition.y = Mathf.Max(newRootPosition.y, hit.point.y); } } transform.position = newRootPosition; //Get body orientation in ground plane for both the ragdolled pose and the animated get up pose Vector3 ragdolledDirection = ragdolledHeadPosition - ragdolledFeetPosition; ragdolledDirection.y = 0; Vector3 meanFeetPosition = 0.5f * (anim.GetBoneTransform(HumanBodyBones.LeftFoot).position + anim.GetBoneTransform(HumanBodyBones.RightFoot).position); Vector3 animatedDirection = anim.GetBoneTransform(HumanBodyBones.Head).position - meanFeetPosition; animatedDirection.y = 0; //Try to match the rotations. Note that we can only rotate around Y axis, as the animated characted must stay upright, //hence setting the y components of the vectors to zero. transform.rotation *= Quaternion.FromToRotation(animatedDirection.normalized, ragdolledDirection.normalized); } //compute the ragdoll blend amount in the range 0...1 float ragdollBlendAmount = 1.0f - (Time.time - ragdollingEndTime - mecanimToGetUpTransitionTime) / ragdollToMecanimBlendTime; ragdollBlendAmount = Mathf.Clamp01(ragdollBlendAmount); //In LateUpdate(), Mecanim has already updated the body pose according to the animations. //To enable smooth transitioning from a ragdoll to animation, we lerp the position of the hips //and slerp all the rotations towards the ones stored when ending the ragdolling foreach (BodyPart b in bodyParts) { if (b.transform != transform) //this if is to prevent us from modifying the root of the character, only the actual body parts //position is only interpolated for the hips { if (b.transform == anim.GetBoneTransform(HumanBodyBones.Hips)) { b.transform.position = Vector3.Lerp(b.transform.position, b.storedPosition, ragdollBlendAmount); } //rotation is interpolated for all body parts b.transform.rotation = Quaternion.Slerp(b.transform.rotation, b.storedRotation, ragdollBlendAmount); } } //if the ragdoll blend amount has decreased to zero, move to animated state if (ragdollBlendAmount == 0) { state = RagdollState.animated; return; } } }