I have some code that adds a fixed joint to an object in the world, changes some of its settings and tries to keep a reference to it so that I can remove the joint at a later time in a different method. The component gets added and the settings get changed but the reference to the object becomes null seemingly for no reason once the method ends.
public FixedJoint WorldJoint;
public void GrabObject ()
{
if (ObjectInRange && !AmGrippingObject)
{
GrabbedObject = InRangeGrabTarget;
AmGrippingObject = true;
// create fixed joint on other object and set its settings
WorldJoint = GrabbedObject.AddComponent<FixedJoint>(); // this line Sort of works???
WorldJoint.connectedArticulationBody = Gripper;
WorldJoint.breakForce = GripStrength;
WorldJoint.breakTorque = GripTorqStrength;
WorldJoint.massScale = 150;
GrabberVisual.GetComponent<Renderer>().material = GrabbedColor;
}
}
My later method Release object always fails because world joint at that point is a null reference. I do not understand why the reference is null.
I currently have 2 ways of calling the method. A keyboard binding script, and a manual activation that looks like this
public bool DebugGrab;
public bool DebugRelease;
private void Update()
{
if (DebugGrab)
{
GrabObject();
DebugGrab = false;
}
if (DebugRelease)
{
ReleaseObject();
DebugRelease = false;
}
}
I can disable the keyboard script and activate just the grab method manually. When I do this All of the other functions of the method work correctly but the world joint refrence remains null.
I found a fix for the issue But I still dont understand why on earth I need to run the line that fixes it.
public FixedJoint WorldJoint;
public void GrabObject ()
{
if (ObjectInRange && !AmGrippingObject)
{
GrabbedObject = InRangeGrabTarget;
AmGrippingObject = true;
// create fixed joint on other object and set its settings
WorldJoint = GrabbedObject.AddComponent<FixedJoint>();
WorldJoint.connectedArticulationBody = Gripper;
WorldJoint.breakForce = GripStrength;
WorldJoint.breakTorque = GripTorqStrength;
WorldJoint.massScale = 150;
GrabberVisual.GetComponent<Renderer>().material = GrabbedColor;
WorldJoint = WorldJoint; // dear god why do i need to do this
}
}
Edit: I found a simpler stupid line that solves the issue
I saved my project and restarted my computer, Now it seems I can remove the cursed line and have the reference not bork its self. The code functions as intended after restarting unity, .
You can use the Break Force and Break Torque properties to set limits for the joint’s strength. If these are less than infinity, and a force/torque greater than these limits are applied to the object, its Fixed Joint will be destroyed and will no longer be confined by its restraints.
When Unity object gets destroyed references to it typically become null (kind of, not really, but for many purposes they behave and need to be treated like null).
So you either need to remove the break force, set it to infinity, or before attempting to destroy the joint check if it’s not already null due being destroyed by exceeding breaking force
I assume that in the cases where it didn’t fail either you didn’t make any moves which would cause the breaking force to be exceeded or changed the breaking force setting while flailing around and randomly changing code, but attributed the fix to something else. My recommendation is that when you observe hard to believe “fixes” like the cursed line, carefully test it by adding and removing the “fix” multiple times. If you don’t retest without “fix” version there is high chance that something else caused behavior to change instead of the thing you thought fixed it. Maybe you changed some other lines of code, or maybe while debugging the problem you started to rush things and changed how you test things in play mode (waving your mouse or less vigorously and thus apply less force on physics objects) .
I printed out the script while it was bugging to bring it to show my dad because of how absurd I found the fix. So I can look back at the exact code that was bugging. There are no calls made to ReleaseObject() that happen in the entire scene. The fixed joint was clearly visible in the inspector, it had not broken and it had the correct settings. there was no code run that set WorldJoint to void. Im guessing the editor had somehow entered a bugged state, and that is what was causing the refrence to become void if I did not set it equal to itsself
does nothing. Your issue may be related to the fact that you add components to other objects that you’re hitting / overlapping with but you never destroy / remove those components. A single gameobject can only have one FixedJoint component. Trying to add another one most likely fails.
So your first step should be to actually make the release method revert what it has done when grabbing objects.
Please, do not post images of code (let alone photos of code printouts).
You have a commented line that looks like this:
//Destroy(GetComponent(WorldJoint.GetType()));
This doesn’t make much sense. You add the joint to the “other” object, not to your own. This line of code graby the actual worldjoint, uses GetType to get the type “FixedJoint” (at this point the reference in WorldJoint is no longer used). Now you use GetComponent on your own gameobject and try to find a FixedJoint component which most likely does not exist so GetComponent would return null. Finally you try to destroy that component which does not work.
If you want to destroy the FixedJoint (and you probably want) you should just do:
Destroy(WorldJoint);
Though if it’s possible that an object may already have a FixedJoint, maybe you want to destroy it before adding a new one or just reuse the joint that’s already on the object instead of always adding a new one.
That’s nonsense there are some Unity components which are limited to 1 component per object. But plenty of components can and are meant to be added in any quantity. I have never seen a physics engine which didn’t allow making arbitrary contraptions using joints.
Well, you’re right, it seems it’s now possible to add multiple FixedJoints to a gameobject. So I stand corrected. However please do not misquote me. I never said there can only be one instance of a component. I specifically talked about FixedJoints. Just like BoxColliders and several others in the past you could only attach a single one of them. It seems they even removed that limitation for Colliders of the same type now (which never made sense in the first place).
Though the majority of built-in components are limited to one instance. (Camera, MeshRenderer, Rigidbody, Animator, LineRenderer, WheelCollider, Cloth, Light, …).
Anyways, if the joint should be removed, it should be properly destroyed. Yes, if a joint breaks it would automatically destroy the joint, but it’s not a reliable solution to just lower the break force.
I also would not use a seperate boolean value “AmGrippingObject”. Just using the “WorldJoint” variable to remember the grabbing state is enough and avoids ambiguities in cases where the object may be destroyed by other means. When releasing the object, there should be a null check if we actually still holding something or not.