我让我的僵尸徘徊,在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);
}
感谢您的帮助。
答案 0 :(得分:1)
首先,您应该能够从堆栈溢出中获取堆栈跟踪,这将有助于追踪这些问题。
虽然我不确切地知道你在这里尝试做什么,但是代码中堆栈溢出的最可能原因是攻击和追逐状态之间的无限交换。
如果您按照代码进行操作,如果范围小于或等于某个数字,则当前追逐会进行攻击,如果范围超过该数字,则攻击会进行追逐。
这些条件目前有效,因为它们是相互排斥的。如果你要改变其中一个来解决触发问题(去除互斥性),那么你就有可能来回无限地改变状态。