- Home /
I want to bind gameObject.Find with a LOOP to find 76 boxes with numeric NAMES!
Hi people, i want to make a destructible object for my game. I want it to break when i hit it but as you know i cannot make it rigid before the impact since the gravity will tear it down as all objets cant stay on their feet without atomic bonding.
So i made a glass shaped sturcture to test and learn unity, i made 2 scripts that work perfectly fine. But i have to write the same code 76 times which is no big deal really, but i wanted to learn the right way to do it so i am here.
The codes i use are:
function React () {
gameObject.AddComponent(Rigidbody);
}
This is the react code that is in every box, 76 of em.
function OnCollisionEnter(col : Collision) { if(col.gameObject.name == "Collider") {
gameObject.Find("1").SendMessage("React");
gameObject.Find("2").SendMessage("React");
gameObject.Find("3").SendMessage("React");
}
}
This goes till 76.What this does is; The object i am hitting the glass is named collider. When the collider hits any of the boxes, all of them suddenly become rigid bodies and it breaks down nicely just as i wanted it to. This code is also in every box, 76 of them. The boxes are named , 1,2,3,4,5... 76 the last one, all in numbers. Now i want to make a loop like this;
function OnCollisionEnter(col : Collision) {
if(col.gameObject.name == "Collider")
{
for(i=1; i<=76; i++){ gameObject.Find("i").SendMessage("React");
}
}
}
But the problem here is that, the "i" that the gameObject.Find is looking for isnt the "i" in my loop. So i need your help. By using loop and class together or just one of them, can i make the code work for every box with a loop.
I also need some help in adding an "Energy" or "Velocity" barrier to the function. For example a glass wouldnt break if it fell from 5 cm, but it will break if it fells from 1 meter. I need to add some sort of a restriction to the Send.Messege operation. If you can help me with that also. I want the cube glass not to break if isnt hit by "X" joules of energy or "Y m/s" velocity.
Any help is appriciated guys, :) love you
Answer by Joshua · Jul 10, 2011 at 03:23 AM
You should never write the (nearly) same line of code 76 times. It's quicker to write a script that will proceduraly create, write and import that script then to actually write it ;).
Also, I assume all these 76 objects are childs of the same parent? Simply use
var children : Transform[] = GetComponentsInChildren.< Transform ();
for( var child : Transform in children )
child.AddComponent( Rigidbody );
Anyway, try to avoid using the Find function, as it is extremely slow. Same goes for AddComponent, there's absolutely no need. Add the rigidbodies beforehand, make them kinematic and then turn isKinematic to false when you want them to 'kick in'.
Now lastly, there's no real reason to do this in a single frame, is there? Why not do it in two or three frames? Here is how I would do it, if there's still a notecable lag, yield once in between to do it in two frames. Also, it would be even better to add the rigidbodies in edit mode (either through in-editor scripting or manually) instead of at run time.
var obj : GameObject;
var rigidbodies : Rigidbody[];
function Start()
{
var children = obj.GetComponentsInChildren.< Transform >();
rigidbodies = new Rigidbody[ children.Length ];
for( var i : int = 0; i < children.Length; i++ )
{
rigidbodies[i] = children[i].AddComponent( Rigidbody ) as Rigidbody;
rigidbodies[i].isKinematic = true;
}
}
function React()
{
for( var rb : Rigidbody in rigidbodies )
rb.isKinematic = false;
}
Answer by Chris D · Jul 10, 2011 at 02:37 AM
Try BroadcastMessage instead. It sends the message to every game object attached to a parent, so you won't even have to loop, you'll just have to set up your hierarchy accordingly.
Answer by Shealei · Jul 10, 2011 at 12:35 AM
Ok i wrote 76 lines of code but this freezes my pc since every single contact i make with the boxes it read the code from the start again. And there are a lot of boxes, so i also need to cancel the code after the first impact, any ideas?=
Or is there a way to make a destructible object that can stay as rigid body all the time even though it isnt on a geometrical state that it can withstand the gravity with mass center alone. For example a statue or a fish tank.
rigidbody.useGravity = false;
ridigbody.constraints = RigidBodyConstraints.FreezeAll;
http://unity3d.com/support/documentation/ScriptReference/Rigidbody-useGravity.html
http://unity3d.com/support/documentation/ScriptReference/Rigidbody-constraints.html
also, inside of your for-loop, try FindObject(""+i)//or count
Answer by Shealei · Jul 10, 2011 at 08:53 AM
Thanks you guys, i managed to fix it with these 2 pieces of codes.
function OnCollisionEnter(col : Collision) { if(col.gameObject.name == "Collider") {
gameObject.Find("1").BroadcastMessage("React");
} }
and the react code is
function React () {
rigidbody.isKinematic = false;
}
But i still have 2 questions here. How do i make the block break with only with more than 50 meter/second velocity for example or 5000joules of energy.
And the code is fine as it is, but i think it can be improved. I am seeing a 250FPS drop at the point of impact, from 500 to 250. This really concerns me if i was shooting 3 bullets/second to a minibar of glasses my pc would freeze immidiately.
I think its the GameObject.Find command, but i dont see a way the go around it.
Jashua, i tried what you said but the codes you wrote dont seem to work. I took your ideas tho ty, and also ty to ChrisD and SilverTabby
Actually, a "250 fps drop" is not as bad as it seems.
If you translate from fps to milliseconds per frame, then you have
"I am seeing a 2 millisecond per frame drop at the point of impact, from 2 milliseconds per frame to 4 milliseconds per frame".
In an example scenario of running at 50 fps (20 mils/frame), adding the exact same setup you have would only drop you to 45.5 fps.
generally, fps is only an accurate measure of performance for values
If you want to avoid dropping fps due to GameObject.Find, you can run the command ahead of time in the Start() or Awake() methods so you don't have to do it at run time - just store the reference in a var. Though I think your performance problem is the rigidbodies, which require a constant upkeep cost, not GameObject.Find() which is a one-and-done function
Both find and waking up a rigidbody are indeed expensive. So follow my example and do the referencing in Start, and the waking up in two or three frames.
If you've fixed your problem, please mark this answer (or whichever one you used) as accepted (check mark beside thumbs up/down) so that other people will know it's been solved.
Your answer
Follow this Question
Related Questions
SendMessage on DontDestroyOnLoad object 1 Answer
Deleting GameObjects 1 Answer
How to obtain a gameObject from an List with the name? 1 Answer
Magnetic Gameobject 1 Answer
Issue with spawning buttons and assigning listeners 1 Answer