How to make enemies stop a certain distance away?

Ok so I have three different “enemies” and my player object, which is just the FPS Character Controler from the Standard Assets. The enemies always rotate to face the player, and if they’re distance from the player is larger than a certain amount, they move towards him. Here is the code:

    //Inspector variables
    var target : Transform;
    
    
    function Update () 
    {
    	transform.LookAt(target);	
    	
    	if ((Vector3.Distance(transform.position,target.position) > 20) && !((Vector3.Distance(transform.position,target.position)) < 8)) 
    	{
    		transform.position = Vector3.MoveTowards(transform.position, target.position, .5);
    	}
    }

The issues I am having with code are:

  1. The enemies go to the exact point of the player, and eventually push against him so that the player ends up on top of them. I want them to just stop near him, not right on top of him.

  2. Instead of them rotating towards the player all the time, is there a way to simply make them rotate towards their direction? So that I could give them a random direction, and then have them move towards the player(and face that direction) when they spot him?

  3. And my last question is if there is a better way you would have done this? Just for learning purposes.

Thanks for much for your time and help!

It is recomended to use triggers, in cases like this, since it will be much more efficient than constantly doing distance check. Attach and set up Rigidbodies, Colliders, layers, and tags if you will use them, and then use OnTriggerEnter() and OnTriggerExit() functions.

bool playerInRange;

void Update ()
{
   if (playerInRange)
      Atack();
   else
      ApproachPlayer();
}

OnTriggerEnter(Collider other)
{
   if(other.tag == "player")
      playerInRange = true;
}

OnTriggerExit(Collider other)
{
   if(other.tag == "player")
      playerInRange = false;
}

!((Vector3.Distance(transform.position,target.position)) < 8

I would think this linedoe snot make sense because of operator precedence. ! has higher precedence than < meaning you have !((Vector3.Distance(transform.position,target.position)) done first (which is wrong since Distance returns a float) and then this is compared to 8.

What you want somehow is more likely to be:

 var distance=Vector3.Distance(transform.position,target.position);// no need to perform this operation twice.
 if(distance < 20 && distance > 8)

This will get you guy to move towards you when in the range of 8 and 20. Now you also need to keep at distance with another if statement and move function. See, when the NPC is within 8m it does not move, but I guess you want to move away if you approach him then keeping him at a 8m distance. That is your next task.

For question 2, place the LookAt inside the if statement so that it is looking at your player only when in range. Rest of the time, you coul dhave him going from waypoint to waypoint using an array of…waypoints where the …waypoint is the target to reach.