Need AI to run to last known position it won't do that...
I am trying to figure our how to make my ai go to the last known position of the player and investigate. However he does not do that and for the life of me I cannot figure out why. heres my code so far.
using System;
using UnityEngine;
using System.Collections;
namespace UnityStandardAssets.Characters.ThirdPerson{
public class EnemySight : MonoBehaviour {
public NavMeshAgent agent;
public ThirdPersonCharacter character;
public enum State {
PATROL,
RUN,
INVESTIGATE
}
public State state;
private bool alive;
private Vector3 lastPlayerSeen;
public GameObject[] waypoints;
private int waypointInd = 0;
public float patrolSpeed = 0.7f;
public float chaseWaitTime = 10f;
private float chaseTimer;
//Run
public float runSpeed = .75f;
public GameObject target;
//Investigate
private Vector3 investigateSpot;
private float timer = 0;
public float InvestigateWait = 5;
//Sight
public float heightMultiplier;
public float sightDST = 10;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
character = GetComponent<ThirdPersonCharacter> ();
agent.updatePosition = true;
agent.updateRotation = false;
state = EnemySight.State.PATROL;
alive = true;
heightMultiplier = 1.36f;
StartCoroutine("FSM");
//start fsm
}
IEnumerator FSM(){
while (alive) {
switch (state){
case State.PATROL:
Patrol ();
break;
case State.RUN:
Run ();
break;
case State.INVESTIGATE:
Investigate();
break;
}
yield return null;
}
}
void Patrol(){
agent.speed = patrolSpeed;
if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) >= 2) {
agent.SetDestination (waypoints [waypointInd].transform.position);
character.Move (agent.desiredVelocity, false, false);
} else if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) <= 2) {
waypointInd += 1;
if (waypointInd >= waypoints.Length) {
waypointInd = 0;
}
} else {
character.Move (Vector3.zero, false, false);
}
}
void Run(){
chaseTimer += Time.deltaTime;
if (chaseTimer < chaseWaitTime) {
agent.SetDestination (this.transform.position);
character.Move (Vector3.zero, false, false);
}
if (chaseTimer >= chaseWaitTime) {
agent.speed = runSpeed;
agent.SetDestination (target.transform.localPosition);
character.Move (agent.desiredVelocity, false, false);
}
}
/*void OnTriggerEnter (Collider coll){
if (coll.tag == "Player") {
state = EnemySight.State.RUN;
target = coll.gameObject;
}
}*/
void Investigate(){
timer += Time.deltaTime;
agent.SetDestination (this.transform.position);
character.Move (Vector3.zero, false, false);
transform.LookAt (investigateSpot);
if (timer >= InvestigateWait) {
state = EnemySight.State.PATROL;
timer = 0;
}
}
void OnTriggerExit (Collider coll){
if (coll.tag == "Player") {
state = EnemySight.State.INVESTIGATE;
investigateSpot = coll.gameObject.transform.position;
}
}
void FixedUpdate(){
RaycastHit hit;
Debug.DrawRay (transform.position + Vector3.up * heightMultiplier, transform.forward * sightDST, Color.green);
Debug.DrawRay (transform.position + Vector3.up * heightMultiplier, (transform.forward + transform.right).normalized * sightDST, Color.green);
Debug.DrawRay (transform.position + Vector3.up * heightMultiplier, (transform.forward - transform.right).normalized * sightDST, Color.green);
if (Physics.Raycast (transform.position + Vector3.up * heightMultiplier, transform.forward, out hit, sightDST)){
if (hit.collider.gameObject.tag == "Player"){
state = EnemySight.State.RUN;
target = hit.collider.gameObject;
}
}
if (Physics.Raycast (transform.position + Vector3.up * heightMultiplier, (transform.forward + transform.right).normalized, out hit, sightDST)){
if (hit.collider.gameObject.tag == "Player"){
state = EnemySight.State.RUN;
target = hit.collider.gameObject;
}
}
if (Physics.Raycast (transform.position + Vector3.up * heightMultiplier, (transform.forward - transform.right).normalized, out hit, sightDST)){
if (hit.collider.gameObject.tag == "Player"){
state = EnemySight.State.RUN;
target = hit.collider.gameObject;
}
}
Vector3 rayDirection = target.transform.position - transform.position;
// Detect if player is within the field of view
if (Physics.Raycast(transform.position, rayDirection, out hit))
{
if(hit.transform.CompareTag("Player")){
lastPlayerSeen = hit.point;
}
}
}
}
}}
I can't add my answer down there: Server Not Responding, but comments work, so I try to help you here, even if I won't get any vote for this ;(
A) remove OnTriggerExit and write ins$$anonymous$$d OnTriggerEnter with this code:
void OnTriggerEnter (Collider coll){
if (coll.tag == "Player") {
state = EnemySight.State.INVESTIGATE;
investigateSpot = coll.gameObject.transform.position;
}
}
This because this sphere collider trigger acts as "ears", so there is no point to check when Exit the trigger, but when Entering and NEVER USE BOTH IN THIS CASE or the behavior would be very weird.
B) agent.SetDestination (target.transform.localPosition);
In the RUN method will make the AI chasing the target, not the last known position.
C) This code never send the AI actor to the investigateSpot, neither the lastPlayerSeen that is defined, initialized but NEVER USED (you should also have a warning about that) so you might want to make some code modifications :P
D) Get the book: Unity 5.x Game Development Essentials, out 1st quarter next year, that will covers all about AI and line of sight :-)
Answer by Injourn · Feb 29, 2016 at 08:48 PM
I am not entirely sure but I don't think that you ever break out of the FSM Coroutine.The variables, i.e. "state", will not change in the IEnumerator once the coroutine starts. Have you tried using update instead? If that's not what you want, you can use stopcoroutine and startcoroutine when there is a change in the state of "state".
Injourn, the yield return null;
in the Coroutine will yield execution, so is indeed leaving out the FS$$anonymous$$ coroutine at each frame.