- Home /
How can you detect when a Gameobject has stopped moving?
I have a gameobject that uses navmesh to walk and when I want it to look at a gameobject when it gets within a radius it continues walking and also trys to look at the object at the same time which makes it spas out. How can I detect if the navmesh agent is done moving so that I can make the object look at another gameobject?
Answer by OutOfRam · Nov 27, 2016 at 09:30 AM
Hey there,
I am afraid I am having a bit of difficulty understanding what it is you are saying, from what I understand once the navmesh agent is within a certain range you want it to stop and find a new target. If that is the correct assumption, the solution is as follows (please note that not all of the following is in correct code format, and is instead a guide for you) :
private NavMeshAgent nma;
private Gamobject target;
Start(){
nma = transform.GetComponent<NavMeshAgent>();
StartCoroutine("Behavior1"); // I find for AI's the best practice is to use a series of co-routines as behaviors. run one untill a condition is met then transition
}
IEnumerator Behavior1(){
while (true){ // this way the behaviour will run untill you stop it manually
set destination to target
if (Vector3.Distance(transform.position, target.position) < radius){
StartCoroutine("NextBehavior"); starts next behavior, in your case finding the next target
break;// stops the current coroutine. this will stop the spazzing out
}
}
}
IEnumorator NextBehaviour(){
Whatever code selects a new target
target = new target
StartCoroutine("Behavior1");
I hope this helps :)
let me know if you need anything else.
Ok thanks you got most of what I was saying, I just wasnt sure what the best method was to stop a navmesh agent from moving so it can do other things. Right now Im just using bools to check if a condition is met then doing something if it is met, using bools and co routines might be better but im not too sure is there a reason why co routines are the best method for AIs I could probably use Navmeshagent.stop() while using bools like I am now. Thanks! I just want more info before I start putting co routines in
Heres an example of my current script; move is called whenever I click so the unit can move there (I want the troop to move there no matter what then when its not commanded to move I want it to look at enemy). I have a sphere collider with IsTrigger On so that when any collider enters with a Tag "Enemy" it is put into a list called EnemiesInRange. The problem I keep running into is when I set the agent to move it tells the agent to move, then it quickly moves on to the next set of code without waiting for the agent to actually get there therefore its calling the LookAt function while the agent is moving. Take a Look:
public void $$anonymous$$ove()
{
Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit, $$anonymous$$athf.Infinity);
DS.TargetObj = Instantiate (DS.Target, hit.point, Quaternion.identity) as GameObject;
agent.destination = hit.point; //How can I check when this is done so it can start the coroutine at the right time
if (this.gameObject.CompareTag ("ShootingFriendly") && SightS.EnemiesInRange.Count > 0) { //Also it starts this right when I click; I want to move first then do this
StartCoroutine ("LookAtEnemy");
}
}
public IEnumerator LookAtEnemy()
{
Debug.Log ("Started");
yield return new WaitForSeconds(1);
while(SightS.EnemyWithinRange == true)
{
if (this.gameObject.CompareTag ("ShootingFriendly") && SightS.EnemiesInRange.Count > 0) {
{
Debug.Log ("Turning");
GameObject CurrentEnemy = SightS.EnemiesInRange [0].gameObject;
Quaternion Rot1 = Quaternion.LookRotation (CurrentEnemy.transform.position - this.gameObject.transform.position);
this.gameObject.transform.rotation = Quaternion.Slerp (this.gameObject.transform.rotation, Rot1, Time.deltaTime * 3);
Quaternion Rot = Quaternion.LookRotation (CurrentEnemy.transform.position - Gun.transform.position);
Gun.transform.rotation = Quaternion.Slerp (Gun.transform.rotation, Rot, Time.deltaTime * 3);
}
}
}
Hey again, You do not need to use co-routines for AI, But I do find it helpful in a lot of situations. Not only does it run constantly this way(so that target points can update if the target moves for example) but you can limit how often these checks occur by using the waitforseconds() function; which can help make your game more efficient. Plus this way you can make sure that only one behavior is active at a time so that your AI wont try to simultaneously perform two behaviors(which is what I believe your "freak-out" is caused by). As for the Stopping of the nave mesh you definatly could use the Nav$$anonymous$$eshAgent.Stop() function but be aware that this stops it along its current path but does not overwrite its target location. This means that the movement to the last set target can be resumed through the code. If what you want is a dead stop and to delet that target path, a simple method is to set the Nav$$anonymous$$eshAgent.Destination = transform.position (essentially setting its destination to the point it is currently at). Its kind of late and I do need to sleep so the edits I make to your script may not be complete, but I'll do what I can.
The script plus this exceeds the char count so ill post it below
void Start()
{
StartCoroutine("Idle");//starts the listening behavior
}
IEnumerator Idle()//waits and listens for click input
{
while (true)
{
if (Input.Get$$anonymous$$ouseButtonDown(0))
{
StopCoroutine("LookAtEnemy");//just in case it is still running this avoids conflict
StartCoroutine("$$anonymous$$oveToPosition");
//no break statment means taht this runs always and will always hear clicks
}
yield return new WaitForSeconds(1);
}
}
IEnumerator $$anonymous$$oveToPosition()//moves to pos
{
Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, $$anonymous$$athf.Infinity);
DS.TargetObj = Instantiate(DS.Target, hit.point, Quaternion.identity) as GameObject;
agent.destination = hit.point; //$$anonymous$$ove these lines into the while loop only if the destination changes without a new click
while (true)
{
if (agent.remainingDistance <= 0 && this.gameObject.CompareTag("ShootingFriendly") && SightS.EnemiesInRange.Count > 0)
{
StartCoroutine("LookAtEnemy");
break;
}
yield return new WaitForSeconds(1)//this way it will only check every 1 sec
}
}
public IEnumerator LookAtEnemy()
{
Debug.Log("Started");
while (SightS.EnemyWithinRange)// == true) not super important, but when you deal with bools you don't need this
{
if (this.gameObject.CompareTag("ShootingFriendly") && SightS.EnemiesInRange.Count > 0)
{
Debug.Log("Turning");
GameObject CurrentEnemy = SightS.EnemiesInRange[0].gameObject;
Quaternion Rot1 = Quaternion.LookRotation(CurrentEnemy.transform.position - this.gameObject.transform.position);
this.gameObject.transform.rotation = Quaternion.Slerp(this.gameObject.transform.rotation, Rot1, Time.deltaTime * 3);
Quaternion Rot = Quaternion.LookRotation(CurrentEnemy.transform.position - Gun.transform.position);
Gun.transform.rotation = Quaternion.Slerp(Gun.transform.rotation, Rot, Time.deltaTime * 3);
}
yield return new WaitForSeconds(0.5f);
}
}
Answer by NateLaw1988 · Nov 29, 2016 at 08:15 AM
this will allow you to detect if the object is moving. just change the animator stuff for your spas out stuff
var lastPosition : Vector3;
var myTransform : Transform;
var isMoving : boolean;
var anim : Animator;
function Start () {
myTransform = transform;
lastPosition = myTransform.position;
isMoving = false;
}
function Update ()
{
if ( myTransform.position != lastPosition )
anim.SetBool("moving",true);
else
anim.SetBool("moving",false);
lastPosition = myTransform.position;
}
Answer by DJGhostViper · Nov 29, 2016 at 11:37 AM
OutOfRam thank you so much for your help. I also had no idea about agent.remaining distance so that should help me start the looking function at the right time. Thanks for explaining coroutines better so I can learn more about them too. Enjoy your sleep :)
Your answer
![](https://koobas.hobune.stream/wayback/20220612101503im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Subtracting the position of transform from the position of Game Objects in a list. 1 Answer
Navmesh agent problem 1 Answer
RTS Style Unit: How to surround enemy when attacking 1 Answer
Navmesh sometimes falling through world when enabled 0 Answers
using Contains(gameObject) to find and destroy a gameObject from a list 2 Answers