My AI tries to find and move to itself!

Hey folks

Im currently doing a very stupid AI meant for lots of little units being on the screen at once. One of the functions in my class is designed to find all gameObjects with the tag “unit”, and then figure out the closest one, to start attacking it. The problem is that each unit has the “unit” tag, which results in them finding themselves. I cannot figure out how to bypass this problem. I’m storing in an array, so I cant really just remove an object at a given index. Should I be using another thing like an ArrayList, or is there a simpler way that I’m not seeing?

Also another thing. Currently I am loading all objects in scene with that tag into an array. This seems a bit stupid further down the road where I may have 60-80 units in game. Can I simply declare the array with ie. size 5, to cut down on computation?

Here is a code snippet for the function.

//Find a target if we dont currently have one
		if (target == null) {	
			target = FindClosestEnemy();
			
		}
		// Rotate towards target    
   Vector3 targetPoint = target.transform.position;
		targetPoint.y = transform.position.y;
   Quaternion targetRotation = Quaternion.LookRotation (new Vector3(targetPoint.x,transform.position.y,targetPoint.z) - transform.position, Vector3.up); 
   transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 40.0f); 
		
		
		if (debugMode) {
	Debug.DrawRay(transform.position,(target.transform.position - transform.position),Color.blue);
	Debug.DrawRay(transform.position,transform.forward*2,Color.red);
	}
	}
	

	
	GameObject FindClosestEnemy () {
	targets = GameObject.FindGameObjectsWithTag("unit");
	
   foreach (GameObject posTarget in targets) {
      Vector3 dirVec = (posTarget.transform.position - transform.position); 
      float curDistance = dirVec.sqrMagnitude; 
      if (curDistance < distance) { 
         closestTarget = posTarget;
         distance = curDistance; 
      } 
   } 
    
   return closestTarget; 
	}
	
	void FixedUpdate(){
		
		if (debugMode) {
			//Debug.Log("Vel :"+rb.velocity.magnitude);
		}
		if (!atTarget) {
			rb.AddForce(transform.forward * speed);
		}else {
		rb.velocity = Vector3.zero;	
		}
	
		
	}

throw a (distance > 0) in there

alternatively, you can compare IDs using GetInstanceId()

You could do something like:

 if (curDistance < distance  posTarget != gameObject)

That said using tags is probably an inefficient way to do this.

Assuming that the script is directly attached to the GameObject in question, when you check distance on line 27 also check that posTarget != gameObject.

Naturally, these are all simple solutions, that I should have thought of. Thanks all :slight_smile:

If using tags is inefficient, how would one do it otherwise? there is going to be plenty o’ gameobjects in the scene sometime in the future

Sphere collider set as a trigger with the radius set to the “view” distance, layers set up so only enemies trigger the collision. When things come in to the sphere (OnTriggerEnter) add them to a list, when they leave remove them.

Next step of optimisation if you need it is to share the sight between various units (so if one unit “sees” something other close by units will attack that instead of looking themselves).

Note this is not necessarily the most efficient way, but once you get a lot of units its more likely to be better than using tags and also easy to implement.

If you have thousands of units you might need something a little more sophisticated and customised.