Making two closest enemies attack player while others stay on standby state.

So I’ve been trying different methods to get enemies to form a battle circle around my player and only have 2 attacking at the same time. I’ve decided to use an enum system with my methods stated down in an enumHandler here. I’ve also used a foreach loop and created float to compare the enemy’s distance to the player however it only takes the closest one and not the two closest.

public enum RobotState { ENGAGING, STANDBY, ENTER_ENGAGING, ENTER_STANDBY, STANDBY_LOW, DYING, RETREATING }
[SerializeField]
private GameObject [] EnemiesNearby;
public float targetDistance;
Transform target;
public float minTargetDistance;

    void Start()
    {             
        target = GameObject.Find("Player").transform;     
        PlayerObject = GameObject.Find("Player");
    }
void Update()
    {
       

       

        EnemiesNearby = GameObject.FindGameObjectsWithTag("Enemy"); // Constantly find for enemies in the update loop;

        
        RobotStateHandler();      
        FindClosestEnemy();
        targetDistance = Vector3.Distance(target.position, transform.position);
    }

StateHandler that contains method

public void RobotStateHandler()
    {


        if (state == RobotState.STANDBY)
        {           
            minTargetDistance = 7f;
        }

        

        if (state == RobotState.ENGAGING)
        {
           
            minTargetDistance = 2f;
        }

        }



    }

Set for close the Robots can move to the player by MinTargetDistance

The foreach loop that compares robots distance and then makes the closest one engaging

public void FindClosestEnemy()
    {
       
        foreach (GameObject enemy in EnemiesNearby)
        {
            // Find distance between other robots and player
            float robotsDistanceToPlayer = Vector3.Distance(enemy.transform.position, target.transform.position);

            if (targetDistance >= robotsDistanceToPlayer)
            {
                state = RobotState.STANDBY;
            }

            if (targetDistance < robotsDistanceToPlayer)
            {
                state = RobotState.ENGAGING;
            }
        }
    }

If its distance to player is closer than the other robots than it will be set to engaging where its min distance will be set close enough to attack player. However the issue is that when the robots gets close and attacks the player, its state gets set back to standby which makes it fall back and retreat even though its the closest to the player. Is there something wrong with this method or is there a better way to get the closest two robots to the player to engaging.

How about you make a static list which is publically available to all the scripts.
Then you can apply one function to all the enemies to report their range to the static list you made.

So on every update loop:

  1. Enemy checks if he is in the shooting range,
  2. if he is, he checks if the static list has a count of 2 or less
  3. if the count is less, he adds himself to the static list.

This way, you can take the enemies in the static list and ask them to start shooting.

This will avoid all your loops and will be much memory efficient.

Cheers!

I would probably make a “Master controller” script that is the central controller of all the robots.

It would be supplied with a list of robots, and then could be supplied with a “maximum that can attack at once” value.

The master controller script could then do things like call functions on the robots to cause them to:

  • attack the player
  • report if they are attacking the player
  • stay back from the player

A simple version of this script could give the behavior you want, and then you could extend it further by making it bring near-death robots out of the fight and put fresh ones in, perhaps depending on game difficulty level. This would require the player to make a massive “finishing strike” on a robot to prevent it running away, for instance. The possibilities are endless!

I’d go this route as well. It would leave a rather straight forward avenue for later adding even more coordination between the robots beyond simple fire control.

1 Like

Check out the Left4Dead game, they have the notion of a “director” that sets a rising and falling tempo of engagement that plays really well: you get short lulls of inactivity as you move along, then suddenly “It’s on.” You could do this with a sufficiently advanced robot master controller.

Here’s a cool discussion of it: http://left4dead.wikia.com/wiki/The_Director

Brilliant gameplay effect.

To get two, you would wait until after the loop is finished to set them, only storing a reference. Probably the simplest way would be to not use a for each, but just a for loop. That way you have an index. Then you store a last lowest position, and a lowest position, which is an index. If the distance is shorter than the lowest position, that value goes to the last lowest position, and this index goes to the lowest position. When you are done you have two indexes. You change those to engage, and the rest to standby. Then you would probably flag it in update, so it didn’t check until some kind of kill was detected or something so another could enter.

well this is what I was trying to say except the language was a little different… static list vs master controller… But thanks, I know how to say things in a much better way now :smile:

Cheers!