2
\$\begingroup\$

I have a rigged 2D character and used Collider2D/Rigidbody2D/HingeJoint2D to body parts to implement ragdoll.

It works fine, but I needed to run ragdoll physics only when character is dead. So I made a script to easily control ragdoll related features called RagdollController:

using UnityEngine;
using UnityEngine.Experimental.U2D.IK;

public class RagdollController : MonoBehaviour {
    [SerializeField] private IKManager2D m_IKManager;
    [SerializeField] private Transform[] m_RagdollTransforms;
    private Rigidbody2D[] m_Rigidbodies;
    private HingeJoint2D[] m_Joints;

    void Setup() {
        m_Rigidbodies = new Rigidbody2D[m_RagdollTransforms.Length];
        m_Joints = new HingeJoint2D[m_RagdollTransforms.Length];

        for (int i = 0; i < m_RagdollTransforms.Length; i++) {
            m_Rigidbodies[i] = m_RagdollTransforms[i].GetComponent<Rigidbody2D>();
            m_Joints[i] = m_RagdollTransforms[i].GetComponent<HingeJoint2D>();
        }
    }

    public void Enable() {
        if (m_Rigidbodies == null) {
            Setup();
        }

        m_IKManager.enabled = false;

        foreach (Rigidbody2D rbody in m_Rigidbodies) {
            rbody.isKinematic = false;
            rbody.gravityScale = 1.0f;
        }

        foreach (HingeJoint2D joint in m_Joints) {
            joint.enabled = true;
        }
    }

    public void Disable() {
        if (m_Rigidbodies == null) {
            Setup();
        }

        m_IKManager.enabled = true;

        foreach (Rigidbody2D rbody in m_Rigidbodies) {
            rbody.isKinematic = true;
            rbody.gravityScale = 0.0f;
        }

        foreach (HingeJoint2D joint in m_Joints) {
            joint.enabled = false;
        }
    }
}

Important part is method named Disable:

public void Disable() {
    if (m_Rigidbodies == null) {
        Setup();
    }

    m_IKManager.enabled = true;

    foreach (Rigidbody2D rbody in m_Rigidbodies) {
        rbody.isKinematic = true;
        rbody.gravityScale = 0.0f;
    }

    foreach (HingeJoint2D joint in m_Joints) {
        joint.enabled = false;
    }
}

Method "Disasble" iterate internal rigidbodies and joints, and set isKinematic to true to prevent physics working, also turn off each hinge joint to prevent any joint physics.

However when I run the game and call Disable(), character just falling through the ground. Note that structure of character looks like this:

[Enemy] - Rigidbody2D and Scripts that controlling character
   └ [Mesh] - IKManager2D
       └ [Body] - SpriteRenderer/SpriteSkinEntity/SpriteSkin
       └ [Head] - SpriteRenderer/SpriteSkinEntity/SpriteSkin
       └ [LeftArm] - SpriteRenderer/SpriteSkinEntity/SpriteSkin
       └ [RightArm] - SpriteRenderer/SpriteSkinEntity/SpriteSkin
       └ [Root]
            └ [Stomach] - From here, every child has Collider2D/Rigidbody2D/HingeJoint2D
                 └ [Chest]
                      └ [Head]
                      └ [UpperArmL]
                             └ [LowerArmL]
                      └ [UpperArmR]
                             └ [LowerArmR]
                 └ [UpperLegL]
                        └ [LowerLegL]
                 └ [UpperLegR]
                        └ [LowerLegR]

Root of Enemy GameObject doesn't have collider, instead legs have it so by default character can stand on the ground.

However when I set rigidbody.isKinematic = true, colliders inside of legs and all other bones just not working and character just falling through.

I have no idea why disabling rigidbody affects to collider. I can temporarily fixed by adding simple box collider 2d near by character's foot and only activate it when character is still alive(means that deactivate when character is dead).

This way my character not falling through the ground so you might think the problem was solved, but there is huge problem, because unless set isKinematic = false, Raycast2D does not hitanything(It only hit the collider I just added to prevent falling through the ground, totally useless).

I want to keep my colliders in each body parts: head/stomach/chest/arms/legs to precise hit detection(I was used single capsule collider but hit detection was horrible). Am I doing wrong way, or is this glitch?

How do I make my colliders work even Rigidbody2D is turned off? Using Unity 2019.1.0f2 and 2D Animation Package@2.1.0, 2D IK Package@1.1.0.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ There's a physics option called Enable Kinematic Static Pairs that you may want to try, though maybe it won't help. An article called Unity Ragdoll and Collisions with Rigidbodies with Kinematics presents another possible solution. Good luck, and sorry if these don't help! \$\endgroup\$ Feb 13, 2020 at 10:15
  • 1
    \$\begingroup\$ When you set a body to kinematic, you're telling the physics engine "I will be responsible for collision resolution for this object. Do not interfere with me if I choose to drive this object through a wall/floor" so it sounds like the physics engine is doing exactly what you asked it to. If you do not want the object to fall through the ground, then it's on you to either position it above the ground, or use a non-kinematic body to let the physics engine handle it. \$\endgroup\$
    – DMGregory
    Feb 13, 2020 at 12:49

1 Answer 1

1
\$\begingroup\$

When you set any object isKinematic, that means you are stopping motion related physics on that object.

For you, Initially set all the rigidbody to isKinematic and Enable them when your player Dead.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .