Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by EuRoKa · Jul 12, 2017 at 06:40 PM · listvaluesaccessing scripts

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[i] == 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!

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Mercbaker · Jul 13, 2017 at 12:04 AM

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[i].age > 13) {
                     Debug.Log(allCitizens[i].objectName + "(age: " + allCitizens[i].age + ")" + " - is over the age of 13");
                 } else {
                     Debug.Log(allCitizens[i].objectName + " is " + allCitizens[i].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. ;)

Note: My citizen object prefab is a cube with a RidgidBody and a BoxCollider.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
2

Answer by Mercbaker · Jul 12, 2017 at 07:22 PM

  • 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[i].age > 13) {
                 Debug.Log(allCitizens[i].name + "(" + allCitizens[i].age + ")" + " - is over the age of 13");
             } else {
                 Debug.Log(allCitizens[i].name + " is " + allCitizens[i].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.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Mercbaker · Jul 12, 2017 at 07:27 PM 1
Share

You should be careful what you put in the update function, because it runs every frame. Your current code will not cause much problems, because simple conditionals like those should process pretty quick. But you don't need to check every frame for those changes.

Ins$$anonymous$$d, check right after the variable changes.

If you have a function that is changing a variable, put an if statement right after the variable change to check if it meets the appropriate criteria.

This way, you don't need to check every frame for the change.

Again, be careful what you check for in the Update function, it can create a lot of unnecessary processing work.

avatar image EuRoKa Mercbaker · Jul 12, 2017 at 10:06 PM 0
Share

You are absolutely right about my failure to use anything other but the Update function. Right now I’m able to run around 400 citizens simultaneously until the system lags. I will also add scripts in the future to let citizens trade automatically among each other according to their needs and finances. By using Update I can probably be happy if my computer manages to compute 50 citizens at once. $$anonymous$$y main need script (responsible for hunger, thirst, status, etc.) runs in an IEnumerator function where it is supposed to wait 3 seconds. By doing this I thought it would calculate everything only every 3 seconds but I doubt it is actually working. You are recommending to put an if statement after variable changes. How exactly do I do that? I tried something similar before where I asked for a bool to be true before the calculation was made. For example, I didn’t want to have the total food and water demand (which makes a citizen decide to invest in a farm) calculated every frame but ins$$anonymous$$d only five times a month so I tried this:

          // Demands
         /*if (demand$$anonymous$$anager.demandAct == true)
         {
             demand$$anonymous$$anager.foodDem = demand$$anonymous$$anager.foodDem + hunger; //sending the hunger info of a single citizen to be added up in the demand$$anonymous$$anager script
             demand$$anonymous$$anager.waterDem = demand$$anonymous$$anager.waterDem + thirst;
             demand$$anonymous$$anager.demandAct = false; // closing the statement to skip it for a few days
         }

        if ((days == 1 && hours == 1) | (days == 7 && hours == 1) | (days == 13 && hours == 1) | (days == 19 && hours == 1) | (days == 25 && hours == 1))
     {
         if (demand$$anonymous$$anager.foodDem > 0 | demand$$anonymous$$anager.waterDem > 0)
         {
             demand$$anonymous$$anager.foodDem = 0;
             demand$$anonymous$$anager.waterDem = 0;
         }
         demand$$anonymous$$anager.demandAct = true;
     }

However, this does not work as every citizen runs the same script and the first one who finishes the if statement sets the Boolean to false, thereby denying access to it for everyone else. Anyway, I guess this is going to require a new thread as I understand only one question per post is allowed in this forum - sorry for straying from the subject and the long post. Thanks again for your help! I hope I’ll be good enough one day to return the favor.

avatar image Mercbaker EuRoKa · Jul 13, 2017 at 12:35 AM 0
Share

If your Object is having its variables changed, just include an if statement right under the change to send a signal that the Object is ready to have something happen.

So, if its hunger...

 //call this method on the object when you need to 
 public void IncreaseHunger(int amount) {
 
     hunger += amount;
     if (hunger >= 30) {
 
         Citizen$$anonymous$$anager.Instance.HandleCitizenHunger();
 
     }
 

So with the above, ins$$anonymous$$d of checking literally thousands of times, we can actually just check only when the variable changes.

The problem you may be facing is that maybe you haven't designed your project to be Object oriented in nature.

You may be mixing unrelated work in your Classes functions. But yeah, overall, this is just something to think about.

Try to find ways to eli$$anonymous$$ate the Update calls and you can probably increase the Citizen count far beyond 400.

avatar image EuRoKa · Jul 12, 2017 at 10:06 PM 0
Share

Thanks so much for your help! I tried to run your code separately from my scripts to see how exactly it works. Unfortunately, I’m having problems with your Citizen Class. Where exactly should I put it? When I copy it in a script and try to attach it to a cube (serving as a NPC prefab) it doesn’t let me as it wants to be a $$anonymous$$onoBehaviour, I guess. It also does not work when I put in on top of the CheckCitizens script.

As to applying your example to my script, I see that line 35 in your code looks exactly like what I was looking for. When it says allCitizens[i].age, it shows an error as I haven’t declared age without the citizen class. In my case, age is declared in another script that is also attached to my citizen prefab. In this script, age is based on calculation referring to a time script which works outside and independent of the whole list and citizen scripts. By now, I have a need, personality and attribute system in five scripts which are all attached to the citizen prefab. I just wish, I could write a code like “: if (allCitizens[i].citizenBasicInfo.age > … “ inside the for loop to refer directly to the script where age is defined. As that is not possible, does it mean, I need to copy all five scripts in your Citizen class and put it in the same script where I declare the list?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

70 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

A node in a childnode? 1 Answer

How to assign saved transform values(tr,rot,sc) from a List, to the same gameobject ? 1 Answer

Changing gameobjects Float from another script? 1 Answer

how can I get values stored in a list? 3 Answers

How can I get all array/list values within a given range? 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges