- Home /
Sorting a list with multiple variables
Hey guys, I have a list that holds a class with a game object and an int. I am having trouble coming up with a way to sort the list so that it returns the game object with highest aggro, and so that if their are multiple game objects with the same aggro level, it will just pick one at random.
public class AggroNode
{
public GameObject aggroPlayerObject;
public int aggro = 0;
}
public class AggroHolder : MonoBehaviour
{
List<AggroNode> aggroTable = new List<AggroNode>();
List<int> topAggro = new List<int>();
public void AddToAggro(GameObject instigator, int damage)
{
foreach (AggroNode entry in aggroTable)
{
if (entry.aggroPlayerObject = instigator)
{
entry.aggro += damage;
}
if (entry.aggroPlayerObject != instigator)
{
AggroNode newEntry = new AggroNode();
newEntry.aggroPlayerObject = instigator;
newEntry.aggro += damage;
aggroTable.Add(newEntry);
}
}
//SetAggroTarget();
}
public bool SetAggroTarget()
{
foreach (AggroNode entry in aggroTable)
{
}
}
}
Be careful! In your line #17 you have
if (entry.aggroPlayerObject = instigator)
This will assign the instigator
every entry.aggroPlayerObject
. So when this loop is done, all elements in your array would reference the same object, the one stored in instigator
. So you most likely want to do a comparison here: ==
instead of =
.
However your code has more issues than that. You can not add items to a list that you're currently iterating over with foreach. You could use a for loop instead, however I don't think your code does what you want. Say it contains 10 different objects and one may be the "instigator". Your second condition would be true for 9 of those 10 objects and for each of those you create a new node that you append at the end of the list. So the list would have countless duplicates and each time you call it it would grow by the amount of nodes that are not the instigator.
I guess your actual goal was to just add a node for the instigator in case it is not yet in the list. For such a task using a Dictionary makes much more sense as it would be way faster and doesn't require extra housekeeping that you're currently missing.
Answer by Ossi101 · Aug 18, 2021 at 03:34 PM
If you're only looking to find an AggroNode with the highest aggro there's no need to sort the list. You can just iterate over the list and check two nodes at a time and pick the highest one. Here's what I came up with, the comments explain the process further:
public AggroNode HighestAggro(List<AggroNode> aggroList)
{
// Return null if an aggro list doesn't exist or is empty.
if (aggroList == null || aggroList.Count == 0) return null;
// Set first AggroNode as the highest so we can check it with the others.
// If this is the only node then it will be the highest by default.
AggroNode highestAggro = aggroList[0];
// Looping over the aggro list.
// It's important we start at index 1 (2nd element.) So that we don't trigger the equality check on the same node.
for (int i = 1; i < aggroList.Count; i++)
{
// Compare the current highest AggroNode with the next element in the list.
if (highestAggro.aggro < aggroList[i].aggro)
{
// If the current node is less than the next element, replace it.
highestAggro = aggroList[i];
}
else if (highestAggro.aggro == aggroList[i].aggro)
{
// If the current node is equal to the next element, pick them at random;
// 50% chance to choose the next element, otherwise it will stay as the last element.
if (Random.value < 0.5f)
{
highestAggro = aggroList[i];
}
}
}
return highestAggro;
}
Here's the result of this code: I hope this helps!
Amazing! This works exactly as I asked it to... and thats the problem. This program is going to be called a few times a second and while doing that the AI is constantly switching between targets with the same aggro level. Is their a way so we can make it pick one at random first then it will only switch once an aggro level surpasses it or the original target is dead(I already have a getcomponent for this). Other than that this is perfect thank you!
Off the top of my head I think you would need a more complicated system than this that keeps track of what targets are selected, die and how to quickly get the highest value without passing over a list of nodes. The method I posted shouldn't cause much issue if you're calling it a few times a second, although realistically it would be called only when you need a new target. So after a cooldown period or when the other target has died. I'm not sure how you've got all that set up so it's hard to say, but I'm glad this helped you out!