Comparing 2 lists not working

Hello,

In the game I am making, I am trying to make the turret change its target if there is no longer a line of sight. I do this by setting the next enemy in the ‘enemiesInRange’ list which I sort by distance. This bit is working fine. However, the problem is that when the ‘enemiesInRange’ changes, I compare the newly changed list with the list before the change so I can try again to look for the closest enemy. But my way of comparing the lists doesn’t seem to work.

if (enemiesInRange.Count != 0){
            enemiesInRange = enemiesInRange.OrderBy(x => Vector3.Distance(transform.position, x.transform.position)).ToList();
            if(!IsSame(oldList, enemiesInRange))
                enemyIndex = 0;
                
            target = enemiesInRange[enemyIndex];
        }
private bool IsSame(List<Transform> l1, List<Transform> l2) {
        if (l1.Count != l2.Count)
            return false;
        for (int i = l1.Count; i == 0;i++) {
            if (l1[i] != l2[i])
            return false;
        }
        return true;
    }

How can I better compare these lists or do I need to come up with a new way of logic? Pls help I might be going crazy!

Seems like your for loop is not doing anything. You initialize i to count and then compare it to 0… and increment it.
I think it should be:
for(int i = 0; i < l1.Count; i++){
either that or
for(int i = l1.Count - 1; i >= 0; i–)[

4 Likes

That was a little thing I had changed and forgot to revert it :). But it seems like that wasn’t the problem. The problem is that the ‘oldList’ doesn’t get set to the new list after comparing them for some reason. So the script gets stuck with setting the ‘enemyIndex’ to 0. I honestly have no clue why this happens.

private void UpdateTarget(){
        GameObject[] enemies = GameObject.FindGameObjectsWithTag(enemyTag);
        List<Transform> oldList = enemiesInRange;
        enemiesInRange.Clear();

        foreach (GameObject enemy in enemies){
            if(Vector3.Distance(transform.position, enemy.transform.position) <= buildingInfo.range)
                enemiesInRange.Add(enemy.transform);
        }

        if (enemiesInRange.Count != 0){
            enemiesInRange = enemiesInRange.OrderBy(x => Vector3.Distance(transform.position, x.transform.position)).ToList();
            if(!IsSame(oldList, enemiesInRange))
                enemyIndex = 0;
                
            target = enemiesInRange[enemyIndex];
        }
        else{
            target = null;
            hasLineOfSight = false;
            inLineOfSight = false;
        }
    }

This is the function that repeats every 0.5 seconds. And maybe when going into more detail; the problem is that there are 2 targets and when I obstruct the furthest nothing happens as expected. However, when I moved the turret, the furthest one that was obstructed became the closest target. Thus changing the list ‘enemiesInRange’ and the difference in the order of the list. This change gets picked up by the ‘IsSame’ function and the if state runs setting the ‘enemyIndex’ to zero. So far it’s expected but then the problem comes, in the next cycle the ‘oldList’ should be set to the new ‘enemiesInRange’ but that somehow doesn’t happen and the script is stuck setting the ‘enemyIndex’ to zero and thus freezing the turret because the target is obstructed. It doesn’t get fixed even if I unobstruct and reobstruct the target at this point because the script is just stuck setting the index to 0 all the time.

I hope this makes sense. I have tried a few ways but those didn’t work. For example, making a global variable for the ‘oldList’ instead of a local one but that didn’t seem to fix it.

Without looking at this closer, the only thing that comes to mind initially is - is this because arrays are passed by reference not value? When you assign oldList to enemiesInRange and then clear enemiesInRange - you clear oldList as well. You may need to clone the list? Might that be the problem?

1 Like

I’m going to guess it is because you have set oldList to a reference of enemiesInRange and then you immediately clear enemiesInRange which clears oldList. You need to make a copy of the actual list.

1 Like

Yeah, that’s what I thought too. Passing by reference… still gets me sometimes.

Ok guys found the solution xD.

enemiesInRange.Clear()

This ^ doesn’t completely reset the list, only gets rid of the values of the list contents. The count doesn’t get set to 0. The fix was:

enemiesInRange = new List<Transform>();

This way I make a completely new list with the count 0. So the count doesn’t get stacked up like the previous line which ends up making the old list and the new list not the same. Every time when I would update the ‘oldList’ even if the contents are the same the count changes nonetheless.

That also changes oldList… just be aware of that.

No, it doesn’t. I first set the ‘oldList’ and then reset the ‘enemiesInRange’, cloning the list this way. Later in the function, you can see that the ‘enemiesInRange’ gets filled up again. That’s when I compare the new scan with the previous scan. Changing the ‘oldList’ every loop is the point.

When you do that, oldList is cleared as well. That’s what I was talking about. Glad you got it figured out.

Oh, you meant that the ‘oldList’ gets reset every time I make a new loop? Yeah, that wasn’t the problem at all. And I am not dumb to miss something as simple as that xD. I don’t need the ‘oldList’ outside of this loop and do not need to store it. I just had to clone the old ‘enemiesInRange’ with the new one after the new loop had run. It seems you guys tried looking at the wrong part of the script.

Nope. We were not looking at anything wrong. You may have fixed your error though. In your original script you said enemyIndex was getting stuck at 0 and we told you why. There are three sections of code above that that matter:

List<Transform> oldList = enemiesInRange;
        enemiesInRange.Clear();

 foreach (GameObject enemy in enemies){
            if(Vector3.Distance(transform.position, enemy.transform.position) <= buildingInfo.range)
                enemiesInRange.Add(enemy.transform);
        }

if(!IsSame(oldList, enemiesInRange))
                enemyIndex = 0;

First, you clear enemiesInRange - which also clears oldList. Then you potentially add some transforms to enemiesInRange - which also adds them to oldList.
Finally you compare the lists… they are always going to be the same so enemyIndex will always be 0.

Cool you fixed your code but nobody was looking at it wrong.

The problem was indeed that the ‘enemyIndex’ got stuck to 0. But what you are saying is that the previous ‘enemiesInRange’, which is before the new loop got cloned to the ‘oldList’ before getting cleared. After I clear it, whatever I do to ‘enemiesInRange’ doesn’t change the ‘enemiesInRange’ because this is cloned to ‘oldLIst’. And I do not change ‘oldList’ throughout the loop whatsoever. It only gets reset when the loop runs again which then gets set to the new ‘enemiesInRange’. As I said, the problem was that the length of the list was not getting reset like the contents which caused the 2 lists to have different total lengths. So when they got compared every time, they weren’t the same because every time the new list would always have more total length than the previous one.