Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Replace random a prefab in a Grid with a random prefab from resources

Discussion in 'Scripting' started by Andreas12345, May 25, 2020.

  1. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    526
    I create a grid with neutral boxes with:
    Code (CSharp):
    1. public class GridManager : MonoBehaviour
    2. {
    3.     public float x_Start, y_Start;
    4.     public int columnLength, rowLength;
    5.     public float x_Space, ySpace;
    6.     public GameObject neutralBoxGrid;
    7.  
    8.     //Create a Grid with the neutral Box
    9.     void Start()
    10.     {
    11.         if (neutralBoxGrid == null)
    12.             neutralBoxGrid = GameObject.FindGameObjectWithTag("neutral");
    13.  
    14.  
    15.         for (int i = 0; i < columnLength * rowLength; i++)
    16.         {
    17.            Instantiate(neutralBoxGrid, new Vector3(x_Start + (x_Space * (i % columnLength)), y_Start + (-ySpace * (i / columnLength))), Quaternion.identity);
    18.  
    19.         }
    20.        
    21.     }
    That gives me for example a grid 2x2 with 4 cloned neutralBoxes

    I like to replace randomly every x seconds 1 of the cloned boxes with a prefab of the resources folder
    In my GameLogicScript i get the boxes with:
    Code (CSharp):
    1. //Make sure the boxes are in
    2.  
    3.         blackBox = Resources.Load("BoxBlack") as GameObject;
    4.         blueBox = Resources.Load("BoxBlue") as GameObject;
    5.         greenBox = Resources.Load("BoxGreen") as GameObject;
    How can i choose a random cloned object, and how do i replace it with 1 prefab of the resource folder every x seconds?
    For a start i created a tagsArray with my boxesPrefabs of the resource folder:

    Code (CSharp):
    1. int  randomIndex = Random.Range(0, 7);
    2.        string randomTag = tagsArray[randomIndex];
    3.        pointObject = GameObject.FindWithTag(randomTag);
    4.         Debug.Log("I found" + pointObject);
    5.         pointObject = pointObjectCount;
     
  2. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    646
    There are a bunch of things you should change.
    the method
    GameObject.FindGameObjectWithTag
    is extremly slow - at this point, it may be ok, because you only check it once your script starts (if it is active by default, this will also be when the game starts) and only if the value is NULL - but the NULL-Check is the next one xD
    Unity does something special when destroying an UnityEngine.Object, thats why you should always use the bool operator overload for any NULL-Check like so:
    if (!neutralBoxGrid)
    without the
    == null

    Because when you destroy the object in the same frame,
    ==  null
    will return false, even when the object is theoretically null.

    Resources.Load
    whatever object you have in your ressources, will be loaded when the game starts. So if you have many objects in your ressources, the game will take ages to load even when just starting the main menu.
    If you assign those objects in the inspector, it will only be loaded when it is needed - so it won't load them in the main menu for example, but when you start your game scene. (also you can rename them without losing the references to them in your scripts / in the inspector)

    You could use a coroutine or InvokeRepeating to execute something every X seconds.

    To identify your objects, there are a lot of ways to do this ..
    For all the solutions that come to my mind right now, you should keep track of your instances.
    Instantiate()
    returns a GameObject, the instance you just created.
    Store this instance in any collection .. it could be a list, or as you said this is a grid with a fixed size - store it in a two dimensional Array
    GameObject[,] instanceGridArray; 
    .

    Option Nr1: Create a new script (MonoBehaviour) and attach it to your cubes. Add a string, enum or int as identifier and store the script instead of the GameObject in your Array
    CubeIdentifier[,] instanceGridArray; 
    ,
    instanceGridArray[x,y] = Instantiate([...]).GetComponent<CubeIdentifier>();
    .
    To check if a cube is of a specific type, just call
    instanceGridArray[x,y].myIdentityValue;
    "myIdentityValue" is of course a field inside the "CubeIdentifier" script which is a "string, enum or int" as mentioned earlier.
    Then you can replace them and update the grid the same way you did, when instantiating the neutral cubes.

    Option Nr2: Basically the same as above but using names for the identity

    Option Nr3: Basically the same as above but you store a custom c# class which is not a monobehaviour in your array and the custom class can hold any information like the identity value - and you don't have to add this information to your instances.

    So you should create a proper data layout for your grid and everything else will be quite simple then.

    Also you should avoid using tags, you only have one tag per object and if two different systems use them, one object cannot be used by both systems ...
     
    Andreas12345 likes this.
  3. Andreas12345

    Andreas12345

    Joined:
    Oct 17, 2013
    Posts:
    526
    Ty,
    i have started so:
    Code (CSharp):
    1. public float changeBoxesEachXSeconds = 0;
    2.         GameObject[] BoxAvatars;
    3.  
    4.         [System.Serializable]
    5.         public class BoxType
    6.         {
    7.             public string name;
    8.             public BoxTypology typology;
    9.             public int odds;
    10.             public GameObject Avatar;
    11.              public AudioClip pickAudioFx;
    12.  
    13.         }
    14.         public BoxType[] boxes;
    15.  
    16.         public enum BoxTypology
    17.         {
    I have it running that 1 box change ever x Seconds with invoke method.
    And i created for it an own script
    I think i can go further now :)
     
    John_Leorid likes this.