简体   繁体   中英

Unity3d: Adding gameobject to List from an array

Thanks for help in advance. Here is a short snippet of the code that I am having an issue with.

GameObject[] allMotor_array;
public List<GameObject> BrokenMotor_list = new List<GameObject>();
void Start()
{
   allMotor_array = GameObject.FindGameObjectsWithTag ("Motors");
}

void Update()
{        
    foreach (GameObject motor in allMotor_array)
    {
        if(motor.GetComponent<Pump_event>().damaged)
        {
            BrokenMotor_list.Add(motor);
        }
    }

}

I have an array of Gameobjects that is created on Start, each of the gameobjects in the array have a script called Pump_event. What I want to do is add the gameobject with a true boolean (damaged) to the list so that I can create a GUI list of all the motors that are damaged (and then take further action on those motors).

With the current code it instantiates the array fine, but when One of the motors boolean changes to true the list tends to continuously add the motor gameobject to the list on each update cycle. So what I want is to figure out a way of adding the gameobject to the list ONCE.

Having it in the update() is probably not the best method but I really am stuck on how to approach this.

G


The Solution to my problem


Thanks for your answers, you all had well thought out responses. I appreciate it. I didn't go with 1 persons method but instead adapted logical approaches found here to work with my script/s.

Here is what I did. In my pump_event script the events are sorted in a Case and switch as damage increased on the pump the event would escalate. So I added in a section to that script to include "reporting" the damage.

public class Master_script: MonoBehaviour 
public void AddtoList(GameObject motor_tobadded)
{
    BrokenMotor_list.Add(motor_tobadded);
} 

I took advice not to insert these types of programing and placed it into its separate class which works out well.

 public class Master_script: MonoBehaviour public void AddtoList(GameObject motor_tobadded) { BrokenMotor_list.Add(motor_tobadded); } 

This also eliminated the need on having an array holding all of the pump event controllers as well. Now the script all works fine. It may not be most efficient but it is doing its job.

Thank you again to all that helped.

According to the code you have posted, the problem lies within the fact that the damaged property is never reset. One solution would be to reset this property once you add it to the list, like so:

    if(motor.GetComponent<Pump_event>().damaged)
    {
        motor.GetComponent<Pump_event>().damaged = false;
        BrokenMotor_list.Add(motor);
    }

However, multiple copies of the same object could still be added to your list if the motor is damaged again.

To go around this, you could use a HashSet . The hash set will allow only one copy of an object to exist within it, thus, if an object is already present is will not be added again.

The catch is that you will need to override the GetHashCode and Equals methods for your GameObject class since these will be used internally by the hash set to place items within itself and identify duplicates.

check if list already contains motor.

if(motor.GetComponent<Pump_event>().damaged)
    {
        if(BrokenMotor_list.Contains(motor))
        { 
           BrokenMotor_list.Add(motor);
        }
    }

although on msdn describes how to implement IEquatable in case if you want compare different objects(with different references) https://msdn.microsoft.com/ru-ru/library/vstudio/bhkz42b3%28v=vs.100%29.aspx

In your Pump_event Script you can have a event Action which you register in this snippet and whenever damaged is set true you need to fire the event.

Example:

// in Pump_event Class
public static event Action<GameObject> OnDamagedValueChanged;
private bool _damaged;
public bool Damaged
{
    get { return _damaged;}
    set 
    { 
        _damaged = value;
        if(_damaged)
        {
              if(OnDamagedValueChanged != null)
                  OnDamagedValueChanged(gameObject);  
        }
    } 
}

In your Current Class where you have array of GameObjects:

void OnEnable()    
{
    Pump_event.OnDamagedValueChanged += HandleOnDamagedValueChanged;
}
void OnDisable()    
{
    Pump_event.OnDamagedValueChanged -= HandleOnDamagedValueChanged;
}   
void HandleOnDamagedValueChanged(GameObject obj)
{
    if (!BrokenMotor_list.Contains (obj))  
    {
        BrokenMotor_list.Add (obj);
    }
} 

Using Actions is a better approach than doing it in Update Method. It is not good for performance to keep checking for a bool in iteration in update method. and try to avoid GetComponent and Find/FindObjectWithTag Methods in Update. It is not good practice. I hope this is helpful.

if (!BrokenMotor_list.Contains (motor)) {
    BrokenMotor_list.Add (motor);
}

You'd better do this after damage event occur by add a delegate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM