繁体   English   中英

Unity AI攻击简单FSM Stackoverflow错误

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM