I cannot offer a solution to your script, only provide an alternative.
The behaviour you’re looking for is based on physics (things recognize and bump into things),
and if you want to use colliders as colliders or triggers then you need a rigidbody for that.
So a basic rule could be ‘for anything that moves, add a rigidbody’.
There is a neat little pattern I noticed with transform.position and rigidbody.velocity :
transform.position += transform.forward * speed * Time.deltaTime;
rigidbody.velocity = transform.forward * speed;
With this pattern it is easy to recode transform.position to work for rigidbody.velocity.
But sometimes it seems rigidbodies have a mind of their own.
To help prevent this, there are the Constraint settings.
Check/tick (enable) all the Freeze Rotation boxes.
SO first to explain the setup of my script.
On your enemies, attach a rigidbody component, freeze all rotations in the constraints portion, leave gravity enabled.
Replace your script with this one (make sure the name of the class is the name of your script, in my example it is called RecognizeColliders ).
using UnityEngine;
using System.Collections;
public class RecognizeColliders : MonoBehaviour
{
public float moveSpeed = 8.0f;
public float rotationSpeed = 2.0f;
public float minDist = 4.0f;
public float maxDist = 45.0f;
private float minSqrDist;
private float maxSqrDist;
private Transform myTransform;
private Transform target;
private Rigidbody myRigidbody;
private Vector3 desiredVelocity;
void Start()
{
minSqrDist = minDist * minDist;
maxSqrDist = maxDist * maxDist;
myTransform = transform;
myRigidbody = rigidbody;
GameObject go = GameObject.FindGameObjectWithTag( "Player" );
target = go.transform;
// moveSpeed += Random.value * someMultiplier; // add randomness to each enemy moveSpeed, same can be done for rotationSpeed
}
void Update()
{
float sqrDist = ( target.position - myTransform.position ).sqrMagnitude;
Quaternion calcRot = Quaternion.LookRotation( target.position - myTransform.position );
desiredVelocity = new Vector3( 0, myRigidbody.velocity.y, 0 );
// apply rotation
myTransform.rotation = Quaternion.Slerp( myTransform.rotation, calcRot, rotationSpeed * Time.deltaTime );
// modify desiredVelocity if within range
if ( sqrDist > minSqrDist && sqrDist < maxSqrDist )
{
desiredVelocity = myTransform.forward * moveSpeed;
desiredVelocity.y = myRigidbody.velocity.y;
}
}
void FixedUpdate()
{
myRigidbody.velocity = desiredVelocity;
}
}
Bear in mind C# is not my native tongue, so this may be inelegant but is tested and working.
A couple of things you may notice different to your script :
Distance has been replaced by square distance. Square distance is much easier for Unity to calculate, and with this running every update on every enemy, using square distance helps performance. If you know your desired distance, then it is more efficient to use
if ( (tgt.position - tx.position).sqrMagnitude < ( minDistance * minDistance ) )
than
if ( Vector3.Distance(tgt.position - tx.position) < minDistance )
and it is so easy to get the square of your desired distance (minDistance * minDistance ) ! So theres a consideration.
Next one is instead of directly applying a move calculation to the transform, that calculation is stored in a variable.
In this case it’s called desiredVelocity, mainly for using this value to apply to the rigidbody in a FixedUpdate.
Sometimes it is better to write another line of code instead of cramming all the calculations into a command, mainly to make things easier to read (especially when starting out).
Sure an extra variable takes a little memory, but really for a Vector3 is insignificant.
There is no such problem for writing one extra line of code to break things up a bit,
there is really no efficiency difference here apart from what pros consider neat and tidy. I have a longhand way of writing with spaces and comments.
Point in case is the conditional check for if the target is within range :
if ( sqrDist > minSqrDist && sqrDist < maxSqrDist )
very easy to read and see what is going on there =]
I think that’s about it apart from where the velocity.y is reapplied to desiredVelocity, for the purpose of gravity. If the object is falling, we want it to keep falling.
Which brings me to my big consideration with using this method - you can use this on uneven terrain =]
Here is a package I have built for you, to demonstrate my example script in 2 environments : flat and uneven. Create a new Project (to avoid confusion with your scripts and assets), then import the package.
Run both scenes, controls for player are WASD and LMB to shoot. Then check the components on the enemy, and the rigidbody settings.
The other scripts are in uJS (from another of my answers), I don’t have the time or need to convert them sorry.
Now this isn’t perfect as it is a basic script, but hopefully it demonstrates a way to be able to recognize collisions with your characters.
You need to include considerations as mentioned by robertblu (adding randomness to the enemy move and rotation speed). Another thing to look into is the suggestion by MickM which is to employ character controllers as they look after collisions.
The player script is actually my modified version of the Rigidbody FPS walker script on the Unity Wiki.
All you can do is experiment and have fun.
oops, nearly forgot, here’s the link to the example package : http://www.alucardj.net16.net/unityanswers/RecognizeColliders.unitypackage
The upload seemed a little slow, so if there are any problems I shall upload it again.