Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How to iterate through components

Discussion in 'Scripting' started by Reject76, Jan 7, 2019.

  1. Reject76

    Reject76

    Joined:
    Jun 12, 2015
    Posts:
    38
    Hey hey

    I'm making sort of a Breakout / Arknoid clone and one of the perks is to have the ball turned into a "wrecking ball" where the ball will destroy any bricks it hits without bouncing (i.e. colliding).

    I figure the best way to do this is to set the bricks on the playfield to "istrigger = true" and then have a OnTriggerEnter in the script attached to the bricks.

    Problem is I cant figure out how to iterate through any and all remaining bricks in the playfield. I have the bricks currently set up like this in the hierarchy:

    Bricks (empty gameobject)
    - BrickReg (1)
    - BrickReg (2)
    - BrickReg (3)
    - BrickHard (1)
    - BrickHard (2)
    - etc etc etc

    The bricks can have either tag "BrickReg" or "BrickHard". Sometimes there might be 21 bricks remaining when the perk is activated and sometimes there might only be 2 as they are destroyed (Destroy(this.gameObject))...

    So...I need a logic where I can loop through any remaining gameobjects in the parents folder in the hierchy and then set istrigger to 'true' on these...

    Most problems I've managed to google a solution to, but this one has me beat...I know there is a foreach loop but I'm not quite sure how I should set it up.

    Any help = much appreciated!
     
  2. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    818
    You can use GetComponentsInChildren with RigidBody as type to find them all below your Bricks object.

    Note that this isnt particularly performant. If this happens often, and you see this coming up in the profiler, consider doing this at the beginning and looping over the same array every time. Just check if it has been destroyed (== null) before using the element.
     
  3. Reject76

    Reject76

    Joined:
    Jun 12, 2015
    Posts:
    38
    Many thanks for the suggestions. I found this regarding GetComponentsinChildren, but is there a way to call this from a script on a different object or does it specifically have to sit on the parent object? I guess I could make it a public class to access the components found from other scripts though.

    https://docs.unity3d.com/ScriptReference/Component.GetComponentsInChildren.html

    Regarding arrays - Ive never ever worked with arrays before, not even in my main language (VB). Do you happen to have a link to some documentation on how to work with arrays? Cheers!
     
  4. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Yeah it's all in the Learn Section (above) and the manual. It's a bit much to go into here, but there's two kinds of collections usually (there are many more but you use these two)

    List and Array

    So you'd want to research those. Unity has good support for collections. Hopefully someone else has time to further tutor you but these should get you started.

    You will also need to learn about references vs values because some things held in arrays will be the actual number or basic built-in type (int, float, string etc and these are called value types) and others will be reference to a type that is not built in. These references instead point to the class data it reference (a gameobject for example, or your own thing).

    It matters because when you create an array or list, and put stuff in that list, or ask a function to do so, it will be null or not null (does it exist or not) still per thing in the array, so you need to be making sure that exists too. So add null to things to think about in the future.

    A bit long winded isn't it? but give it time and it will make more sense as you go along, just push through it :)
     
  5. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    818
    As you see in the manual, you can call GetComponentsInChildren on anything that is a Component. When you click on the Component class you see its the base class of everything attached to gameObjects, so you can call it on many types. For example you can get a reference of your Bricks Transform (which inherits from Component, thus has GetComponentsInChildren) and call it. You can get the transform by either putting the script on the Bricks object, or making it public and dragging it in via the inspector.

    The manual for GetComponentsInChildren shows how to loop over them and set a value.
     
  6. Reject76

    Reject76

    Joined:
    Jun 12, 2015
    Posts:
    38
    Many thanks for the help - I have managed to write a piece of code that will set my bricks to isTrigger = true (easy peasy once you understand it...like most things...)

    However I've run into a peculiar issue - the game is an Arknoid clone of sorts. The perk "wreckingball" should be activated when the player picks up another game object (a cylinder).

    The script I have made is on the parent empty gameobject in the hierarchy, like so:

    Bricks (empty gameobject) - SCRIPT (see script details below)
    - BrickReg (1)
    - BrickReg (2)
    - BrickReg (3)
    - etc etc etc

    However, the I'm calling this script from another script that is attached to the perk-cylinder gameobject, using this line of code: SetBrickTriggers.instance.settriggers();

    The perk-cylinder gameobject is itself initiated by this line: Instantiate(Cylinder, brickpos, Quaternion.Euler(0, 0, 90));

    The perk-cylinder will be created in the root of the hierarchy, BUT for some odd reason the perk-cylinder gameobject will be affected by the isTrigger = true while the bricks are unaffected, despite the actual script being on the parent empty gameobject which holds the children bricks...

    Help? I've obviously missed something on how this works...



    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class SetBrickTriggers : MonoBehaviour
    7. {
    8.  
    9.     public Component[] BoxieCollider;
    10.  
    11.     public static SetBrickTriggers instance = null;
    12.  
    13.  
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.  
    18.         BoxieCollider = GetComponentsInChildren<BoxCollider>();
    19.    
    20.     }
    21.  
    22.     // Update is called once per frame
    23.     void Update()
    24.     {
    25.    
    26.     }
    27.  
    28. public void settriggers()
    29.     {
    30.          
    31.  
    32.         foreach (BoxCollider box in BoxieCollider)
    33.             box.isTrigger = true;
    34.  
    35.     }
    36.  
    37.  
    38.     public void resettriggers()
    39.     {
    40.  
    41.         foreach (BoxCollider box in BoxieCollider)
    42.             box.isTrigger = false;
    43.  
    44.     }
    45.  
    46.  
    47. }
    48.  
     
    Last edited: Jan 9, 2019
  7. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    818
  8. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    818
    Lets try some debugging, can you do a Debug.Log on every box. That way you can see which elements are actually set.

    Are you sure the boxcolliders exist when you get them (at Start)?
     
  9. Reject76

    Reject76

    Joined:
    Jun 12, 2015
    Posts:
    38
    Much obliged for your help so far Mr TJHeuvel...

    Unfortunately I dont even know how to use the debug.log namespace...I think I'll have to figure this all out by myself...might take a few more days, but I'll get there :)

    Thanks again!
     
  10. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,732
    Using Debug.Log() is one of the most useful ways to quickly track down problems in code, it's worth getting the hang of using it, and it's not difficult to use.

    https://docs.unity3d.com/ScriptReference/Debug.Log.html

     
  11. toddisarockstar

    toddisarockstar

    Joined:
    Nov 28, 2014
    Posts:
    4
    it is good habit to organize things from the start when deciding to make a project.
    you should really take the time to learn loops and arrays and references. planning a good organizational system for any game saves the developer time and can give a game much more proficiency and FPS. Run this. here is a system where you dont need any game engine lookups and pry don't need any scripts on the blocks.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class breakout : MonoBehaviour {
    5.     GameObject[][] bricks;
    6.  
    7.  
    8.     void Start () {
    9.          int x,y;
    10.         // make yer bricks
    11.         x = 10;
    12.         bricks = new GameObject[x][];
    13.         while(x>0){x--;
    14.             y = 5; bricks[x] = new GameObject[y];
    15.             while(y>0){y--;
    16.                 bricks[x][y] = GameObject.CreatePrimitive(PrimitiveType.Cube);
    17.                 bricks[x][y].transform.position = new Vector3(x,y,0);
    18.                 bricks[x][y].transform.name = x+" "+y;
    19.                 bricks[x][y].collider.isTrigger = true;
    20.             }}
    21.  
    22.         // now you can refer to your brick gameobjects with coodinates like this:
    23.         bricks [2][3].transform.renderer.material.color = Color.green;
    24.  
    25.         // search bricks like this
    26.         for (x = 0; x < bricks.Length; x++) {
    27.         for (y = 0; y < bricks[x].Length; y++) {
    28.  
    29.                 if(bricks[x][y].transform.renderer.material.color == Color.green){
    30.                     print (x+","+y+" is green");
    31.                 }}}
    32.  
    33.         // page through a row like this
    34.         for (x = 0; x < bricks.Length; x++) {
    35.             bricks[x][0].transform.renderer.material.color = Color.red;
    36.        
    37.         }
    38.    
    39.    
    40.     }
    41.  
    42.  
    43.  
    44.  
    45.    
    46.  
    47. }
    48.