- Home /
Navmesh Enemy AI, Syntax issue?
THE VISUAL: The scene setup is a roaming enemy using waypoints (patrolling). When player is near, the enemy will chase the player and also shoot when close enough. If you MOUSECLICK on the enemy during any state Patrol/Chase/Shoot, it will cause him to walk to a set of Markers for brief time, eventually returning back to Patrol as he should.
The Problem: Everything seems to "kinda" work. It's a bit shaky. You have to click twice on the enemy to get him to run.(ONE click is desired result) First click the enemy will walk to its patrol waypoint than stop. Second Click he will then walk to the marker? I also think the speed of the run is interfering with the speed of his patrol walk?
void Awake ()
{
markers = GameObject.FindGameObjectsWithTag("marker");
// Setting up the references.
enemySight = GetComponent<DoneEnemySight>();
nav = GetComponent<NavMeshAgent>();
player = GameObject.FindGameObjectWithTag(DoneTags.player).transform;
lastPlayerSighting = GameObject.FindGameObjectWithTag(DoneTags.gameController).GetComponent<DoneLastPlayerSighting>();
isClicked = false;
}
void OnMouseDown()
{
isClicked = true;
StartCoroutine(WaitForSomeTime());
Vector3 markerPos = markers[Random.Range(0, markers.Length)].transform.position;
GetComponent<NavMeshAgent>().destination = markerPos;
posToCheck = markerPos;
canCheckDistance = true;
}
void Update ()
{
if (isClicked) {
Running ();
}
else if (enemySight.playerInSight)
{
if (!isClicked)
Shooting ();
}
else if (enemySight.personalLastSighting != lastPlayerSighting.resetPosition) {
if (!isClicked)
Chasing ();
}
else
{
if (!isClicked)
Patrolling ();
}
}
void Running ()
{
nav.speed = runSpeed;
if (canCheckDistance) {
if (Vector3.Distance (transform.position, posToCheck) > distanceLimit - 0.5f)
isClicked = false;
canCheckDistance = false;
}
}
Answer by Inan-Evin · Feb 15, 2015 at 09:29 PM
First you should decide in which condition the user will be able to click on the enemy and make it go somewhere else. You may want the enemy to be affected by mouse click only when patrolling, only when chasing, only when attacking, or in the situations that can be combination of these. Once you decide, we can show you exactly in which part of the code you should be building your logic. In this case, all I can tell you is that you need to create some logic with booleans. For example, create a private boolean called "isClicked".
if(!isClicked)
Shooting();
if(!isClicked)
Chasing();
if(!isClicked)
Patrolling();
this will disable those functions / states if isClick boolean is true. So, when you should make it true ?
GameObject[] markers;
void Start()
{
markers = GameObject.FindGameObjectsWithTag("marker");
//requires you to tag every marker as "marker"
}
void OnMouseDown() // Requires a collider on your character
{
isClicked = true;
//if you use NavMesh
GetComponent<NavMeshAgent>().destination = markers[Random.Range(0, markers.Length)].transform.position;
}
Now the AI will behave as usual, and when it is clicked it will stop processing those Shoot/Patrol/Chase behaviours and go to the random selected marker position. Now you need to make the isClicked variable false again for AIs to behave as expected, and it is up to you to decide when to make the variable false again.
- You can use a coroutine, give a desired time.
GameObject[] markers;
public float waitTime;
void Start()
{
markers = GameObject.FindGameObjectsWithTag("marker");
//requires you to tag every marker as "marker"
}
void OnMouseDown() // Requires a collider on your character
{
isClicked = true;
//if you use NavMesh
GetComponent<NavMeshAgent>().destination = markers[Random.Range(0, markers.Length)].transform.position;
StartCoroutine(WaitForSomeTime());
}
IEnumerator WaitForSomeTime()
{
yield return new WaitForSeconds(waitTime);
isClicked = false;
}
And now the AI return to its normal behaviour.
- You can check the distance to the marker :
GameObject[] markers;
public float distanceLimit;
private bool canCheckDistance;
private Vector3 posToCheck;
void Start()
{
markers = GameObject.FindGameObjectsWithTag("marker");
//requires you to tag every marker as "marker"
}
void OnMouseDown() // Requires a collider on your character
{
isClicked = true;
//if you use NavMesh
Vector3 markerPos = markers[Random.Range(0, markers.Length)].transform.position;
GetComponent<NavMeshAgent>().destination = markerPos;
posToCheck = markerPos;
canCheckDistance = true;
}
void Update()
{
if(canCheckDistance)
{
if(Vector3.Distance(transform.position, posToCheck) > distanceLimit - 0.5f) // 0.5f is the margin
{
//reached
isClicked = false;
canCheckDistance = false;
}
}
}
You can also combine the 1st and the 2nd way together. You can first check the distance, and if reached, start a coroutine, wait for some time and then make isClicked false again in order to make the AI start behaving normaly.
PS. I actually did not inspect the AI code too much, so you may need to reset or tweak some patrol point variables in order to make the AI behave correctly after moving to a marker, because it may be away from its origin position once you make it go somewhere else with mouse click and this can cause some issues. So this is the logic that you can built, I hope I've helped :).
That was epic reply, I'm gonna go ahead and try to apply some of this logic to the AI script, see if i can get any results. $$anonymous$$ight take awhile for me lol but truly appricate it dude
You were correct about that I should have mentioned I wanted to be able to click on the enemy during any state. Thanks for pointing that out
Well no problem, if got stuck in somewhere, just tell it out, I'll do my best to help!
It's because of your syntax, you need to open brackets after if statements, non bracked statements mean "read only the first line after this (first stated line)" So you should be doing this:
private bool isClicked;
void Update ()
{
// If the player is in sight and is alive...
if(enemySight.playerInSight && playerHealth.health > 0f)
{
// ... shoot.
if(!isClicked)
Shooting();
}
// If the player has been sighted and isn't dead...
else if(enemySight.personalLastSighting != lastPlayerSighting.resetPosition && playerHealth.health > 0f)
{
// ... chase.
if(!isClicked)
Chasing();
}
// Otherwise...
else
{
// ... patrol.
if(!isClicked)
Patrolling();
}
}
I feel like i'm close but still being a noob lol Everything seems to "kinda" work. It's a bit shaky. You have to click twice on the enemy to get him to run.(ONE click is desired result) First click the enemy will walk to its patrol waypoint than stop. Second Click he will then walk to the marker? I also think the speed of the run is interfering with the speed of his patrol walk?
void Awake ()
{
markers = GameObject.FindGameObjectsWithTag("marker");
// Setting up the references.
enemySight = GetComponent<DoneEnemySight>();
nav = GetComponent<Nav$$anonymous$$eshAgent>();
player = GameObject.FindGameObjectWithTag(DoneTags.player).transform;
lastPlayerSighting = GameObject.FindGameObjectWithTag(DoneTags.gameController).GetComponent<DoneLastPlayerSighting>();
isClicked = false;
}
void On$$anonymous$$ouseDown()
{
isClicked = true;
StartCoroutine(WaitForSomeTime());
Vector3 markerPos = markers[Random.Range(0, markers.Length)].transform.position;
GetComponent<Nav$$anonymous$$eshAgent>().destination = markerPos;
posToCheck = markerPos;
canCheckDistance = true;
}
void Update ()
{
if (isClicked) {
Running ();
}
else if (enemySight.playerInSight)
{
if (!isClicked)
Shooting ();
}
else if (enemySight.personalLastSighting != lastPlayerSighting.resetPosition) {
if (!isClicked)
Chasing ();
}
else
{
if (!isClicked)
Patrolling ();
}
}
void Running ()
{
nav.speed = runSpeed;
if (canCheckDistance) {
if (Vector3.Distance (transform.position, posToCheck) > distanceLimit - 0.5f)
isClicked = false;
canCheckDistance = false;
}
}
Your answer
Follow this Question
Related Questions
Performing NPC movement with a function. 2 Answers
Navmesh Trouble 1 Answer
Why isn't a Ai Waypoint Spawning??? 0 Answers
Need help detecting barriers for my game 0 Answers
WayPoints mixed with Raycast 1 Answer