#c# #unity3d #nullreferenceexception #qvector3d
#c# #unity3d #исключение nullreferenceexception #qvector3d
Вопрос:
Прямо сейчас я создаю игру, в которой враги становятся предупрежденными об игроке и преследуют их неопределенно долго, пока игрок не встанет на «безопасную тарелку» в игре. Когда игрок стоит здесь, враги должны вернуться в исходное положение.
Проблема в том, что всякий раз, когда игрок стоит на тарелке, я получаю ошибку исключения нулевой ссылки, и я вижу, что исходная позиция защиты была сброшена на 0,0,0 в консоли. Я предполагаю, что причина исключения нулевой ссылки заключается в том, что мировое происхождение не находится в используемой мной навигационной сетке, хотя я легко могу ошибаться в этом. Я просто не могу понять, почему значение vector3 вообще изменилось, поскольку переменная guardPosition инициируется при запуске и больше никогда не трогается.
Я включил как мой класс enemyAi (скрипт, прикрепленный к enemy), так и мой класс, связанный с наступлением на тарелки. Если есть что-то еще, что нужно включить, дайте мне знать. Если у кого-нибудь есть какие-либо идеи, буду признателен за помощь. Приветствия.
Скриншот на консоли после нажатия на тарелку
public class EnemyAI : MonoBehaviour
{
DeathHandler dh;
[SerializeField] Transform target;
[SerializeField] float chaseRange = 5f;
[SerializeField] float killRange = 2f;
[SerializeField] GameObject explosionEffect;
NavMeshAgent navMeshAgent;
float distanceToTarget = Mathf.Infinity;
bool isDead = false;
bool isAlert = false;
Vector3 guardPosition;
void Start()
{
GameObject gob;
gob = GameObject.Find("Player");
dh = gob.GetComponent<DeathHandler>();
guardPosition = transform.position;
navMeshAgent = GetComponent<NavMeshAgent>();
}
void Update()
{
distanceToTarget = Vector3.Distance(target.position, transform.position);
print(guardPosition " guard position during update");
//alert a dude
if (distanceToTarget <= chaseRange amp;amp; !isDead)
{
isAlert = true;
}
//chase a dude
if (isAlert == true)
{
ChasePlayer();
print(isAlert);
}
}
public void ChasePlayer()
{
navMeshAgent.SetDestination(target.position);
//explode a dude
if (distanceToTarget <= killRange)
{
Explode();
dh.KillPlayer();
}
}
public void SetAlertStatus(bool status)
{
isAlert = status;
}
public void ReturnToPost()
{
//isAlert = false;
print(guardPosition " guard position after stepping on plate");
navMeshAgent.SetDestination(guardPosition);
}
void Explode()
{
Instantiate(explosionEffect, transform.position, transform.rotation);
isDead = true;
Destroy(gameObject);
}
void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, chaseRange);
}
}
public class SafeSpots : MonoBehaviour
{
EnemyAI enemyAi;
void Start()
{
GameObject gob;
gob = GameObject.FindGameObjectWithTag("Enemy");
enemyAi = gob.GetComponent<EnemyAI>();
}
public void OnTriggerStay(Collider other)
{
if (other.gameObject.tag == "Player")
{
enemyAi.SetAlertStatus(false);
enemyAi.ReturnToPost();
}
}
}
Комментарии:
1. вы уверены, что извлекаете
navMeshAgent
данные в начале? Возможно, это то, что равно нулю и является причиной исключения2. Насколько я знаю, он извлекается. Враг будет преследовать игрока на NavMesh fine. Это просто, когда игрок наступает на тарелку, она ломается.
3. код не выдает описанное поведение — ни одна строка не выводит «защитную позицию во время обновления». В любом случае, возможно, что
EnemyAI.guardPosition
считываемый для печати журнал «положение защиты во время обновления» имеет экземплярEnemyAI
, отличный отFindGameObjectWithTag("Enemy")
найденного. В вопросе упоминается много врагов. Рассматривали ли вы возможность использованияFindGameObjectsWithTag
затем перебора их всех?4. Ах, извините, я изменил операторы печати после вставки кода, чтобы сделать снимок экрана более читаемым. Теперь я отредактировал код до того места, где они появляются. Что касается вашего предложения, у меня действительно есть несколько врагов, но в целях тестирования я отключил скрипт EnemyAi для всех, кроме 1.
5. Да, и поэтому, когда вы ищете игровые объекты с тегом in
SafeSpots.Start
, кажется, что он получает тот, у которогоEnemyAI
отключен скрипт. И поскольку он отключен, онEnemyAI.Start
не запускается, и поэтому онguardPosition = transform.position;
никогда не вызывается в этом экземпляре. Это означает, что когда вы вызываетеGetComponent<EnemyAI>()
его, он получает отключенный экземплярEnemyAI
, который никогда не устанавливал своеguardPosition
поле. Это другой экземплярEnemyAI
, чем тот, которыйUpdate
выполняется и печатает «защитную позицию во время обновления»
Ответ №1:
Вы получаете отключенный экземпляр EnemyAI
. Вместо этого используйте FindGameObjectsWithTag
затем перебирайте их все и добавляйте их EnemyAI
в список, который вы можете перебирать при необходимости. Кстати, его лучше использовать CompareTag
, когда это возможно, для уменьшения мусора:
public class SafeSpots : MonoBehaviour
{
List<EnemyAI> enemyAis;
void Start()
{
GameObject[] enemies= GameObject.FindGameObjectsWithTag("Enemy");
enemyAis = new List<EnemyAI>();
foreach (GameObject enemy in enemies)
{
enemyAis.Add(enemy.GetComponent<EnemyAI>());
}
}
public void OnTriggerStay(Collider other)
{
if (other.CompareTag("Player"))
{
foreach(EnemyAI enemyAi in enemyAis)
{
enemyAi.SetAlertStatus(false);
enemyAi.ReturnToPost();
}
}
}
}
Комментарии:
1. Да, хорошо, так оно и было! Все это время я фокусировался не на той области. Я внес эти изменения, и теперь я получаю ожидаемое поведение. Большое вам спасибо, это сводит меня с ума. Я буду помнить об этом
CompareTag
и в будущем, спасибо!