Coroutine never stops...
Hi.
I made two Coroutines.
One for wander and one for chase.
I used all kind of code to make wander stops when chasing, but it almost never chases player and wander.
I used yield break, yield return null, stopcoroutine, named it with string, etc...
But it never stops wandering..
I just let them yield break to see if it will make my wandering stops, but it doesn't!!
Here is my code.
Help me God bless you all.
public Transform sight;
public GameObject Player;
NavMeshAgent navMeshAgent;
NavMeshPath path;
public float timeForNewPath;
Vector3 target;
bool inCoRoutine;
bool chasing;
void Start()
{
navMeshAgent = GetComponent<NavMeshAgent> ();
path = new NavMeshPath ();
chasing = false;
navMeshAgent.speed = speedController.speedValue;
}
void Update()
{
// Two CoRoutines with chasing and wandering.
if (!inCoRoutine && !chasing)
{
StartCoroutine ("Wandering");
StopCoroutine ("Chase");
}
if (chasing)
{
StartCoroutine ("Chase");
StopCoroutine ("Wandering");
}
//This is for move animation.
if (navMeshAgent.velocity.magnitude > 1.0f)
{
anim.SetBool ("IsWalking", true);
}
else
{
anim.SetBool ("IsWalking", false);
}
}
Vector3 getNewRandomPosition()
{
float x = Random.Range (-45, -5);
float y = Random.Range (-0.2f, 0.2f);
float z = Random.Range (-33, 25);
Vector3 pos = new Vector3 (x, y, z);
return pos;
}
IEnumerator Wandering()
{
if (!chasing)
{
inCoRoutine = true;
yield return new WaitForSeconds (timeForNewPath);
GetNewPath ();
inCoRoutine = false;
}
if (chasing)
{
yield break;
}
}
IEnumerator Chase()
{
if (chasing)
{
GetNewPath ();
yield return new WaitForSeconds (timeForNewPath);
target = Player.transform.position;
navMeshAgent.SetDestination (target);
}
if (!chasing)
{
yield break;
}
}
void GetNewPath()
{
if (!chasing)
{
target = getNewRandomPosition ();
navMeshAgent.SetDestination (target);
}
else if (chasing)
{
target = Player.transform.position;
navMeshAgent.SetDestination (target);
}
}
void OnTriggerStay()
{
Ray ray = new Ray (sight.position, sight.forward);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, 30.0f))
{
sight.LookAt (Player.transform.position);
if (hit.transform.CompareTag ("Player"))
{
chasing = true;
Debug.Log ("Hello");
}
else
{
chasing = false;
Debug.Log ("No");
}
}
}
void OnTriggerExit()
{
chasing = false;
}
}
Answer by Hellium · Feb 23, 2018 at 03:45 PM
I know, the solution I propose is a total reworking of what you currently have, and it goes outside of the scope of your question.
I advise you to get rid of your coroutines which are difficult to handle in the Update
function. Instead, manage your delay inside the Update
function directly.
An additional improvement is to use the Strategy pattern to handle the states of your player. It will simplify your player class and you easily be able to create new states.
public Transform sight;
public GameObject Player;
public float timeForNewPath;
private NavMeshAgent navMeshAgent;
private NavMeshPath path;
private BehaviourState state; //
private int walkingHash ;
void Start()
{
navMeshAgent = GetComponent<NavMeshAgent> ();
navMeshAgent.speed = speedController.speedValue;
path = new NavMeshPath ();
walkingHash = Animator.StringToHash( "IsWalking" ) ; // Use this to optimize the call to SetBool
state = new WanderState( navMeshAgent, timeForNewPath );
}
void Update()
{
state.Update(); // The NavMeshAgent will automatically retrieve the path at the specified interval
anim.SetBool( walkingHash, navMeshAgent.velocity.magnitude > 1.0f );
}
void OnTriggerStay()
{
Ray ray = new Ray (sight.position, sight.forward);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, 30.0f))
{
sight.LookAt (Player.transform.position);
// If the player is in sight, activate the chase mode => create a new state which is updated in the Update function
if (hit.transform.CompareTag ("Player"))
{
if( !( state is ChaseState ) )
state = new ChaseState( navMeshAgent, timeForNewPath, hit.transform );
}
// If not, activate the wander mode => create a new state which is updated in the Update function
else if( !( state is WanderState ) )
{
state = new WanderState( navMeshAgent, timeForNewPath );
}
}
}
void OnTriggerExit()
{
if( !( state is WanderState ) )
{
state = new WanderState( navMeshAgent, timeForNewPath );
}
}
public abstract class BehaviourState
{
protected NavMeshAgent navMeshAgent ;
private float targetAcquisitionInterval;
private float lastTargetAcquisitionTime ;
public BehaviourState( NavMeshAgent agent, float interval )
{
navMeshAgent = agent ;
targetAcquisitionInterval = interval;
}
public void Update()
{
//Debug.Log( Time.time + " " + lastTargetAcquisitionTime );
if( Time.time > lastTargetAcquisitionTime + targetAcquisitionInterval )
GoToTarget() ;
}
private void GoToTarget()
{
navMeshAgent.SetDestination ( GetTargetPosition() );
lastTargetAcquisitionTime = Time.time ;
}
protected abstract Vector3 GetTargetPosition();
}
public class WanderState : BehaviourState
{
public WanderState( NavMeshAgent agent, float interval ) : base ( agent, interval )
{
GoToTarget() ;
}
protected override Vector3 GetTargetPosition()
{
float x = Random.Range (-45, -5);
float y = Random.Range (-0.2f, 0.2f);
float z = Random.Range (-33, 25);
Vector3 pos = new Vector3 (x, y, z);
return pos;
}
}
public class ChaseState : BehaviourState
{
private Transform target ;
public ChaseState( NavMeshAgent agent, float interval, Transform t ) : base( agent, interval )
{
target = t ;
GoToTarget() ;
}
protected override Vector3 GetTargetPosition()
{
return target.position ;
}
}
Hey!
Should I erase all the using System things?
Cause I can't see nav$$anonymous$$eshAgent without .AI in BehaviourState.
@PaincideStudio : I've erased your last comment by mistake....
Hey everything works fine But he keeps confused to chase my Player when he raycasts my Player. He wanders fine, but he confused to chase my Player.. I think I need to fix the chase state.
What do you mean by "he confused to chase my Player"?
He goes to my player about one step and goes back to wander one step and again goes to my player one step and he loop this forever..
if( Time.time > lastTargetAcquisitionTime + interval )
Also In that script, if I put interval,the name 'interval' does not exist in the current context pops up. If I put targetAcquisitionInterval it doesn't make error.
I finally took the time to test my code. I fixed my answer. It should work now.
Answer by PaincideStudio · Feb 25, 2018 at 11:11 AM
I re-exported my model and it worked. Thx for helping me out!
Your answer
Follow this Question
Related Questions
wait WWW to finish download with yield does not work 0 Answers
How to skip WaitForSeconds? 1 Answer
IEnumerator skips remaining function after yield 1 Answer
Unity - Lines after yield not getting executed 0 Answers
How to add multiple yield return new wait for seconds inside an IEnumerator? 1 Answer