how do I access values from a script which is attached to a list’s elements and count them?

Hi,

I’m working on a model to simulate a population. I have a script that lets me spawn citizens and assigns them to a list as elements. These clones are based on a prefab which has several more scripts attached to it. One of it contains information about a citizen’s profession. For example, it determines if a citizen is employable or not based on his/her age. I want to find out how many citizens are currently employable in total. So how do I access values from a script which is attached to a list’s elements and count them?

What I have done so far: I created an empty game object with the following script attached to it in order to spawn the citizens. it is also supposed to tell me demographic facts about the employment status:
`

public GameObject citizen;
public int totalCitizens;
public Text totalCitizensText;
public int totalEmployedCitizens;
public Text totalEmployedCitizensText;
public int totalEmployableCitizens;
public Text totalEmployableCitizensText;
public int totalUnfitCitizens;
public Text totalUnfitCitizensText;
public float unemploymentRate;
public Text unemploymentRateText;

public List<GameObject> CitizenRegister = new List<GameObject>();

void Update()
{
    if (Input.GetKey(KeyCode.Space)) // add a lot quickly
    {
        CitizenRegister.Add( (GameObject)Instantiate(citizen, new Vector3(1 * Random.Range(-10, 10), 0, 1 * Random.Range(-10, 10)), Quaternion.Euler(0, 0, 0)));
    }
    if (Input.GetKeyDown(KeyCode.N)) // add a single one
    {
        CitizenRegister.Add((GameObject)Instantiate(citizen, new Vector3(1 * Random.Range(-10, 10), 0, 1 * Random.Range(-10, 10)), Quaternion.Euler(0, 0, 0)));
    }

    //Remvoe missing elements
    for (var i = CitizenRegister.Count - 1; i > -1; i--)
    {
        if (CitizenRegister *== null)*

CitizenRegister.RemoveAt(i);
}
//Count all citizens
totalCitizens = CitizenRegister.Count + 1; // + 1 because of player
totalCitizensText.text = "Population: " + totalCitizens;
//Count all employable citizens
totalEmployableCitizens = ; // Employable if citizen is not unfit for work (professionNumber 1)
totalEmployableCitizensText.text = "Employable: " + totalEmployableCitizens;
/*
//Count all employed citizens
totalEmployedCitizens = ; // don’t forget the player
totalEmployedCitizensText.text = "Employed: " + totalEmployedCitizens;

//Count all citizens who are unfit for work
totalUnfitCitizens = 0; // don’t forget the player
totalUnfitCitizensText.text = "Unfit for work: " + totalUnfitCitizens;
//Calculate unemplyoment rate
unemploymentRate = 100 * totalEmployedCitizens / totalEmployableCitizens;
unemploymentRateText.text = "Unemplyoment rate: " + unemploymentRate.ToString(“0”) + “%”;*/
}
* *As can be seen, I'm stuck at this line:* *

totalEmployableCitizens = ; // Employable if citizen is not unfit for work (professionNumber 1)
* *The information about the profession of a citizen is in the script below. It is attached to the GameObject "citizen".* *

public bool emplyoed;
public bool unfitForWork;
public int retirementAge;
public int professionNumber;
public string profession;
public Text professionText;
public float AgeCurrent;

  • // Use this for initialization*

  • void Start () {*
    retirementAge = 65;
    professionNumber = 0;

  • }*

  • // Update is called once per frame*

  • void Update () {*
    //Profession determination
    if (citizens.age < 18 | citizens.age >= retirementAge)
    {
    professionNumber = 1;
    }

//Profession List
if (professionNumber == 0)
{
profession = “none”;
}
else if (professionNumber == 1)
{
profession = “unfit”;
}
else if (professionNumber == 2)
{
profession = “food producer”;
}
else if (professionNumber == 3)
{
profession = “water producer”;
}
else
{
profession = “none”;
}
//UI
//professionText.text = "Profession: " + profession;

}
`
Please feel free to give me additional notes as I am fairly new to c# and unity, for example if it is better to have an array in this case.
Thanks a lot for your help!

  • In general you can utilize a for, or
    forEach loop to check through your
    list.
  • You then need to define the condition
    to be met.
  • At this point you can access the data
    by utilizing the iterator variable.
  • Make sure in your Citizen Class that
    you make the variable you want to
    access public.

