Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Resolved Need Configurable Joint source code

Discussion in 'Physics' started by CaseyHofland, Mar 20, 2022.

  1. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    564
    Heya, I wanted to write my own various types of joints! In order to gain some inspiration I would like to check the source code for the existing joints so I can make sure they behave similarly.

    Unity of course uses Physx for its physics simulation so I looked in the Physx repo, but I couldn't find a configurable joint. Does anybody know what it's named in Physx?
     
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,434
  3. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    564
    Oh boy, I can already tell this is gonna be a bad time :’)

    Thanks though! Mostly it’s just extracting the right code in a simpler format (like a specific joint for target position, target rotation, prismatic joint) so I’ll get there yet!
     
  4. HespKass

    HespKass

    Joined:
    Apr 6, 2019
    Posts:
    4
    Any updates on this?
     
  5. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    564
    Boy oh boy I do: it's become a whole beast of a different color, but I do.

    TLDR;
    SliderJoint is an implementation for a 3D SliderJoint (aka a Prismatic Joint) that uses a ConfigurableJoint under the hood but gives you a nice Inspector and API specifically for manipulating Slider Joints.

    If you read on, you'll learn how to do this for ANY COMPONENT IN THE FUTURE :eek: as an example, I reuse the underlying API that makes this all work to link a custom CharacterController2D with a CapsuleCollider2D.

    ===========================================

    IN MOST CASES, loose coupling of objects is the way to go - it allows for designers to get creative with your components, mixing them in ways you didn't even imagine when you wrote the initial code: this is cool!

    But sometimes, you just need the ability to force components to behave a certain way based on the properties of your custom one. Enter IAuthor, the interface that allows you to Author other components.

    It's real easy!
    Code (CSharp):
    1. [RequiredComponent(typeof(CapsuleCollider2D))]
    2. public class Test : MonoBehaviour, IAuthor
    3. {
    4.     public CapsuleCollider2D capsuleCollider2D => GetComponent<CapsuleCollider2D>();
    5.  
    6.     [SerializeField] private Vector2 _offset;
    7.     public Vector2 offset
    8.     {
    9.         get => capsuleCollider2D.offset;
    10.         set => capsuleCollider2D.offset = _offset = value;
    11.     }
    12.  
    13.     [field: SerializeField, HideInInspector] private bool IAuthor.isDeserializing {get; set;}
    14.     void IAuthor.Serialize() => offset = offset;
    15.     void IAuthor.Deserialize() => offset = _offset;
    16.     private void Reset() => ((IAuthor)this).ResetAuthor();
    17.     private void OnDestroy() => ((IAuthor)this).DestroyAuthor();
    18. }
    If you pop in the above code, notice how changing the offset field on one will also change it on the other! (Cool tidbit: this means it works with any components, they don't even have to be on the same object).

    One thing you might also be interested in is the "RequiredComponent<>" struct. The above uses the "RequiredComponentAttribute" to make sure a CapsuleCollider2D is present. But this is flawed in that you have multiple scripts with the "RequiredComponentAttribute" it will still only require 1 CapsuleCollider2D, plus there is no certainty to it linking properly.

    That's why I also recommend employing RequiredComponent<> for ease of use:
    Code (CSharp):
    1. public class Test : MonoBehaviour, IAuthor
    2. {
    3.     // Link a CapsuleCollider2D to our author and additionally hide it in the inspector.
    4.     [SerializeField, HideInInspector] private RequiredComponent<CapsuleCollider2D> _capsuleCollider2D;
    5.     public CapsuleCollider2D capsuleCollider2D => _capsuleCollider2D.GetComponent(gameObject, HideFlags.HideInInspector);
    6.  
    7.     void IAuthor.DestroyAuthor() => ExtraObject.DestroyImmediateSafe(_capsuleCollider2D); // Destroy our linked CapsuleCollider2D when we destroy the author.
    8. }
    The above code will additionally hide the CapsuleCollider2D for you in the inspector - but this is not a hard limit. All this code is pretty crazy in what it will let you do: heck, that struct will even let you require components on completely different GameObjects! I don't recommend it but hey who am I to say? Go nuts!

    ===========================================

    I've added the required scripts below, but you can also get these from installing my UnityExtras package. Even though main is stable, DO NOT expect all components to, uhm... work. UnityExtras is full of generic reusable code and it's super useful! But nothing is ever stress-tested and expect API's to break without warning. Still: if you like extras you'll love UnityExtras.
     

    Attached Files:

  6. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    564
    And of course:

    If you're just here for joints, download the above scripts as well as this one for an advanced use case in IAuthor and manipulating joints. SliderJoint is also included in the UnityExtras package.
     

    Attached Files:

    Last edited: Jan 4, 2023
  7. HespKass

    HespKass

    Joined:
    Apr 6, 2019
    Posts:
    4
    Thanks @CaseyHofland for taking the time that was very helpful.
     
    CaseyHofland likes this.