I’m coding the combat system for my RTS game, and every time a unit spawns I iterate over all enemies and then attack the closest one. This is achieved using the below block of code:
void FindCurrentTarget()
{
//find all potential targets (enemies of this character)
enemies = GameObject.FindGameObjectsWithTag(attackTag);
//distance between character and its nearest enemy
float closestDistance = Mathf.Infinity;
GameObject potentialTarget = null;
foreach (GameObject _enemy in enemies)
{
//check if there are enemies left to attack and check per enemy if its closest to this character
if (Vector3.Distance(transform.position, _enemy.transform.position) < closestDistance && _enemy != null)
{
//if this enemy is closest to character, set closest distance to distance between character and enemy
closestDistance = Vector3.Distance(transform.position, _enemy.transform.position);
//also set current target to closest target (this enemy)
if ((currentTarget == null) || ((currentTarget != null) && Vector3.Distance(transform.position, currentTarget.transform.position) > 2))
{
potentialTarget = _enemy;
}
}
}
//set the current target at end of for loop, this is the closest enemy
currentTarget = potentialTarget;
}
This works as expected but the problem is that if I deploy 10 units, all 10 units will target the same closest unit and will gang up on the poor guy. These 10 units will then all move to the next guy and this way I have a murder ball of units.
I am thinking of a solution for this but cant think of any, any ideas as a solution would be greatly welcomed.
One solution I thought was to ensure that a target can have a maximum of 3 attackers, and if in the above loop, if it is seen that a target already has 3 attackers attacking it then move on to the next.
For this I added an int _attackers to the Character() script, and then when a new target is found it increments that integer, and if that integer is 3 we move on to the next enemy in the loop.
Below is the modification of the above code to take into account max attackers:
void FindCurrentTarget()
{
//find all potential targets (enemies of this character)
enemies = GameObject.FindGameObjectsWithTag(attackTag);
//distance between character and its nearest enemy
float closestDistance = Mathf.Infinity;
GameObject potentialTarget = null;
foreach (GameObject _enemy in enemies)
{
// if the current enemy already has 3 attackers on him, then ignore and move to next
if (_enemy.GetComponent<Character>()._attackers >= 3)
continue;
//check if there are enemies left to attack and check per enemy if its closest to this character
if (Vector3.Distance(transform.position, _enemy.transform.position) < closestDistance && _enemy != null)
{
//if this enemy is closest to character, set closest distance to distance between character and enemy
closestDistance = Vector3.Distance(transform.position, _enemy.transform.position);
//also set current target to closest target (this enemy)
if ((currentTarget == null) || ((currentTarget != null) && Vector3.Distance(transform.position, currentTarget.transform.position) > 2))
{
potentialTarget = _enemy;
}
}
}
// in case we have a different target than the one we are changing to then decrement attacker before changing target
if (currentTarget != null && potentialTarget != null && potentialTarget != currentTarget)
{
potentialTarget.GetComponent<Character>()._attackers--;
}
// increment the attacker after targetting it
if (potentialTarget != null)
{
potentialTarget.GetComponent<Character>()._attackers++;
}
//set the current target at end of for loop, this is the closest enemy
currentTarget = potentialTarget;
}
I am of course also ensuring that the int is decremented when the attacker dies and and am also clamping the value of _attackers between 0 and 4.
But this modification is not working, the nearest enemies are ignored, the targeting which used to be nearest first is now random, sometimes targets are ignored entirely.
When I check in the inspector the targets that are ignored, it shows that the _attackers variable is already at 3. When I debug which of my deployed units is these 3 units, its just a random selection, no longer is the nearest principle respected.
Ive tried all day trying to fix this and I just end up fixing one thing and breaking two. It should be a simple enough concept to implement, but its apparently not