Home > OS >  Unity - What is OOP - Null Reference Exception
Unity - What is OOP - Null Reference Exception

Time:10-07

im kind of newbie to unity and object oriented programming. Recently im trying to clone Cube Surfer mobile game. Basic idea from my view is this ;

-When we triggered to collactable cubes which consist script will be duplicated and it will be belong the main cube parent as child object then triggered cube will be destroyed.(After positioning)

-Later this duplicate child objects(cubes) will do the same when they enter trigger area of other collectable cubes(those will be the same prefab but did not yet create a prefab)

Im trying to collect(create a clone of it position and destroy the object) cubes. For first cube, I added some code to my movement script which is below.

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

public class Movement : MonoBehaviour
{
    public GameObject addup;
    Rigidbody rb;
    float controlSpeed = 1.25f;
    float forwardMovementSpeed = 10f;
    private Vector3 axisGet;
    float deathTime;
    public int collected;

    // Start is called before the first frame update
    void Start()
    {
        rb = gameObject.GetComponent<Rigidbody>();
        collected = 0;
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        axisGet = new Vector3(0, 0, Input.GetAxis("Horizontal"));
        rb.MovePosition(transform.position   Vector3.left * forwardMovementSpeed * Time.deltaTime   axisGet * controlSpeed * Time.deltaTime);
    }

    private void OnTriggerEnter(Collider other)
    {
        if(other.tag=="add up")
        {
            gameObject.transform.position  = Vector3.up;
            var newObject = Instantiate(addup.gameObject, Vector3.zero, Quaternion.identity);
            newObject.transform.parent = transform;
            newObject.transform.position = gameObject.transform.position   Vector3.down;
            Destroy(other.gameObject);
            newObject.GetComponent<BoxCollider>().isTrigger = false;
            collected  ;
        }
    }
}

WORKED WITHOUT ERROR BUT THEN, I applied the same method to collectable cubes scripts.

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

public class UpNdown : MonoBehaviour
{
    
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "add up")
        {
            GameObject parentTransform;//?????????
            parentTransform = gameObject.GetComponentInParent<GameObject>(); //get first cube component
            parentTransform.transform.position  = Vector3.up; //first cube one unit up
            GameObject newObject; // ?????????
            newObject = Instantiate(other.gameObject, Vector3.zero, Quaternion.identity) as GameObject; //???????????
            Debug.Log(newObject);
            var collect = parentTransform.GetComponent<Movement>().collected;
            if (other != null)
            {
                Destroy(other.gameObject); //destroy triggered collactable
            }
            
            newObject.transform.parent = parentTransform.transform; //setting parent to new cube
            newObject.transform.position = parentTransform.transform.position   Vector3.down * (collect   1); //setting position of new cube
            newObject.GetComponent<BoxCollider>().isTrigger = false; //prepare the below cubes(new cubes) for trigger with other collactable cubes
            collect  ;
        }
    }
}

And, I had nullexception error in every line in ontriggerenter method then, I changed(added) the lines with question marks. So, I get

ArgumentException: GetComponent requires that the requested component 'GameObject' derives from MonoBehaviour or Component or is an interface. UnityEngine.GameObject.GetComponentInParent[T] (System.Boolean includeInactive) (at :0) UnityEngine.GameObject.GetComponentInParent[T] () (at :0) UpNdown.OnTriggerEnter (UnityEngine.Collider other)

I thought, I understood the OOP instance idea which objects in the scenes are instances scripts has their own value... but i dont understand that while I was operating on a instance why it is null in the memory :((((((((((((( if PC can't access how instantiates the object ?

SORRY I WRITE THIS LONG BUT IM ABOUT THE EDGE AGAIN I DON'T WANT TO QUIT BECAUSE OF FACING THIS PROBLEM AGAIN

TY FOR YOUR ANSWERS, ALREADY APPRECIATED :)

CodePudding user response:

GameObject is no component (it is rather a container of all components attached to it!)

=> you can't get it using GetComponent or GetComponentInParent at all. (Btw Note that GetComponentInParent starts the search on this object itself first before bubling up the hierarchy so either way this isn't what you want to use).


What you want is simply transform.parent to get the Transform component of the parent object of the object this script is attached to (assuming the rest of your code does what it should)

private void OnTriggerEnter(Collider other)
{
    // Rather use CompareTag instead of string ==
    // The latter silently fails in case of typos making your debugging life miserabel
    // it is also slightly less efficient
    if (!other.CompareTag("add up")) return;
    
    // Get the parent of this object
    var parentTransform = transform.parent;
    // Cache this you will need it later see below
    var parentMovement = parentTransform.GetComponent<Movement>();
    var collect = parentMovement.collected;

    parentTransform.position  = Vector3.up;

    // By using the correct type you want later you can skip GetComponent
    var newObjectCollider = Instantiate(other, Vector3.zero, Quaternion.identity);
    Debug.Log(newObjectCollider);
           
    Destroy(other.gameObject);
    
    newObjectCollider.transform.parent = parentTransform;
    newObjectCollider.transform.position = parentTransform.position   Vector3.down * (collect   1);
    newObjectCollider.isTrigger = false;
    // This does absolutely nothing. Numeric values are passed by value and there is no connection
    // between your local variable and the component you got it from
    //collect  ;
    // you probably rather want to increase
    parentMovement.collected  ;
}

Or alternatively since you anyway have a specific component on your parent object you could also do

    // Instead directly get this component
    var parentMovement = GetComponentInParent<Movement>();
    // Then wherever needed access the transform through it
    var parentTransform = parentMovement.transform;
    ...

I'm quite sure though that the other way round it is more efficient since you already know exactly which parent you are searching the component on.


Or - and this would probably be the best option - cache that parent information once right away:

// If possible already reference this vis the Inspector
[SerializeField] private Movement parentMovement;

private Transform parentTransform;

private void Awake ()
{
    if(! parentMovement) parentMovement = GetComponentInParent<Movement>();

    parentTransform = parentMovement.transform;
} 

CodePudding user response:

Ty sir my first code was nearly the same of your first answer but didn't work again at least for error.


private Transform parentTransform;

private void Awake ()
{
    if(! parentMovement) parentMovement = GetComponentInParent<Movement>();

    parentTransform = parentMovement.transform;
} 

But this worked, I guess the problem I need to define instances to class so they don't disappear instantly on the trigger function or direct I need to define them to class.

Anyway, thank you derHugo now need to solve different problems :D

  • Related