Search Unity

Question Making sure every object from a list has been used

Discussion in 'Scripting' started by thewonderingvagabond, Apr 22, 2023.

  1. thewonderingvagabond

    thewonderingvagabond

    Joined:
    Mar 11, 2023
    Posts:
    16
    I am trying to instantiate objects from a list using the following code.

    Code (CSharp):
    1.    [SerializeField] public List<GameObject> stitches = new List<GameObject>();
    2.     public List<GameObject> spawnedStitches = new List<GameObject>();
    3.     [SerializeField] private Transform[] trackPoints;
    4.  
    5.     // Start is called before the first frame update
    6.     void Start()
    7.     {
    8.         Spawnstitches();
    9.     }
    10.  
    11.     // Update is called once per frame
    12.     void Update()
    13.     {
    14.        
    15.     }
    16.  
    17.     void Spawnstitches()
    18.     {
    19.         if(stitches.Count < trackPoints.Length)
    20.         {
    21.             //add black stitches to the stitches list while loop
    22.             Debug.Log("not enough stitches");
    23.         }
    24.  
    25.         if(stitches.Count == trackPoints.Length)
    26.         {
    27.             for (int i = 0; i <stitches.Count; i++)
    28.             {
    29.                 GameObject newStitch = Instantiate (stitches[Random.Range(0, stitches.Count)], trackPoints[i].position, Quaternion.identity);
    30.                 spawnedStitches.Add(newStitch);
    31.             }
    I want to make sure the stitches here are randomly instantiated, but how can I make sure all the items in the list are used? Or should I be looking at different methods for what I'd like to achieve?
     
  2. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    797
    You could shuffle the list and then just loop through it
     
  3. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,105
    1) what flashframe told you above
    Code (csharp):
    1. shuffle the list
    2. go over the items
    See Fisher-Yates shuffle

    2) you make another list of bools or integers and book-keep
    Code (csharp):
    1. make a list B that is of same size
    2. maintain some counter (starting from 0)
    3. pick a random index, check B[index]
    4. use the item only if B[index] is not used, set it to used (increment the counter)
    5. repeat from 3 until counter == list count
    3) if you have fewer items than 32, you can do the same thing with integer flags
    Same algorithm as (2) but you don't need a list. Instead you build powers of two and store that to a 32-bit integer:
    you test whether the item was used by doing
    state & (1 << index) > 0

    then you set the state by doing
    state |= (1 << index)


    4) you remove items from the list
    Code (csharp):
    1. pick a random index
    2. remove the item with Remove(index)
    3. repeat until the list is empty
    5) you don't actually remove items from the list (because that's slow), but you pretend like you do
    Code (csharp):
    1. set some counter X to list count
    2. pick a random index from 0..X (exclusive)
    3. swap that item with the last item (at X-1), decrement X by 1
    4. repeat from 2 until X is 0
    My recommendation is either (1) or (5).
     
    Bunny83, flashframe and mopthrow like this.
  4. thewonderingvagabond

    thewonderingvagabond

    Joined:
    Mar 11, 2023
    Posts:
    16
    Thank you so much for your replies! However, this is going way over my head unfortunately, especially as I wanted to do things with the list later and I am just a beginner trying to make its own project without typing over another tutorial.

    I have 10 gameobjects of different colours that the player needs to 'tag'. At the end of the round, I calculate which ones are tagged by having a bool set to true oncollision. If the player only tagged fe 8/10 the next level will have 2/10 objects disabled. I had difficulties identifying which colours have not been tagged when using these lists and have gone back to setting every object separately (instead of randomly with a random colour) with its own script and it's separate bools. Now I'm ending up checking 10 if-statement to see which colours to place in the next level. It should work now, I don't think this is the best way to do it though. If anyone has some ideas, I would love to read them. If I should be using lists, I will look back at the project after getting more experience. Thanks!
     
    MelvMay likes this.
  5. NikMikk

    NikMikk

    Joined:
    Nov 4, 2015
    Posts:
    25
    How about separating the logic into two scripts like this:

    Code (CSharp):
    1. public class StichObject : MonoBehaviour
    2. {
    3.     public Color color;
    4.     public bool collected; // Mark as collected during collision as you're already doing
    5. }
    6.  
    7. public class StichSpawner : MonoBehaviour
    8. {
    9.     [SerializeField] private Transform[] trackPoints;
    10.     [SerializeField] public List<StichObject> stitches = new List<StichObject>();
    11.     public List<StichObject> spawnedStitches = new List<StichObject>();
    12.  
    13.     // Start is called before the first frame update
    14.     void Start()
    15.     {
    16.         Spawnstitches();
    17.     }
    18.  
    19.     void Spawnstitches()
    20.     {
    21.         if(stitches.Count < trackPoints.Length)
    22.         {
    23.             //add black stitches to the stitches list while loop
    24.             Debug.Log("not enough stitches");
    25.         }
    26.  
    27.         if(stitches.Count == trackPoints.Length)
    28.         {
    29.             for (int i = 0; i <stitches.Count; i++)
    30.             {
    31.                 StichObject newStitch = Instantiate (stitches[Random.Range(0, stitches.Count)], trackPoints[i].position, Quaternion.identity);
    32.                 spawnedStitches.Add(newStitch);
    33.             }
    34.         }
    35.     }
    36. }
    Now you can loop over the stitches and check if they are collected and their color
    Code (CSharp):
    1.  
    2. for (int i = 0; i < spawnedStitches.Count; i++)
    3. {
    4.    if(spawnedStitches.isCollected)
    5.    {
    6.       // Do stuff
    7.    }
    8.  
    9.    Check the collected object's color like this
    10.   if(spawnedStitches[i].color == someColorOrCondition)
    11. }
    12.  
     
    Last edited: Apr 23, 2023
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,455
    Here's an overview of one of the techniques mentioned above:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Collections;
    3. using UnityEngine;
    4.  
    5. public class RandomFromList : MonoBehaviour
    6. {
    7.     void Start()
    8.     {
    9.         // Populate a list of GameObjetcs.
    10.         var myList = new List<GameObject>();
    11.         for (var n = 0; n < 10; ++n)
    12.         {
    13.             myList.Add(new GameObject($"#{n}"));
    14.         }
    15.  
    16.         // Iterate until no more GameObjects are left.
    17.         while (myList.Count > 0)
    18.         {
    19.             // Choose random index from current list.
    20.             var index = Random.Range(0, myList.Count);
    21.  
    22.             // Fetch the random GameObject.
    23.             var go = myList[index];
    24.             Debug.Log(go.name);
    25.  
    26.             // Remove the GameObject at the random index.
    27.             // For speed, swap the last one to this index as it stops everything above
    28.             // this index from being copied down in memory which "RemoveAt(index)" does.
    29.             myList.RemoveAtSwapBack(index);
    30.         }  
    31.     }
    32. }
    33.  
     
    mopthrow likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    There is a reason for tutorials. How is asking us to laboriously explain it to you here any different than you doing it in a tutorial and then looking it up properly in documentation as you go?

    You actually ARE looking EVERYTHING up in the documentation as you go, correct? If you are not then you are just a monkey at a keyboard, whether you are typing it from this forum or from a tutorial.

    Imphenzia: How Did I Learn To Make Games:



    Tutorials and example code are great, but keep this in mind to maximize your success and minimize your frustration:

    How to do tutorials properly, two (2) simple steps to success:

    Step 1. Follow the tutorial and do every single step of the tutorial 100% precisely the way it is shown. Even the slightest deviation (even a single character!) generally ends in disaster. That's how software engineering works. Every step must be taken, every single letter must be spelled, capitalized, punctuated and spaced (or not spaced) properly, literally NOTHING can be omitted or skipped.

    Fortunately this is the easiest part to get right: Be a robot. Don't make any mistakes.
    BE PERFECT IN EVERYTHING YOU DO HERE!!


    If you get any errors, learn how to read the error code and fix your error. Google is your friend here. Do NOT continue until you fix your error. Your error will probably be somewhere near the parenthesis numbers (line and character position) in the file. It is almost CERTAINLY your typo causing the error, so look again and fix it.

    Step 2. Go back and work through every part of the tutorial again, and this time explain it to your doggie. See how I am doing that in my avatar picture? If you have no dog, explain it to your house plant. If you are unable to explain any part of it, STOP. DO NOT PROCEED. Now go learn how that part works. Read the documentation on the functions involved. Go back to the tutorial and try to figure out WHY they did that. This is the part that takes a LOT of time when you are new. It might take days or weeks to work through a single 5-minute tutorial. Stick with it. You will learn.

    Step 2 is the part everybody seems to miss. Without Step 2 you are simply a code-typing monkey and outside of the specific tutorial you did, you will be completely lost. If you want to learn, you MUST do Step 2.

    Of course, all this presupposes no errors in the tutorial. For certain tutorial makers (like Unity, Brackeys, Imphenzia, Sebastian Lague) this is usually the case. For some other less-well-known content creators, this is less true. Read the comments on the video: did anyone have issues like you did? If there's an error, you will NEVER be the first guy to find it.

    Beyond that, Step 3, 4, 5 and 6 become easy because you already understand!

    Finally, when you have errors, don't post here... just go fix your errors! Here's how:

    Remember: NOBODY here memorizes error codes. That's not a thing. The error code is absolutely the least useful part of the error. It serves no purpose at all. Forget the error code. Put it out of your mind.

    The complete error message contains everything you need to know to fix the error yourself.

    The important parts of the error message are:

    - the description of the error itself (google this; you are NEVER the first one!)
    - the file it occurred in (critical!)
    - the line number and character position (the two numbers in parentheses)
    - also possibly useful is the stack trace (all the lines of text in the lower console window)

    Always start with the FIRST error in the console window, as sometimes that error causes or compounds some or all of the subsequent errors. Often the error will be immediately prior to the indicated line, so make sure to check there as well.

    Look in the documentation. Every API you attempt to use is probably documented somewhere. Are you using it correctly? Are you spelling it correctly?

    All of that information is in the actual error message and you must pay attention to it. Learn how to identify it instantly so you don't have to stop your progress and fiddle around with the forum.
     
  8. thewonderingvagabond

    thewonderingvagabond

    Joined:
    Mar 11, 2023
    Posts:
    16
    Thanks for all the insights. Don't get me wrong, in the end here I was not asking for others to write my code, I just need to be pushed in the right direction I guess.

    I followed tutorials and then made some small projects based on the tutorials I did so in a way this was doing step 2. But understanding a concept that was applied in a certain way and copying this is different to trying to apply it in a different way in a different type of game. What makes it difficult to google as well is that there is no one way of doing things.

    For example, I made object pools for bullets using lists using a tutorial, but now I need this list to do other things. After having read the documentation for 3 hours and seeing 5 people doing things differently on google, I could not think clearly on anything anymore, hence my question. I went back to basic if functions (a lot) to make the game work. After this I intend to do the same but now using lists as mentioned above and just play around with them.

    Thanks for the help everyone, enjoying the learning process and hope to get better every day!
     
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    This is a FANTASTIC way to do Step #2. Really... it's the best way.

    In your paragraph here:

    ... what I see above is far too much to be digested in one effort.

    As with any engineering effort, break it up into steps, and don't be afraid to do the work yourself at first, even if ultimately you want the computer to do it.

    Let's say you want the computer to randomly place 10 objects of random colors. That's great. But right now just PLACE ten objects and hand-assign ten random colors.

    That puts it behind you, lets you move forward.

    Now work on the "tagging." What does that mean? Does it mean adding a tag? Marking it with a different color? Something else? Do tutorials for small games that have a type of tagging mechanism and learn what they do to consider something tagged. Do they add it to a list of tagged objects? Great! DO that!

    Study how they show the score, which might be the count of tagged items. Do they keep their own counter that they increment each time? Great! Do that! Or do they simply count the items within the list? If so, try that!

    The key is it is all about layering on small tiny "chunks" of knowledge that you can explain fully to anyone, your dog or your grandma for example, and then ideally coming back and REDOING it tomorrow, or just reviewing all of it again tomorrow. If you come back three days (or three sessions) in a row and review what you have done, you're gonna be amazed at how much it has become part of your reasoning processes for the next part of your game.

    Now go back and start a fresh scene and script and see if you can sprinkle ten cubes randomly around the scene. Review tutorials to do this. Once you have it, see if you can randomly colorize them.

    Now bring the two parts together: put your tagging mechanism in place with the computer-generated scene. All of a sudden you are making content and playing it at the same time! MAGIC!