英文:
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' 类继承的,而且我将会有更多的敌人子类,我如何从这里初始化我的敌人呢?
你可以尝试使用以下方法来解决这个问题:
-
确保预制件正确配置: 确保你的敌人预制件(Prefab)已正确配置,并且在预制件上已经附加了相应的脚本组件。确保
enemy.Init();
中的enemy
不为 null。 -
检查子类的初始化方法: 如果你有多个敌人子类,确保每个子类都实现了
Init()
方法。你可以在每个子类中重写Init()
方法,以确保它们的初始化逻辑正确执行。 -
使用多态: 你可以使用多态来确保调用适当的子类的
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论