Object reference not set to an instance of an object

0

Witam mam 2 skrypty i chcę wywołać funkcje ze skryptu 1 w skrypcie 2, ale pojawia się błąd.

NullReferenceException: Object reference not set to an instance of an object
explosiveBarrel.Explode () (at Assets/Scripts/explosiveBarrel.cs:54)
explosiveBarrel.OnCollisionEnter (UnityEngine.Collision collision) (at Assets/Scripts/explosiveBarrel.cs:28)

Skrypt 1

using UnityEngine;
using UnityEngine.AI;

public class EnemyAiTutorial : MonoBehaviour
{
    public NavMeshAgent agent;

    public Transform player;

    public LayerMask whatIsGround, whatIsPlayer;

    public GameObject bulletPrefab;

    public bool enemyAreDead;

    public Animator animator;

    //Patroling
    public Vector3 walkPoint;
    bool walkPointSet;
    public float walkPointRange;

    //Attacking
    public float timeBetweenAttacks;
    public bool alreadyAttacked;
    public GameObject projectile;

    //States
    public float sightRange, attackRange;
    public bool playerInSightRange, playerInAttackRange;

    private void Awake()
    {
        player = GameObject.Find("Player").transform;
        agent = GetComponent<NavMeshAgent>();
    }

    private void Start()
    {
        animator.enabled = true;
        enemyAreDead = false;
        setRigidbodyState(true);
        setColliderState(false);
    }

    void setRigidbodyState(bool state)
    {
        Rigidbody[] rigidbodies = GetComponentsInChildren<Rigidbody>();

        foreach(Rigidbody rigidbody in rigidbodies)
        {
            rigidbody.isKinematic = state;
        }

        GetComponent<Rigidbody>().isKinematic = !state;
    }

    void setColliderState(bool state)
    {
        Collider[] colliders = GetComponentsInChildren<Collider>();

        foreach (Collider collider in colliders)
        {
            collider.enabled = state;
        }

        GetComponent<Collider>().enabled = !state;
    }


    private void Update()
    {
        //Check for sight and attack range
        playerInSightRange = Physics.CheckSphere(transform.position, sightRange, whatIsPlayer);
        playerInAttackRange = Physics.CheckSphere(transform.position, attackRange, whatIsPlayer);

        if (!playerInSightRange && !playerInAttackRange && !enemyAreDead) Patroling();
        if (playerInSightRange && !playerInAttackRange && !enemyAreDead) ChasePlayer();
        if (playerInAttackRange && playerInSightRange && !enemyAreDead) AttackPlayer();
    }

    private void Patroling()
    {
        if (!walkPointSet) SearchWalkPoint();

        if (walkPointSet)
            agent.SetDestination(walkPoint);

        Vector3 distanceToWalkPoint = transform.position - walkPoint;

        //Walkpoint reached
        if (distanceToWalkPoint.magnitude < 1f)
            walkPointSet = false;
    }
    private void SearchWalkPoint()
    {
        //Calculate random point in range
        float randomZ = Random.Range(-walkPointRange, walkPointRange);
        float randomX = Random.Range(-walkPointRange, walkPointRange);

        walkPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ);

        if (Physics.Raycast(walkPoint, -transform.up, 2f, whatIsGround))
            walkPointSet = true;
    }

    private void ChasePlayer()
    {
        agent.SetDestination(player.position);
    }

    private void AttackPlayer()
    {
        //Make sure enemy doesn't move
        agent.SetDestination(transform.position);

        transform.LookAt(player);
       // transform.rotation *= Quaternion.Euler(0, 0, 0);

        if (!alreadyAttacked)
        {
            ///Attack code here
            GameObject bulletObject = Instantiate(bulletPrefab);
            bulletObject.transform.position = transform.position + new Vector3(0, 1.5f, 0f);
            bulletObject.transform.forward = transform.forward;
            ///End of attack code

            alreadyAttacked = true;
            Invoke(nameof(ResetAttack), timeBetweenAttacks);
        }
    }
    private void ResetAttack()
    {
        alreadyAttacked = false;
    }

    public void killEnemy()
    {
        enemyAreDead = true;
        setRigidbodyState(false);
        setColliderState(true);
        animator.enabled = false;
        Debug.Log("killenemy working");
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.gameObject.tag == "bullet")
        {
            killEnemy();
            Debug.Log("Hitted!");
        }

    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, attackRange);
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, sightRange);
    }
}

Skrypt 2

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

public class explosiveBarrel : MonoBehaviour
{
    public float radius = 5f;
    public float force = 1f;
    bool hasExploded = false;
    public AudioSource audioData;
    public GameObject explosionEffect;

    public Texture[] textures;
    public Renderer rend;
    EnemyAiTutorial ETAI;

    private void Start()
    {
        ETAI = GetComponent<EnemyAiTutorial>();
        audioData = GetComponent<AudioSource>();
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider.gameObject.tag == "bullet" && !hasExploded)
        {
            Explode();
            hasExploded = true;
            Debug.Log("make explode");
        }

    }

    void Explode()
    {

        rend.material.mainTexture = textures[0];

        audioData.Play();

        Vector3 explosionPos = transform.position;

        Instantiate(explosionEffect, transform.position, transform.rotation);

        Collider[] colliders = Physics.OverlapSphere(explosionPos, radius);
        foreach (Collider nearbyObject in colliders)
        {

            if (nearbyObject.tag == "enemy")
            {
                Debug.Log("enemy boom");
                ETAI.killEnemy();
                nearbyObject.GetComponent<Rigidbody>().AddExplosionForce(force, transform.position, radius, 1, ForceMode.Impulse);
            }

            if (nearbyObject.tag == "box")
            {
                Debug.Log("box boom");

                nearbyObject.GetComponent<Rigidbody>().AddExplosionForce(force, transform.position, radius, 1, ForceMode.Impulse);
            }

            if (nearbyObject.tag == "Player")
            {
                Debug.Log("player dead!");
                SceneManager.LoadScene("deathScene");
            }


        }

    }
}

0

Masz informację, że błąd jest w tej linijce:
nearbyObject.GetComponent<Rigidbody>().AddExplosionForce(force, transform.position, radius, 1, ForceMode.Impulse);

Zobacz co zwraca nearbyObject.GetComponent<Rigidbody>().

1

Nie odpowiadaj w komentarzach.

A co zawiera ETAI?

0

Zwraca wartość Null chociaż przypisuje jej odwołanie do skryptu GetComponent<EnemyAiTutorial>();

0

Przejedź po kodzie debugerem i będziesz wszystko wiedział w temacie tego błędu.

1
Дамян Скоцзын napisał(a):

Zwraca wartość Null chociaż przypisuje jej odwołanie do skryptu GetComponent<EnemyAiTutorial>();

Czyli ta metoda zwraca null.
Tak jak mówi ŁF, zaznacz breakpointa na tej linijce i idź kolejno po kodzie (wchodząc w metody) i zobaczysz co się dzieje.

0

Podałem ci odpowiedź w komentarzu do posta na grupie Unity na facebooku i wszystko było ok (nie było zastrzeżeń), więc w celu oszczędzenia czasu innym napiszę, że pytanie nie jest aktualne.

0

Na życzenie @hipekk :D Tutaj chce tego używać

Collider[] colliders = Physics.OverlapSphere(explosionPos, radius);
        foreach (Collider nearbyObject in colliders)
        {

            if (nearbyObject.tag == "enemy")
            {
                Debug.Log("enemy boom");
                ETAI.killEnemy();
                nearbyObject.GetComponent<Rigidbody>().AddExplosionForce(force, transform.position, radius, 1, ForceMode.Impulse);
            }
      }

A referencja do skryptu ETAI jest pobierana w Start()

 private void Start()
    {
        ETAI = GetComponent<EnemyAiTutorial>();
        audioData = GetComponent<AudioSource>();
    }

GetComponent<EnemyAiTutorial>(); to jest to samo co gameObject.GetComponent<EnemyAiTutorial>();
Czyli explosiveBarrel próbuje znaleźć komponent "EnemyAiTutorial" w tym samym gameobjectcie do którego sam jest dołączony, a wybuchowa beczka raczejnie ma EnemyAi, więc getComponent zwraca null.

Dlatego żeby dostać się do skryptu "EnemyAiTutorial" trzeba w foreachu zamiast
ETAI.killEnemy();
zrobić
nearbyObject.GetComponent<EnemyAiTutorial>().killEnemy();

1 użytkowników online, w tym zalogowanych: 0, gości: 1