09/28/2022
Generally, the ragdoll animation is controlled directly but the code to change parameters in the Configurable Joint. But it is quite inconvenient in teamwork, and not straightforward compare to other animations. So, is there any method to combine animation to ragdoll?
The trick is quite easy: copy the animation to the ragdoll!
We deploy 2 models in the scene, one of them is the ragdoll controlled by the player, and the other one is hidden up to merely play the animation, and we use code to copy the animation to the ragdoll!
Access the link below to view the source code of this sample:
We deploy two models, the left one is for animation. Generally, we do not want players to notice this one.
Note: I turn the ragdoll one to face right, as I set this position to be its initial position.
2. Prepare animation for the model, here I just make it in Unity.
3. For the ragdoll model, we write a script to let its joints copy rotations in corresponding rotations in the animation model.
public class RagdollAnimationSync : MonoBehaviour
{
[SerializeField] private Transform targetLimb;
[SerializeField] private bool enableCopy = true;
private ConfigurableJoint ConfigurableJoint;
Quaternion targetInitialRotation;
// Start is called before the first frame update
void Awake()
{
this.ConfigurableJoint = this.GetComponent<ConfigurableJoint>();
this.targetInitialRotation = this.targetLimb.transform.localRotation;
}
private void FixedUpdate() {
if (!enableCopy)
{
return;
}
// Copy the rotation
ConfigurableJoint.targetRotation = copyRotation();
}
private Quaternion copyRotation() {
return Quaternion.Inverse(this.targetLimb.localRotation) * this.targetInitialRotation;
}
}
4. Properly Assign above scripts to the necessary joints.
Note: It is recommended to only copy the rotation in pivotal joints, like shoulders, elbows, neck, and knees. Just left other part for physics simlation~
5. Properly write scripts to control the animator based on the action of the character, here I just simply make the character move and stop.
Note: Do not forget to update the rotation of the Hip to make the character face to correct directions.
public class RagdollMove : MonoBehaviour
{
#region Attributes
public float Speed = 10f;
public Rigidbody Hip;
public Animator Animator;
#endregion
#region Update
void FixedUpdate()
{
Vector3 direction = GetTransformInput();
if (direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.z, direction.x) * Mathf.Rad2Deg;
ChangeRotation(targetAngle);
Move(direction * Speed);
}
else
{
StopMove();
}
}
#endregion
#region Input
private Vector3 GetTransformInput()
{
return new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
}
#endregion
#region Moving
/// <summary>
/// To move the character, add force in the hip, and play animation
/// </summary>
/// <param name="force"></param>
private void Move(Vector3 force)
{
Hip.AddForce(force);
Animator.SetBool("IsMove", true);
}
private void StopMove()
{
Animator.SetBool("IsMove", false);
}
/// <summary>
/// To change the rotation of the character, we modify targetRotation of the Hip
/// </summary>
/// <param name="targetAngle"></param>
private void ChangeRotation(float targetAngle)
{
Hip.angularVelocity = Vector3.zero;
Hip.GetComponent<ConfigurableJoint>().targetRotation = Quaternion.Euler(0f, targetAngle, 0f);
}
#endregion
}
6. Done! Let's check in the game:
Don't forget to modify the parameters in the configurable joints & rigidbody to fit your animation to your character's action~