Object reference not set to an instance of an object, Unity

huangapple go评论54阅读模式
英文:

Object reference not set to an instance of an object, Unity

问题

当敌人生成时,我尝试在这里初始化他 enemy.Init();,但出现了错误“Object reference not set to an instance of an object”(对象引用未设置为对象的实例)。但在这里 Debug.Log(enemy._enemyHealth);,我能够获取到敌人的生命值。如果敌人是类 'Usual Enemy' 并且它是从 'Enemy' 类继承的,而且我将会有更多的敌人子类,我如何从这里初始化我的敌人呢?

你可以尝试使用以下方法来解决这个问题:

  1. 确保预制件正确配置: 确保你的敌人预制件(Prefab)已正确配置,并且在预制件上已经附加了相应的脚本组件。确保 enemy.Init(); 中的 enemy 不为 null。

  2. 检查子类的初始化方法: 如果你有多个敌人子类,确保每个子类都实现了 Init() 方法。你可以在每个子类中重写 Init() 方法,以确保它们的初始化逻辑正确执行。

  3. 使用多态: 你可以使用多态来确保调用适当的子类的 Init() 方法。这样,无论你使用哪个子类的实例,都会调用正确的初始化方法。

例如,如果你的 enemy 变量是 Enemy 类型的引用,但实际上它是一个子类的实例,那么你可以这样调用 Init() 方法:

enemy.Init();

这将根据实际的对象类型调用正确的 Init() 方法。

确保在你的子类中正确实现了 Init() 方法,以便它可以执行所需的初始化逻辑。如果你仍然遇到问题,可以提供更多的代码或信息,以便我可以提供更具体的帮助。

英文:

So when enemy is spawned i try to init him here enemy.Init(); but had error Object reference not set to an instance of an object. But here Debug.Log(enemy._enemyHealth); i get number of enemy health. How i can Init my enemy from here if enemy has class 'Usual Enemy' and it extends from this class 'Enemy' and i wiil have more enemy child cllases?

I vave class Enemy

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public abstract class Enemy : MonoBehaviour
{

    private GameObject _player;
    private Animator _animator;
    private Rigidbody _rigidbody;
    private bool _isSpawned;
    private const int _enemySpavnTime = 5;
    [SerializeField] public float _enemyHealth;
    [SerializeField] protected float _rotationSpeed = 10f;
    [SerializeField] protected float _moveSpeed;
    [SerializeField] protected float _damage;
    [SerializeField] protected DamageBox _damageBox;
    [SerializeField] protected TriggerBox _triggerBox;
    private EnemyCondition _enemyCondition = EnemyCondition.Dead;
    
    private enum EnemyCondition 
    {
        Spawn,
        Run,
        Attack,
        Dead
    }


    void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
        _animator = GetComponent<Animator>();
        _player = GameObject.FindWithTag("Hero");
        _damageBox.HeroHited += enemyAttack;
        _triggerBox.HeroInAttackRange += enemyGetAngry;
        _triggerBox.HeroOutAttackRange += enemyGetChill;
    }

    void Update()
    {   
        if (_player != null) 
        {
            if (_enemyCondition == EnemyCondition.Run)
            {
                EnemyPlayerRotation(_player);

            } else if (_enemyCondition == EnemyCondition.Attack)
            {
                EnemyPlayerRotation(_player);
            }
        }
        
    }

    void FixedUpdate() {
        if (_enemyCondition == EnemyCondition.Run)
        {
            EnemyPlayerFollow();
        }   
    }

    public virtual void Init() {
        enemySpawn();
    }

    protected virtual void EnemyPlayerFollow() {
        Vector3 direction = transform.TransformDirection(new Vector3(0, 0, 1));
        _rigidbody.velocity = direction * _moveSpeed;
    }

    protected virtual void EnemyPlayerRotation(GameObject target) {
        Vector3 direction = (target.transform.position - transform.position).normalized;
        Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
        transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * _rotationSpeed);
     }

    public virtual void EnemyDamage(float damage)
    {
        _enemyHealth -= damage;
        if (_enemyHealth <= 0) {
            PoolManager.Instanse.Despawn(gameObject);
        }
    }

    public virtual void enemySpawned() {
        _enemyCondition = EnemyCondition.Run;
        _rigidbody.isKinematic = false;
        _animator.SetTrigger("Run");
        StopCoroutine(SpawnMoveUp());
        Debug.Log("enemySpawned");
    }

    protected virtual void enemyAttack(Hero trigger) 
    {   
        if (_enemyCondition == EnemyCondition.Attack) {
            trigger.HeroDamage(_damage);
        }
    }

    protected virtual void enemyGetAngry() {
        _enemyCondition = EnemyCondition.Attack;
        _animator.SetTrigger("Attack");
    }

    protected virtual void enemyGetChill() {
        _enemyCondition = EnemyCondition.Run;
        _animator.SetTrigger("Run");
    }

    protected virtual void enemySpawn() {
        _animator.SetTrigger("Spawn");
        _animator.speed = 0.0f;
        StartCoroutine(SpawnMoveUp());
    }

    IEnumerator SpawnMoveUp()
    {  
        float spawnStage = 0.0f;
        Vector3 startPoint = transform.position;
        while(spawnStage <= 1.0f) {
            transform.position = Vector3.Slerp(startPoint, new Vector3(transform.position.x, 0, transform.position.z), spawnStage);
            spawnStage += Time.deltaTime/_enemySpavnTime;
            yield return null;
        }
        _animator.speed = 1.0f;
        
    }
    
}

And I have class that spawns enemies

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemiesSpawner : MonoBehaviour
{
    [SerializeField] private Levels[] _levelsList;
    private List<GameObject> _enemiesQueue = new List<GameObject>();
    private List<GameObject> _levelEnemiesList = new List<GameObject>();
    private List<int> _levelEnemiesCount = new List<int>();

    private bool _isBossSpawned = false;
    // private int _currentLevel = PlayerPrefs.GetInt("currentLevel") - 1;
    private int _currentLevelNumber = 0;
    private float _reloadPause = 0;
    private int currentEnemiesListPos = 0;
    private int allEnemiesCount = 0;

    private float _reloadTime;
    private float _spawnRadius;
    private float _spawnOfsetRadius = 2f;

    [SerializeField] private GameObject _boss;
    [SerializeField] private GameObject _spawnPoint;

    void Start() {
        Levels currentLevelObj = _levelsList[_currentLevelNumber];
        _levelEnemiesCount.AddRange(currentLevelObj.enemiesCount.ToArray());
        _levelEnemiesList = currentLevelObj.enemiesPrefabs;
        _spawnRadius = currentLevelObj.spawnRadius;
        _reloadTime = currentLevelObj.spawnReload;

        foreach(int num in _levelEnemiesCount) {
            allEnemiesCount += num;
        }

        while(_enemiesQueue.Count < allEnemiesCount){
            int randomIndex = Random.Range(0, _levelEnemiesCount.Count);
            if (_levelEnemiesCount[randomIndex] == 0) {
                continue;
            } else {
                _enemiesQueue.Add(_levelEnemiesList[randomIndex]);
                _levelEnemiesCount[randomIndex] --;
            }
        }
    }

    public void SetPlayerForSpawn (GameObject player) {
        _spawnPoint = player;
    }

    void Update ()
    {           
        if (_spawnPoint != null){
            SpawnEnemies();
        }
        
    }

    public void SpawnEnemies() 
    {
        _reloadPause += Time.deltaTime;
        if (_reloadPause >= _reloadTime && currentEnemiesListPos < allEnemiesCount) {
            GameObject go = PoolManager.Instanse.Spawn(_enemiesQueue[currentEnemiesListPos],new Vector3((Random.value < 0.5f) ? Random.Range(_spawnPoint.transform.position.x + _spawnOfsetRadius, _spawnPoint.transform.position.x + _spawnRadius) : Random.Range(_spawnPoint.transform.position.x - _spawnOfsetRadius, _spawnPoint.transform.position.x - _spawnRadius), -5, (Random.value < 0.5f) ? Random.Range(_spawnPoint.transform.position.z + _spawnOfsetRadius, _spawnPoint.transform.position.z + _spawnRadius) : Random.Range(_spawnPoint.transform.position.z - _spawnOfsetRadius, _spawnPoint.transform.position.z - _spawnRadius)), Quaternion.identity);
            Enemy enemy = go.GetComponent<Enemy>();
            Debug.Log(enemy._enemyHealth);
            enemy.Init();
            _reloadPause = 0;
            currentEnemiesListPos ++;
        } else if (currentEnemiesListPos == allEnemiesCount && _isBossSpawned == true) {
            Instantiate(_boss,new Vector3(0,0,0), Quaternion.identity);
            _isBossSpawned = true;
        }
        
    }
}

So when enemy is spawned i try to init him here enemy.Init(); but had error Object reference not set to an instance of an object. But here Debug.Log(enemy._enemyHealth); i get number of enemy health. How i can Init my enemy from here if enemy has class 'Usual Enemy' and it extends from this class 'Enemy' and i wiil have more enemy child cllases?

答案1

得分: 0

问题不在于“敌人”对象。它不是空的。如果你看一下调用栈中的最后一个引用,你会发现它是“_animator”字段。

这可能是因为你在Unity引擎调用“敌人”对象的“Start”方法之前调用了“Init”函数。

英文:

The problem is not about "enemy" object. It is not null. If you look at the last reference on your call stack, you see that it is "_animator" field.

It's probably because you call the "Init" function before the "enemy" object's "Start" method called by Unity engine.

huangapple
  • 本文由 发表于 2023年6月1日 18:54:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76381166.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定