- Home /
Adding rigidbody engages children colliders?
Hello, after looking at the forums and answers for this problem i saw that it didn't really match mine, here's what i do: i have some pieces (lego-like) which have their custom colliders (screenshot below) and they have the "connection points" which are using box colliders to trace mouse clicking, entering and leaving - visible as the smaller cubes below:
However, when i add a rigidbody (via script) to the parent piece, all the children seem to give their colliders to the rigidbody, thus i lose the mouse functionality over them, and they now act as part of the parent rigidbody, even colliding with each other like this:
is there a way to get my connector colliders back and not let them be part of the parent rigidbody? i've tried using Destroy(rigidbody) but nothing changed. Any ideas? Thank you!
Answer by Fattie · Sep 07, 2012 at 12:18 PM
YOU FOUND A BUG.
Make a new project with a scene. have two objects, a large and a small cube. give them DIFFERENT names. Make the small cube a child of the big cube.
Attach this script it to BOTH OBJECTS:
#pragma strict
// this script shows the Unity BUG ....
function Update() // WORKS PROPERLY all four combos
{
var ray : Ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hit : RaycastHit;
if ( Input.GetMouseButtonDown(0) )
if (collider.Raycast (ray, hit, 100.0))
{
Debug.DrawLine (ray.origin, hit.point, Color.green, 1 );
Debug.Log("YOU CLICKED ON ......" + transform.name);
}
}
function OnMouseEnter () // UNITY BUG - DOES NOT WORK for combo 3
{
Debug.Log("TESTE OMENTER");
renderer.material.color = Color.red;
}
function OnMouseExit () // UNITY BUG - DOES NOT WORK for combo 3
{
Debug.Log("TESTE OMEXIT");
renderer.material.color = Color.white;
}
Try these four combinations of
parent .. child
no rigidbody, no rigidbory
no rigidbody, yes rigidbory
yes rigidbody, no rigidbory
yes rigidbody, yes rigidbory
EVERYTHING WORKS PERFECTLY WITH RAYCASTING
double-checked.... note the image below
WITH ONMOUSE, COMBO #3 DOES NOT WORK.
So that's it. Someone telephone Unity.
Your solution: do not use OnMouseEnter / OnMouseExit. Achieve same result with ordinary casting.
SOLUTION SCRIPT:
// this works perfectly but (correctly) has the 'shoot through' issue
// see 'ultimate solution' below if you prefer not shoot-through
function FixedUpdate()
{
var ray : Ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hit : RaycastHit;
if (collider.Raycast (ray, hit, 100.0))
{
Debug.DrawLine (ray.origin, hit.point, Color.green, 1 );
renderer.material.color = Color.red;
}
else
{
renderer.material.color = Color.white;
}
}
Simply try that. You'll see it works perfectly in all four combos. Phew!
There is a problem, a raycast shoots through everything, so, you will get BOTH when one blocks the other. See image. (Note that the whacky OnMouse functions are "strange" or that very reason, they only find the one near the camera. It's useful for a quick development script say, but strange, and since they are broken we need an alternative!)
Now depending on your project, that could be no good. Again the solution script presented immediately above will get any object, not just the one closest to the screen. (Of course another issue is you can adjust the length if desired with the parameter that says "100.0" in the example....often you want to ignore things that are "too far away" in the scene, in this type of thing.)
ULTIMATE SOLUTION ....
// this solution FULLY TESTED with all four combos, all good
// attach to an empty object "operations" in the scene
private var theCam:Camera;
private var yellowRay: Ray;
private var theHit : RaycastHit;
function Awake()
{
theCam = GameObject.Find("cam").camera;
}
function FixedUpdate()
// no need to do this in Update(), FU is usually
// easily fast enough for smooth fingering
{
if ( Input.touches.Length != 1 ) return;
yellowRay = theCam.ScreenPointToRay( Input.touches[0].position );
if ( Physics.Raycast (yellowRay, theHit, 100.0 ) )
{
Debug.Log("theHit.collider.name " +theHit.collider.name);
// for example ... theHit.collider.transform is the object
// you'd likely just look them up from here, eg
// if ( theHit.collider.transform == mySpaceship ) whatever..
// if ( theHit.collider.transform.name == "13" ) whatever..
// or you could do this ...
// theHit.collider.transform.GetComponent(BlahScript) ...
}
}
Make a new empty game object. (I usually call these something like "operations" or "headquarters" ... it takes care of "things on the whole scene".) Put that script in the new empty object. Do not put ANY scripts on the small and large cube.
You'll see it works absolutely perfectly AND you avoid the "shoot through" issue, i.e. only the closest object touched is chosen. (Again you may want to shoot "all the way through" and have all such objects react; in that case use the other method above.)
So, that's it.
To see the red-white effect in testing, just do this:
var aa:Renderer;
var bb:Renderer;
private var theCam:Camera;
private var yellowRay: Ray;
private var theHit : RaycastHit;
function Awake()
{
theCam = GameObject.Find("cam").camera;
}
function FixedUpdate()
{
aa.material.color = Color.white;
bb.material.color = Color.white;
if ( Input.touches.Length != 1 ) return;
yellowRay = theCam.ScreenPointToRay( Input.touches[0].position );
if ( Physics.Raycast (yellowRay, theHit, 100.0 ) )
{
Debug.Log("theHit.collider.name " +theHit.collider.name);
theHit.collider.transform.renderer.material.color = Color.red;
}
}
Hope it helps! What do you win from Unity when you find a bug?
Sorry I wasted so much of your time, at first I ignored that you mentioned OnMouseEnter/Exit. I foolishly assumed all the casting versions in Unity would be equally bug-free.
But you know what they say .... ASSUME makes an ASS out of U and ME ! :)
the side-effect i have in my scripts is this: like you did, i have colliders on my small and big objects, also the small is child of the bigger one. however, when i apply a rigidbody component to the bigger one (the smaller doesn't need to be a rigid body), the onmouseenter and mouseexit functions work only on the big object and not the small anymore... (!)
Hi @vagos !
YOU HAVE FOUND A BUG ...
it does NOT WOR$$anonymous$$ with On$$anonymous$$ouseEnter / On$$anonymous$$ouseExit
IF there is:
(*) rigidbody on the parent, no rigidbody on the child.
SOLUTION:
DO not use On$$anonymous$$ouseEnter / On$$anonymous$$ouseExit ... they are hokey anyway, and obviously not there on iPad. Just do proper raycasts. One line of code.
Someone contact Unity!
Yes i found a bug this is what i realised after testing your code, which worked perfectly :) i was just about to test the on$$anonymous$$ouseEnter and Exit for the 10th time after your second post hehe... Thank you for your time and your detailed explanation, i know how to do raycasting for clicking, but how about mouse enter and mouse exit? do i have to do continuous raycasting in let's say, my camera's Update script? Yes i'm aware that these functions are not available on iPad/android, it would be a good point to change them ASAP :D
exactly, combo #3 is what i'm doing :D looks like i hit the jackpot! lol... Thank you for your patience Fattie!
you imagined it well, i only want the closest to the camera object under the ray :) Although, i can use this script only on my camera and not on each of the big/small cubes. Physics.Raycast only returns the first hit so i'm ok with it. Physics.RaycastAll is what would return all the hits. I'll test it when i have more time and let you know!
Answer by Kryptos · Sep 07, 2012 at 09:04 AM
A rigidbody always catch all events from every colliders and child colliders. This is the way to create a compound collider.
So either don't use a rigidbody on the parent object, or don't parent every child under a common parent.
Another workaround is to add a rigidbody to every child so that collision events will not be propagated to the parent rigidbody. The question is: why do you need a parent rigidbody?
the reason i want to make the pieces rigid bodies is to simulate the connections between them. And the reason i don't just use hierarchy is that the connections are a bit "elastic" allowing for arbitrary structures, they're not solid rock. if you have about 80 pieces one behind another and you bend them you could make a big circle ;)
@$$anonymous$$ryptos, it turns out there is a bug in On$$anonymous$$ouseEnter/Exit. (But not the other casts, of course.)
Who would have guessed ??!
@Fattie I don't think it is a bug. It's pretty logcial in fact (regarding how compound colliders work).
Don't call something a bug just because you don't understand it.
I$$anonymous$$HO it is not a bug but an issue. The difference is essential: a bug means something is/was broken. An issue means the behaviour could have been different. Logically speaking, compound colliders are just like one collider. So Unity implementers chose to return the first collider as reference.
If you want to make distinct colliders, you either need to use a rigidbody on each child (like I suggested). Or you can check the position of the contact point (in case of a collision) with the bounds of each child collider to find the one that was hit.
Default implementation of On$$anonymous$$ouseEnter cast a ray and try to find the same collider as the reference returned by this.collider
. In case of a compound, it will always be the first one. Therefore, you need to write your own cast (using Physics.Raycast) or prevent the use of compound colliders.
heh heh! it's good you have enough experience to know that distinction
I am happy to listen to ideas on why it should behave as it does?
Your answer
Follow this Question
Related Questions
Rigidbody will overwrite children colliders, and collision events won't run. -5 Answers
How to raycast a child collider of a parent rigidbody 2 Answers
Simple Collider Test - Sphere Falls Through Mesh 1 Answer
Animated character with simple colliders on joints - rigidbody not finding child colliders. 0 Answers