I have a “Grab” script I’ve repurposed from an online active ragdoll tutorial.
So, I have my “Player” (blue), with a hanging ‘hand’, on the player hand is a sphere collider with a Rigidbody attached, I then have a box (pink) with the tag “Grabbable”, with a box collider and a Rigidbody.
So, I can manoeuvre the Player to the box, and I’m able to ‘grab’ it by creating a hinge joint, this is fine so far, however, I have noticed some glitches, mainly
1. Grabbing is difficult, sometimes I have to click a number of times before it actually ‘grabs’ the object, anything I can do to help with this? 2. Not all the time, but fairly often, when I ‘grab’, multiple hinge joints are created, why, how might I fix? 3. Distance between my Players hand and the box object is ‘far’, making it look like my player is using ‘the force’ to move the object, rather than the actual ‘grab’, how to close the distance between the hinge joint setup?
The Grab code is here
using UnityEngine;
public class Grab : MonoBehaviour
{
public bool canGrab;
private bool hold;
void Update()
{
if (canGrab)
{
if (Input.GetMouseButton(0))
{
hold = true;
}
else
{
hold = false;
Destroy(GetComponent<FixedJoint>());
}
}
}
private void OnCollisionEnter(Collision collision)
{
if (hold && collision.transform.tag != "Player" && collision.gameObject.tag == "Grabbable")
{
Rigidbody rb = collision.transform.GetComponent<Rigidbody>();
if (rb != null)
{
FixedJoint fj = transform.gameObject.AddComponent(typeof(FixedJoint)) as FixedJoint;
fj.connectedBody = rb;
}
else
{
FixedJoint fj = transform.gameObject.AddComponent(typeof(FixedJoint)) as FixedJoint;
}
}
}
}
For #1: find out why by debugging. First question is, what is the state of canGrab when it fails to grab?
For #2: keep a reference to the joint you create (AddComponent() returns the new reference). That way if it exists, don’t remake it. This also lets you Destroy() it explicitly and set it to null, thus avoiding so much GetComponent() noise.
For #3: again, debug to find out why the distances are bigger than you expect. Are the colliders perhaps larger? Is the hand bouncing off first (use layers to inhibit)? etc.
Whenever you need more information about what your program is doing as well as how and where it is deviating from your expectations, that means it is…
Time to start debugging!
By debugging you can find out exactly what your program is doing so you can fix it.
Here is how you can begin your exciting new debugging adventures:
You must find a way to get the information you need in order to reason about what the problem is.
Once you understand what the problem is, you may begin to reason about a solution to the problem.
What is often happening in these cases is one of the following:
the code you think is executing is not actually executing at all
the code is executing far EARLIER or LATER than you think
the code is executing far LESS OFTEN than you think
the code is executing far MORE OFTEN than you think
the code is executing on another GameObject than you think it is
you’re getting an error or warning and you haven’t noticed it in the console window
To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.
Doing this should help you answer these types of questions:
is this code even running? which parts are running? how often does it run? what order does it run in?
what are the names of the GameObjects or Components involved?
what are the values of the variables involved? Are they initialized? Are the values reasonable?
are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)
Knowing this information will help you reason about the behavior you are seeing.
You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);
If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.
You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.
You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.
You could also just display various important quantities in UI Text elements to watch them change as you play the game.
Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: How To - Capturing Device Logs on iOS or this answer for Android: How To - Capturing Device Logs on Android
If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.
Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.
If your problem is with OnCollision-type functions, print the name of what is passed in!
Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:
“When in doubt, print it out!™” - Kurt Dekker (and many others)
Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.
Keep in mind that using GetComponent() and its kin (in Children, in Parent, plural, etc) to try and tease out Components at runtime is definitely deep into super-duper-uber-crazy-Ninja advanced stuff.
Here’s the bare minimum of stuff you absolutely MUST keep track of if you insist on using these crazy Ninja methods:
what you’re looking for:
→ one particular thing?
→ many things?
where it might be located (what GameObject?)
where the Get/Find command will look:
→ on one GameObject? Which one? Do you have a reference to it?
→ on every GameObject?
→ on a subset of GameObjects?
what criteria must be met for something to be found (enabled, named, etc.)
If you are missing knowledge about even ONE of the things above, your call is likely to FAIL.
This sort of coding is to be avoided at all costs unless you know exactly what you are doing.
Botched attempts at using Get- and Find- are responsible for more crashes than useful code, IMNSHO.
If you run into an issue with any of these calls, start with the documentation to understand why.
There is a clear set of extremely-well-defined conditions required for each of these calls to work, as well as definitions of what will and will not be returned.
In the case of collections of Components, the order will NEVER be guaranteed, even if you happen to notice it is always in a particular order on your machine.
It is ALWAYS better to go The Unity Way™ and make dedicated public fields and drag in the references you want.
Thanks for your informative post, I hope you’ve copied and pasted this a few times, and didn’t come up with all that on the fly!
Point 1 : The canGrab is not relevant within this script, it is publicly set and simply lets the script know whether it’s in play or not. The private and ‘main’ bool would be the ‘hold’. I used Debug.Log to determine when it was being triggered and when it was not, this held true when I pressed the left mouse button down, otherwise it was always false.
I suspect when clicking to grab the box, on some occasions, I am possibly ‘inside’ the box’s ‘box collider’, and so multiple clicks might be registered before it finally ‘registers’ a grab, as in I might need to move my players ‘arm’ outside of the box, and then ‘collide’ ‘again’ to register a click. I probably need a better way to register the collision, I can work on this.
Point 2 : Answers to point one, somewhat explain problems arising in point 2, if I’m clicking multiple times in quick succession to try and register a ‘grab’, then multiple hinge joints could be created, your point of tracking the reference and if it exists, not remaking it, is good advice, I will try to implement that method.
Point 3 : Yes, the hand does bounce off, but with the hand and box being rigid bodies, I can’t avoid this(?), making the sphere collider on the hand smaller and ‘within’ the hand certainly helps with the distance disparity though, so I will look into this further!
Thanks for your guidance and help, appreciated!
Regards
EDIT: Code with fixes implemented ```csharp
**using UnityEngine;
public class Grab : MonoBehaviour
{
public bool canGrab;
private bool hold;
private bool hasJoint;
void Update()
{
if (canGrab)
{
if (Input.GetMouseButton(0))
hold = true;
else
{
// Set boolean conditions
hold = false;
hasJoint = false;
// Destroy fixed Joint
Destroy(GetComponent<FixedJoint>());
}
}
}
private void OnCollisionStay(Collision collision)
{
// If hold is TRUE, AND collision object is not Player, AND collision object has tag "Grabbable"
if (hold && !collision.gameObject.CompareTag("Player") && collision.gameObject.CompareTag("Grabbable"))
{
// Check If collision object HAS a Rigidbody, and hasJoint is FALSE
if (collision.gameObject.GetComponent<Rigidbody>() != null && !hasJoint)
{
// If both conditions are TRUE, add a fixed Joint
gameObject.AddComponent<FixedJoint>();
// Disable Preprocessing | Helps with Joint stability
gameObject.GetComponent<FixedJoint>().enablePreprocessing = false;
// Add the collision object (rigidBody) as a connected Body
gameObject.GetComponent<FixedJoint>().connectedBody = collision.rigidbody;
// Set hasJoint to TRUE
hasJoint = true;
}
}
}