1
\$\begingroup\$

My Task: I'm trying to replicate this project. I'm using unity as my physics engine. Currently I'm still learning how to work with the different joints unity has to offer. The type of movement I'm looking for is where a body is connected to only one other body and its relative movement can be limited based on angles on different axes.

My Problem: I'm using Configurable joints for my movement restrictions. The Low Angular X Limit and High Angular X Limit does exactly what I'm looking for since it can have a different uppper and lower rotation limit. Looking at the documentation, it seems that this can only be done on the X axis. The Y and Z axes only have a Angular Y Limit or Angular Z Limit which set the upper as the opposite of the lower limit.

My Question: Is it possible for the Y and Z axes to have the same lower-upper limit system that the X axis has? Is the use of configurable joint good for this task?

Thanks in advance :)

\$\endgroup\$
  • \$\begingroup\$ It sounds like you could get the behaviour you want by chaining two joints: one on the x axis, and one twisted 90 degrees so that its x is your y. Or a single configurable joint where you've simply rotated its initial/neutral y to be equidistant between your high and low limits, so that you can express the limit symmetrically about this neutral pose..How have you tried solving your problem so far? \$\endgroup\$ – DMGregory Nov 27 at 10:49
  • \$\begingroup\$ Currently, I don't have a direction for a solution. In your first solution, do you mean to twist the joint itself? How could I do that? \$\endgroup\$ – Koby 27 Nov 27 at 11:06
1
\$\begingroup\$

I used the method @DMGregory suggested and rotated the joint before setting the limits. Since the joint limits rotation and also cannot be disabled I created a script that rotates and then adds the joint.

public class ConfigJoint : MonoBehaviour {

    private ConfigurableJoint joint;

    [SerializeField]
    private Rigidbody connectedBody;

    [Header("Angular X Limits")]

    [SerializeField, Range(-180, 0)]
    private float xLower;
    [SerializeField, Range(0, 180)]
    private float xUpper;


    [Header("Angular Y Limits")]
    [SerializeField, Range(-180, 0)]
    private float yLower;
    [SerializeField, Range(0, 180)]
    private float yUpper;

    [Header("Angular Z Limits")]
    [SerializeField, Range(-180, 0)]
    private float zLower;    
    [SerializeField, Range(0, 180)]
    private float zUpper;

    [Header("Anchors")]
    [SerializeField]
    private Vector3 anchor;
    [SerializeField]
    private Vector3 connectedAnchor;

    void Start () {                

        Rotate(); // Rotate to the rotation that matches the wanted limits

        joint = gameObject.AddComponent<ConfigurableJoint>();  // Adds a configurable joint

        LockMotion();   // Sets all movement to Locked
        LimitRotation();    // Sets all angular movement to Limited

        SetAnchors();   // Sets the anchors to the wanted anchors

        SetAngularLimits();  // Sets the limits for the joint
    }

    private void Rotate()
    {
        // The mid point between the upper and lower limit
        float xMid = (xUpper + xLower) / 2;
        float yMid = (yUpper + yLower) / 2;
        float zMid = (zUpper + zLower) / 2;

        //Debug.Log("Setting rotation: " + new Vector3(xMid, yMid, zMid));
        transform.localRotation = Quaternion.Euler(xMid, yMid, zMid);        
    }


    private void SetAngularLimits()
    {        
        // The value that each angular limit needs to be to create the effect of an upper and lower limit
        float xAbsAvg = (xUpper - yLower) / 2;
        float yAbsAvg = (yUpper - yLower) / 2;
        float zAbsAvg = (zUpper - zLower) / 2;

        SoftJointLimit sjl = new SoftJointLimit();

        sjl.limit = xAbsAvg;
        joint.highAngularXLimit = sjl;

        sjl.limit = -xAbsAvg;
        joint.lowAngularXLimit = sjl;

        sjl.limit = yAbsAvg;
        joint.angularYLimit = sjl;

        sjl.limit = zAbsAvg;
        joint.angularZLimit = sjl;


    }

    private void SetAnchors()
    {
        joint.connectedBody = connectedBody;
        joint.anchor = anchor;
        joint.connectedAnchor = anchor;
    }

    private void LockMotion()
    {
        // Body parts should not move. They can only rotate
        joint.xMotion = ConfigurableJointMotion.Locked;
        joint.yMotion = ConfigurableJointMotion.Locked;
        joint.zMotion = ConfigurableJointMotion.Locked;
    }

    private void LimitRotation()
    {
        joint.angularXMotion = ConfigurableJointMotion.Limited;
        joint.angularYMotion = ConfigurableJointMotion.Limited;
        joint.angularZMotion = ConfigurableJointMotion.Limited;
    }    
}

How to use: Add this to the component you would add the configurable joint to. All parameters are pretty self-explanatory or parallel to those in regular joints.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.