Example is below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CheckCitizens : MonoBehaviour {

    private List<Citizen> allCitizens;

    private void Start() {
        allCitizens = new List<Citizen>();
        // For this example I'll just add 10 citizens to the list
        for (int i = 0; i < 10; i++) {
            //Create instance of Citizen...
            Citizen newDood = new Citizen();
            //Assign an age...
            newDood.age = i + 10;
            //Assign a random name...
            newDood.name = "Person" + Random.Range(0, 100);
            //Add citizen to the list of AllCitizens
            allCitizens.Add(newDood);
        }

        CheckAgeOfCitizen();

    }
    //This method access the values inside of the List of Citizens (as per your question)
    public void CheckAgeOfCitizen() {
        //Use a for loop to check the List. If you want to check ALL of the list
        //use the ".Count" keyword to get the size of the list
        //The conditional is up to your design.
        for (int i = 0; i < allCitizens.Count; i++) {
            //Here we access the value of "age" directly
            //We can even check to see if the age is one we are looking for
            //In this case we will check how many are over age "13"
            if (allCitizens*.age > 13) {*

Debug.Log(allCitizens_.name + “(” + allCitizens*.age + “)” + " - is over the age of 13");
} else {
Debug.Log(allCitizens.name + " is " + allCitizens.age + " years old.");
}*_

}
}

}

Just put this code into a script and it’ll run the example, read the debug.log
As a note, you should make a List of Citizens, and in the Citizen class define the variables that are appropriate to the Citizen. My Citizen class of this example is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Citizen {
public string name;
public int age;
}

Hope this helps.
Also, just a pointer about the update function… read below.

Ok, I’ve changed the example to be more resembling your design.

  • Make a Citizen class > extend
    MonoBehavior like normal, add this to
    the prefab object

  • When you instantiate the prefab into
    your scene, we set the values for
    that unique citizen

  • At the same time, we add the Citizen
    to a list that we can access at a
    later point in time

  • Note the syntax to get the specific
    component values

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class CheckCitizens : MonoBehaviour {
    [SerializeField]
    GameObject randomCitizen;

     public List<Citizen> allCitizens;
    
     private void Start() {
         allCitizens = new List<Citizen>();
         //making 10 random citizens
         for (int i = 0; i < 10; i++) {
             //instantiate the prefab object to the scene
             GameObject obj = Instantiate(randomCitizen);
             //place it somewhere random
             obj.transform.position = new Vector3(Random.Range(0, 10), 5, Random.Range(0, 10));
             //assigning the age of the citizen
             obj.GetComponent<Citizen>().age = Random.Range(10, 50);
             //assigning a random name
             obj.GetComponent<Citizen>().objectName = "Citizen" + Random.Range(1, 100);
             //adding this individual citizen to the List, so we can check its values later on
             allCitizens.Add(obj.GetComponent<Citizen>());
         }
    
         CheckAgeOfCitizen();
    
     }
     //This method access the values inside of the List of Citizens (as per your question)
     public void CheckAgeOfCitizen() {
         //Use a for loop to check the List. If you want to check ALL of the list
         //use the ".Count" keyword to get the size of the list
         //The conditional is up to your design.
         for (int i = 0; i < allCitizens.Count; i++) {
             //Here we access the value of "age" directly
             //We can even check to see if the age is one we are looking for
             //In this case we will check how many are over age "13"
             if (allCitizens*.age > 13) {*
    

Debug.Log(allCitizens_.objectName + “(age: " + allCitizens*.age + “)” + " - is over the age of 13”);
} else {
Debug.Log(allCitizens.objectName + " is " + allCitizens.age + " years old.");
}
}
}
}*

If your CheckCitizens Class equivalent is a Singleton, then you will be able to keep track of all the citizens as they live in your scene.
Note I changed the Citizen class variable “name” to “objectName”. I forgot “name” is actually a keyword to the Object class.
You can attach the above scrip to any object in the scene. Then drag and drop the Citizen prefab(with the Citizen class scrip) into the [SerializedField] randomCitizen.
Everything should work. :wink:
Note: My citizen object prefab is a cube with a RidgidBody and a BoxCollider._