I am trying to produce a basic AI where an enemy will chase the player when in range, stop moving when out of range and shoot the player when close enough. At the moment my script causes the enemy to initially follow the player, both stopping when too close and too far away, as expected. But when the player moves out of range and back in, the enemy’s movement becomes erratic often moving to the side or away from rather than to the player. If someone could identify the error in my logic here, that would be much appreciated. Thanks in advance.
public class DroneBehaviour : MonoBehaviour {
GameObject mPlayerObject;
float mDroneSpeed = 1.5f;
float mClosestToPlayer = 5.0f;
float mFurtherestFromPlayer = 15.0f;
Vector3 velocity = Vector3.zero;
Vector3 direction = Vector3.zero;
float magnitude = 0.0f;
void Start () {
mPlayerObject = GameObject.FindGameObjectWithTag ("Player");
}
void Update () {
//Find the distance to the player
magnitude = Vector3.Distance(mPlayerObject.transform.position, transform.position);
//Face the drone to the player
direction = mPlayerObject.transform.position - transform.position;
direction.Normalize ();
direction.y = 0;
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
//If the player is in range move towards
if(magnitude <= mFurtherestFromPlayer && magnitude > mClosestToPlayer )
{
mDroneMovesToPlayer();
}
//If the player is close enough shoot
else if(magnitude <= mFurtherestFromPlayer && magnitude <= mClosestToPlayer)
{
mDroneStopsMoving();
mShootPlayer();
}
//If the player is out of range stop moving
else
{
mDroneStopsMoving();
}
//Apply velocity to rigidbody
rigidbody.velocity = velocity;
}
void mDroneStopsMoving(){
velocity = Vector3.zero;
}
void mDroneMovesToPlayer(){
velocity = direction * mDroneSpeed;
velocity.y = 0;
}
void mShootPlayer(){
//Shoot player ...
}
}
Try this , I made some minor changes . im not on unity so its untested. Let me know if it works.
Edited…Added Physics. Should work fine now.
using UnityEngine;
using System.Collections;
public class DroneBehaviour : MonoBehaviour
{
private GameObject player;
[SerializeField]
private float moveSpeed = 250;
[SerializeField]
private float minDistance = 50.0f;
[SerializeField]
private float maxDistance = 100.0f;
[SerializeField]
private float rotationDrag = 0.75f;
[SerializeField]
private bool canShoot = true;
[SerializeField]
private float brakeForce = 5f;
private bool isShooting = false;
private Vector3 direction;
private float distance = 0.0f;
public enum CurrentState { Idle, Following, Attacking };
public CurrentState currentState;
public bool debugGizmo = true;
public float DistanceToPlayer { get { return distance; } }
public bool CanShoot { get { return canShoot; } set { canShoot = value; } }
void Start()
{
player = GameObject.FindGameObjectWithTag("Player");
currentState = CurrentState.Idle;
isShooting = false;
}
void Update()
{
//Find the distance to the player
distance = Vector3.Distance(player.transform.position, this.transform.position);
//Face the drone to the player
direction = (player.transform.position - this.transform.position);
direction.Normalize();
}
private void FixedUpdate()
{
this.rigidbody.rotation = Quaternion.LookRotation(direction, Vector3.up);
this.rigidbody.angularDrag = rotationDrag;
//If the player is in range move towards
if(distance > minDistance && distance < maxDistance )
{
currentState = CurrentState.Following;
DroneMovesToPlayer();
}
//If the player is close enough shoot
else if(distance < minDistance)
{
DroneStopsMoving();
if(canShoot)
{
currentState = CurrentState.Attacking;
ShootPlayer();
}
}
//If the player is out of range stop moving
else
{
currentState = CurrentState.Idle;
DroneStopsMoving();
}
}
private void DroneStopsMoving()
{
isShooting = false;
this.rigidbody.drag = (brakeForce);
}
private void DroneMovesToPlayer()
{
isShooting = false;
this.rigidbody.AddRelativeForce(Vector3.forward * moveSpeed);
}
private void ShootPlayer()
{
isShooting = true;
//Shoot player ...
}
private void OnDrawGizmosSelected()
{
if (debugGizmo)
{
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(this.transform.position, maxDistance);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(this.transform.position, minDistance);
}
}
}
Didn’t confirm whether or not Ermarrero solution worked as I ended up approaching the problem from a new angle. This script now effectively handles the movement I desired from my enemy above. Thanks to Ermarrero for his help though.
GameObject mPlayerObject;
float mDroneSpeed = 1.0f;
float mFarThreshold = 20.0f;
float mShootThreshold = 10.0f;
float mCloseThreshold = 5.0f;
void Update () {
//Calculate player's position
Vector3 direction = mPlayerObject.transform.position - transform.position;
float magnitude = direction.magnitude;
direction.Normalize ();
//Calculate crawler's speed
Vector3 velocity = direction * mDroneSpeed;
if( magnitude > mShootThreshold && magnitude < mFarThreshold)
{
//Move the crawler
rigidbody.velocity = new Vector3 (velocity.x, rigidbody.velocity.y, velocity.z);
}
else if( magnitude < mCloseThreshold)
{
rigidbody.velocity = new Vector3 (-velocity.x, rigidbody.velocity.y, -velocity.z);
}
if(magnitude < mShootThreshold)
{
}
//Face the crawler to the player
transform.LookAt(new Vector3(mPlayerObject.transform.position.x, transform.position.y, mPlayerObject.transform.position.z));
}