[英]Unity AI attack Simple FSM Stackoverflow error
我让僵尸四处游荡,在LOS&FOV上追我,但当它们到达我身边时(Camera Rig Vive VR),只有一个攻击我(不是eveytime,而是他尝试)。 一旦他们靠近我,我想让他们所有人都来攻击我(最好是他们在我周围绕圈)。
如果我尝试更改距离或使用触发器对撞机将布尔值传递为true而不是计算剩余距离(在攻击协程中),则出现堆栈溢出错误。 我不明白为什么。 如果有人可以驱逐我,那将非常好。
这是AI_Enemy的代码:
using UnityEngine;
using System.Collections;
using UltimateSpawner;
using System.Collections.Generic;
public class AI_Enemy : MonoBehaviour
{
public enum ENEMY_STATE {PATROL, CHASE, ATTACK, DEAD};
public ENEMY_STATE CurrentState
{
get{return currentstate;}
set
{
//Update current state
currentstate = value;
//Stop all running coroutines
StopAllCoroutines();
switch(currentstate)
{
case ENEMY_STATE.PATROL:
StartCoroutine(AIPatrol());
break;
case ENEMY_STATE.CHASE:
StartCoroutine(AIChase());
break;
case ENEMY_STATE.ATTACK:
StartCoroutine(AIAttack());
break;
case ENEMY_STATE.DEAD:
break;
}
}
}
[SerializeField]
private ENEMY_STATE currentstate = ENEMY_STATE.PATROL;
[SerializeField] Animator ThisAnimator;
[SerializeField] AudioSource ThisAudioSource;
//Reference to patrol destination
[SerializeField] GameObject[] PatrolDestinations;
private AudioClip sound;
public AudioClip[] attacksSounds;
//Reference to line of sight component
private LineSight ThisLineSight = null;
//Reference to nav mesh agent
private UnityEngine.AI.NavMeshAgent ThisAgent;
//Reference to transform
private Transform ThisTransform = null;
//Reference to player health
public PlayerHealth PlayerHealth = null;
//Reference to player transform
private Transform PlayerTransform = null;
public Transform PatrolDestination;
[SerializeField] float timeBetweenAttacks = 1.4f;
private WaitForSeconds attackDelay;
//Damage amount per second
public float MaxDamage = 2.8f;
public static bool inRange = false;
void Awake()
{
ThisLineSight = GetComponent<LineSight>();
ThisAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
ThisTransform = GetComponent<Transform>();
ThisAnimator = GetComponent<Animator>();
ThisAudioSource = GetComponent<AudioSource>();
attackDelay = new WaitForSeconds(timeBetweenAttacks);
}
void Start()
{
//Configure starting state
ThisAgent.enabled = true;
PlayerHealth = GameManager.Instance.Player;
PlayerTransform = GameManager.Instance.EnemyTarget;
PatrolDestinations = GameObject.FindGameObjectsWithTag("Waypoint");
StartCoroutine(StartZombie());
}
public IEnumerator AIPatrol()
{
ThisAnimator.SetBool("Attack", false);
ThisAnimator.SetBool("Chase", false);
ThisAnimator.SetBool("Walk", true);
PatrolDestination = PatrolDestinations[Random.Range(0, (PatrolDestinations.Length - 1))].transform;
//Loop while patrolling
while (currentstate == ENEMY_STATE.PATROL)
{
//Set strict search
ThisLineSight.Sensitity = LineSight.SightSensitivity.STRICT;
ThisAgent.speed = 1f;
//Chase to patrol position
//ThisAgent.Resume();
ThisAgent.isStopped = false;
ThisAgent.SetDestination(PatrolDestination.position);
//Wait until path is computed
while(ThisAgent.pathPending)
yield return null;
if (ThisAgent.remainingDistance < 1.5f)
PatrolDestination = PatrolDestinations[Random.Range(0, (PatrolDestinations.Length))].transform;
//If we can see the target then start chasing
if (ThisLineSight.CanSeeTarget)
{
//ThisAgent.Stop();
ThisAgent.isStopped = true;
transform.LookAt(GameManager.Instance.EnemyTarget);
CurrentState = ENEMY_STATE.CHASE;
yield break;
}
//Wait until next frame
yield return null;
}
}
public IEnumerator AIChase()
{
ThisAnimator.SetBool("Attack", false);
ThisAnimator.SetBool("Chase", true);
ThisAnimator.SetBool("Walk", false);
ThisAgent.speed = 1.7f;
//Loop while chasing
while (currentstate == ENEMY_STATE.CHASE)
{
//transform.LookAt(GameManager.Instance.EnemyTarget);
//Set loose search
ThisLineSight.Sensitity = LineSight.SightSensitivity.LOOSE;
//Chase to last known position
//ThisAgent.Resume();
ThisAgent.isStopped = false;
ThisAgent.SetDestination(ThisLineSight.LastKnowSighting);
//Wait until path is computed
while(ThisAgent.pathPending)
yield return null;
//Have we reached destination?
if(ThisAgent.remainingDistance <= ThisAgent.stoppingDistance +0.5f)
{
//Stop agent
ThisAgent.isStopped = true;
//ThisAgent.Stop();
//Reached destination but cannot see player
if(!ThisLineSight.CanSeeTarget)
CurrentState = ENEMY_STATE.PATROL;
else //Reached destination and can see player. Reached attacking distance
CurrentState = ENEMY_STATE.ATTACK;
yield break;
}
//Wait until next frame
yield return null;
}
}
public IEnumerator AIAttack()
{
ThisAnimator.SetBool("Attack", true);
ThisAnimator.SetBool("Chase", false);
ThisAnimator.SetBool("Walk", false);
//Loop while chasing and attacking
while (currentstate == ENEMY_STATE.ATTACK)
{
//Chase to player position
ThisAgent.isStopped = false;
ThisAgent.SetDestination(GameManager.Instance.EnemyTarget.position);
//Wait until path is computed
while (ThisAgent.pathPending)
yield return null;
//Has player run away?
if(ThisAgent.remainingDistance > ThisAgent.stoppingDistance + 0.5f)
//if(!inRange)
{
//Change back to chase
CurrentState = ENEMY_STATE.CHASE;
yield break;
}
else
{
//Attack
GameManager.Instance.Player.TakeDamage(MaxDamage);
sound = attacksSounds[Random.Range(0, (attacksSounds.Length))];
ThisAudioSource.PlayOneShot(sound);
}
//Wait until next frame
yield return attackDelay;
}
yield break;
}
//Called when the enemy is defeated and can no longer move
public void Defeated()
{
Debug.Log("DEFEATED");
//Disable the navmesh agent
ThisAgent.enabled = false;
ThisAnimator.SetBool("Die", true);
SpawnableManager.informSpawnableDestroyed(gameObject, false);
CurrentState = ENEMY_STATE.DEAD;
EnemyManager.nbrZombies --;
EnemyManager.CountAllZombie();
}
public IEnumerator StartZombie()
{
yield return new WaitForSeconds(5);
CurrentState = ENEMY_STATE.PATROL;
}
}
视线代码:
using UnityEngine;
using System.Collections;
//------------------------------------------
public class LineSight : MonoBehaviour
{
//------------------------------------------
//How sensitive should we be to sight
public enum SightSensitivity {STRICT, LOOSE};
//Sight sensitivity
public SightSensitivity Sensitity = SightSensitivity.STRICT;
//Can we see target
public bool CanSeeTarget = false;
public bool DebugFOV = false;
//FOV
public float FieldOfView = 120f;
//Reference to target
public Transform Target = null;
//Reference to eyes
public Transform EyePoint = null;
//Reference to transform component
private Transform ThisTransform = null;
//Reference to sphere collider
public SphereCollider ThisCollider = null;
//Reference to last know object sighting, if any
public Vector3 LastKnowSighting = Vector3.zero;
private Vector3 DirToTarget;
void Awake()
{
ThisTransform = GetComponent<Transform>();
ThisCollider = GetComponent<SphereCollider>();
LastKnowSighting = ThisTransform.position;
}
private void Start()
{
Target = GameManager.Instance.EnemyTarget;
}
//------------------------------------------
bool InFOV()
{
//Get direction to target
DirToTarget = Target.position - EyePoint.position;
//Get angle between forward and look direction
float Angle = Vector3.Angle(EyePoint.forward, DirToTarget);
//Are we within field of view?
if(Angle <= FieldOfView)
{
Debug.DrawRay(EyePoint.position, (Target.position - EyePoint.position), Color.cyan);
return true;
}
//Not within view
return false;
}
//------------------------------------------
bool ClearLineofSight()
{
RaycastHit Info;
if (Physics.Raycast(EyePoint.position, (Target.position - EyePoint.position), out Info, ThisCollider.radius *2))
{
//If player, then can see player
//if (Info.transform.CompareTag("MainCamera"))
if(Info.transform.gameObject.layer == LayerMask.NameToLayer("Gringan"))
return true;
}
return false;
}
//------------------------------------------
void UpdateSight()
{
switch(Sensitity)
{
case SightSensitivity.STRICT:
CanSeeTarget = InFOV() && ClearLineofSight();
break;
case SightSensitivity.LOOSE:
CanSeeTarget = InFOV() || ClearLineofSight();
break;
}
}
//------------------------------------------
void OnTriggerStay(Collider Other)
{
UpdateSight();
//Update last known sighting
if(CanSeeTarget)
LastKnowSighting = Target.position;
}
void OnDrawGizmos()
{
float totalFOV = 120.0f;
float rayRange = 3.9f;
float halfFOV = totalFOV / 2.0f;
Quaternion leftRayRotation = Quaternion.AngleAxis(-halfFOV, Vector3.up);
Quaternion rightRayRotation = Quaternion.AngleAxis(halfFOV, Vector3.up);
Vector3 leftRayDirection = leftRayRotation * transform.forward;
Vector3 rightRayDirection = rightRayRotation * transform.forward;
Gizmos.color = Color.red;
Gizmos.DrawRay(transform.position, leftRayDirection * rayRange);
Gizmos.DrawRay(transform.position, rightRayDirection * rayRange);
}
private void Update()
{
if(CanSeeTarget)
Debug.DrawRay(EyePoint.position, (Target.position - EyePoint.position), Color.yellow);
}
谢谢你帮我
首先,您应该能够从堆栈溢出中获取堆栈跟踪,这将有助于追踪这些问题。
尽管我不知道您要在这里做什么,但最有可能导致代码溢出的原因是攻击状态和追逐状态之间的无限交换。
如果您遵循该代码,那么如果range小于或等于一个数字,则当前追踪将进入攻击,如果range大于该数字,则当前追踪将进入攻击。
这些条件目前是可行的,因为它们是互斥的。 但是,如果您要更改其中之一以消除触发器(消除相互排斥),那么您将有可能无限地来回更改状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.