Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Get centre point of multiple child objects

Discussion in 'Scripting' started by spendew, Apr 13, 2012.

  1. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    Hello,

    How would I get the average centre of multiple objects that are parented to each other? I want the root parent (the "godfather" of all the other objects) to be able to gather all the child objects positions, add them, then multiply them by how many of them there are (this will get me the average centre if Im not mistaken).

    Please help!
     
  2. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
  3. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    I'm sorry Diablo but I meant how to do it using Unity's functions, not the math behind it.
     
  4. wccrawford

    wccrawford

    Joined:
    Sep 30, 2011
    Posts:
    2,040
    So it sounds like you've got a good plan... Get all the positions, add them up, then divide by the number of objects.

    Have you tried it yet?
     
  5. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    You must use the math behind it and calculate it yourself.

    There is no magic function for every possible problem you can call and be done with it. It's called programming and not sorcery ^^
     
    laranthir, Joe-Censored and hsirkar like this.
  6. Rapskalian

    Rapskalian

    Joined:
    Jan 4, 2011
    Posts:
    45
    Code (csharp):
    1.  
    2. function calculateCentroid(centerPoints : Array){
    3.   var centroid : Vector3 = new Vector3(0,0,0);
    4.   var numPoints = centerPoints.length;
    5.   for(var point : Vector3 in centerPoints){
    6.     centroid += point;
    7.   }
    8.  
    9.   centroid /= numPoints;
    10.  
    11.   return centroid;
    12. }
    13.  
    Where centerPoints is an array of Vector3 objects representing the centers of all the objects you want to include in the calculation. This is purely the centroid. It does not account for the weighted average of their masses.

    This is just the basic algorithm. You could modify its arguments to receive the "grandfather" object. Then within the function you could obtain all its children's positions before calculating the centroid.
    This snippet might help: http://unity3d.com/support/documentation/ScriptReference/Transform.html
     
    Last edited: Apr 14, 2012
  7. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    forum won't let me edit or delete my post, I meant to post this for my code:

    Code (csharp):
    1. function calculateCentroid()
    2. {
    3.   var centroid : Vector3 = new Vector3(0,0,0);
    4.  
    5.   if ( transform.childCount > 0 )
    6.   {
    7.      for (var child : Transform in transform)
    8.     {
    9.         centroid += child.transform.position;
    10.     }
    11.     centroid /= ( transform.childCount+1 );
    12.   }
    13.  
    14.   transform.position = centroid;
    15. }
    16.  
     
  8. flaminghairball

    flaminghairball

    Joined:
    Jun 12, 2008
    Posts:
    868
    Why are you adding 1 to the childCount?
     
  9. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    To accommodate for the root because the child count doesn't include the root object.

    Edit: So I am trying a much simpler approach to find the centre now, I have a game object labelled "middle" that is moved to the supposed centroid, it gets the proper centre for the first block I add to it but when more than two are added it just moves to far off places each time.

    looks like this now:
    Code (csharp):
    1. function calculateCentroid()
    2. {
    3.   var centroid : Vector3 = Vector3.zero;
    4.  
    5.   if ( transform.childCount > 0 )
    6.   {
    7.     var allChildren = transform.gameObject.GetComponentsInChildren(Transform);
    8.     for (var child : Transform in allChildren)
    9.     {
    10.         centroid += child.transform.position;
    11.         print(child.transform.position);
    12.     }
    13.     centroid /= (transform.childCount+1);
    14.   }
    15.   GameObject.Find("middle").transform.position = centroid;
    16. }
    17.  
     
    Last edited: Apr 15, 2012
  10. Rapskalian

    Rapskalian

    Joined:
    Jan 4, 2011
    Posts:
    45
    I believe GetComponentsInChildren already accounts for the root object itself. You don't need to add 1. Not sure if that's the problem though..

    EDIT: ah wait! I think its because you're counting ALL children, not just Transforms. You should divide it by allChildren.length
     
    Last edited: Apr 16, 2012
  11. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    GetComponentsInChildren does not include the Component included on the caller's GameObject.
     
  12. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    Rapskalian, wouldn't "allChildren.length" return the same result as "transform.childCount"?
     
  13. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    In this special case it would, because each gameobject must have a transform. This is not true for other kind of components.

    Still, you must not add + 1. It's not an index, its the count. An array is zero index based, so an array of size/length/count 5 has elements with index 0, 1, 2, 3 and 4. NOT 5.
     
  14. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    Thank you Tseng.

    Ladies and gents, I have found the problem!

    The problem was that all the objects were doing this code rather than jus the root object, it is now fixed:
    Code (csharp):
    1. function calculateCentroid()
    2. {
    3.     if ( transform.root.gameObject == transform.gameObject )
    4.     {
    5.         var centroid : Vector3 = Vector3.zero;
    6.  
    7.         if ( transform.childCount > 0 )
    8.         {
    9.         var allChildren = transform.gameObject.GetComponentsInChildren(Transform);
    10.         for (var child : Transform in allChildren)
    11.         {
    12.             centroid += child.transform.position;
    13.         }
    14.         centroid /= (allChildren.length);
    15.         }
    16.         GameObject.Find("middle").transform.position = centroid;
    17.     }
    18. }
    19.  
    Thanks for the help! Now all I need to do is make the centre be affected by the mass of the objects, shouldn't be too hard.
     
    Last edited: Apr 17, 2012
  15. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    Ok famous last words haha. I need help with making objects of higher mass influence the centroid more.

    This is my code:
    Code (csharp):
    1. var centroid : Vector3 = transform.position;
    2.            
    3.             var allChildren = transform.gameObject.GetComponentsInChildren(Transform);
    4.             for (var child : Transform in allChildren)
    5.             {
    6.                 centroid += child.transform.position;
    7.                 centroid*= child.transform.gameObject.GetComponent(blockScr).blockMass/5;
    8.             }
    9.             centroid /= (allChildren.length);
    10.             centroidIns.transform.position = centroid;
    It works if the root object is placed at point (0,0,0), but when it is moved the centroid is moved all out of place through multiplication of the position.
     
  16. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
  17. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    I have the weighted average working as I would want it to but only when the root object is centred at (0,0,0). Basically I want to know how I can make it so the centre of mass is in the same place (local to the root) no matter where it is.

    Here is the code I am using:

    Code (csharp):
    1. var centroid : Vector3 = Vector3.zero;
    2.             var massInfluence : Vector3 = Vector3.zero;
    3.            
    4.             var allChildren = transform.gameObject.GetComponentsInChildren(Transform);
    5.             for (var child : Transform in allChildren)
    6.             {
    7.                 centroid += child.transform.position;
    8.                 massInfluence = child.transform.position*child.transform.gameObject.GetComponent(blockScr).blockMass/10;
    9.                 centroid += massInfluence;
    10.             }
    11.             centroid /= (allChildren.length);
    12.            
    13.             centroidIns.transform.position = centroid;
    14.  
     
    Last edited: Apr 17, 2012
  18. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    Here's a hint : the child transforms are local (that is, relative) to your root object. You're trying to set the root object's coordinates to a local space position that only makes sense *inside* the root object but not outside, where the root object lives. I'll leave the rest to you as an easy excercise.
     
  19. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    I accept your exercise challenge, was I on the right track with my previous post?
     
  20. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    Well.... I'm no math wiz, but isn't the weighted average supposed to be :

    x = Sum(Nx * weight) / Sum(weight)

    where Nx is each coordinate position?
     
    Last edited: Apr 17, 2012
  21. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    Indeed..

    Okay so here is the new code:

    Code (csharp):
    1. var allChildren = transform.gameObject.GetComponentsInChildren(Transform);
    2.             for (var child : Transform in allChildren)
    3.             {
    4.                 var blockMass = child.transform.gameObject.GetComponent(blockScr).blockMass;
    5.                
    6.                 centroid += child.transform.position*blockMass;
    7.                 massTotal += blockMass;
    8.             }
    9.             centroid /= (allChildren.length);
    10.             centroid /= massTotal;
    11.            
    12.             centroidIns.transform.position = centroid;
    13.  
    I will contenue to try and fix this.
     
    chzwhz likes this.
  22. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    You forgot to get rid of line 9
     
  23. spendew

    spendew

    Joined:
    Feb 12, 2012
    Posts:
    104
    UGH! Thank you Diablo! You've been a great help!

    Works perfectly fine now :3
     
  24. Rapskalian

    Rapskalian

    Joined:
    Jan 4, 2011
    Posts:
    45
    NathanBrower likes this.
  25. trollanator5729

    trollanator5729

    Joined:
    May 7, 2018
    Posts:
    5
    For anybody finding this, I would recommend seeing if this will work:
     
  26. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,555
    Cool necro bro