Home > Software design >  Objects continue to be added to the List
Objects continue to be added to the List

Time:01-17

I have 2 Targets in the world that I want to add to a list when the Player comes close to them.

I first use the Physics OverlapBox method to return an array of colliders. After this, I run a for loop in which the 2 targets should get added to the list. Only 2 target objects are in the scene but the list gets occupied with hundreds of copies of those objects.

Code Down below

private void TrySelectTarget(bool switchInput)
{
    targetArray = Physics.OverlapBox(transform.position, range, Quaternion.identity, targetLayer, QueryTriggerInteraction.Ignore);
    for (int i = 0; i < targetArray.Length ; i  )
    {
        if (targetArray[i].TryGetComponent<Target>(out Target target))
        {
            availableTargets.Add(target);
            
        }
    }      
}

I did a deblug.Log on targetarray.Length and it returned 2, so I don't understand why so many objects are being added to the availableTargets List. I am calling the TrySelectTarget() method in Update().

I am new to c# and programming, so apologies if I am making a stupid mistake.

Thank you for the help.

CodePudding user response:

I think you either want to

 availableTargets.Clear();

first so you start with an empty list every time, as anyway you seem to only be interested in the targets overlapping in that instance.


Or you could use Link and do e.g.

using System.Linq;

...

private void TrySelectTarget(bool switchInput)
{
    availableTargets = Physics.OverlapBox(transform.position, range, Quaternion.identity, targetLayer, QueryTriggerInteraction.Ignore)
        .Select(col => col.GetComponent<Target>())
        .Where(target => target)
        .ToList();
}

CodePudding user response:

With your code everytime Physics.OverlapBox returns hits you add the same objects that have already references stored in the list, again. To simply solve the issue of not having duplicates being stored you should check if an object is already referenced (has an entry in the list). Do that by doing:

if (targetArray[i].TryGetComponent<Target>(out Target target))
{
    if (!availableTargets.Contains(target)) availableTargets.Add(target);
        
}

That will not solve the issue of targets not being removed when not in range anymore though. If that is needed then you should change your code so that the list gets cleared before any new references are being added. You could do:

availableTargets.Clear();
targetArray = Physics.OverlapBox(transform.position, range, Quaternion.identity, targetLayer, QueryTriggerInteraction.Ignore);
for (int i = 0; i < targetArray.Length ; i  )
...

The better solution to solve for this problem in general is to make use of OnTriggerEnter() and OnTriggerExit() messages provided through a Rigidbody component. Those Methods only get invoked if at least one of the interacting objects has a Rigidbody component. Add a Rigidbody to your player object and a collider with the size of the detection range/zone size and set this collider to be IsTrigger. If you dont want that physics affects the object just check the IsKinematic option on the Rigidbody component. In a script on the player then do:

private void OnTriggerEnter (Collider other)
{
    if (other.TryGetComponent<Target>(out Target target))
    {
        // check if not present already to be 100% sure not to get duplicates
        // even though it generally shouldn't be happening, better safe than sorry
        if (!availableTargets.Contains(target))
        {
            availableTargets.Add(target);
        }

    }
}

private void OnTriggerExit (Collider other)
{
    if (other.TryGetComponent<Target>(out Target target))
    {
        availableTargets.Remove(target);
    }
}
  • Related