简体   繁体   English

Unity - 什么是 OOP - Null 参考异常

[英]Unity - What is OOP - Null Reference Exception

im kind of newbie to unity and object oriented programming.我是统一和面向 object 编程的新手。 Recently im trying to clone Cube Surfer mobile game.最近我正在尝试克隆 Cube Surfer 手机游戏。 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) -当我们触发包含脚本的可收集立方体时,将被复制并且它将属于主立方体父级作为子级 object 然后触发的立方体将被销毁。(定位后)

-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.我正在尝试收集(创建它的克隆 position 并销毁对象)立方体。 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.而且,我在 ontriggerenter 方法的每一行中都有 nullexception 错误,然后我更改(添加)了带问号的行。 So, I get所以,我得到

ArgumentException: GetComponent requires that the requested component 'GameObject' derives from MonoBehaviour or Component or is an interface. ArgumentException:GetComponent 要求请求的组件“GameObject”派生自 MonoBehaviour 或 Component 或者是一个接口。 UnityEngine.GameObject.GetComponentInParent[T] (System.Boolean includeInactive) (at:0) UnityEngine.GameObject.GetComponentInParent[T] () (at:0) UpNdown.OnTriggerEnter (UnityEngine.Collider other) UnityEngine.GameObject.GetComponentInParent[T] (System.Boolean includeInactive) (at:0) UnityEngine.GameObject.GetComponentInParent[T] () (at:0) UpNdown.OnTriggerEnter (UnityEngine.Collider 其他)

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?我想,我理解 OOP 实例的想法,场景中的对象是实例脚本有它们自己的价值......但我不明白,当我在一个实例上操作时,为什么它在 memory 中是 null:(((((( (((((((如果PC无法访问如何实例化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:)感谢您的回答,已经感谢您:)

GameObject is no component (it is rather a container of all components attached to it!) GameObject不是组件(它是所有附加组件的容器!)

=> you can't get it using GetComponent or GetComponentInParent at all. => 您根本无法使用GetComponentGetComponentInParent获取它。 (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). (顺便说一下, GetComponentInParent会先开始搜索这个 object 本身,然后再向上扩展层次结构,所以无论哪种方式,这都不是您想要使用的)。


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)你想要的只是transform.parent来获取这个脚本附加到的 object 的父 object 的Transform组件(假设你的代码的 rest 做了它应该做的)

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或者,因为您无论如何在您的父母 object 上一个特定的组件,您也可以这样做

    // 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;
} 

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.但这行得通,我想我需要将实例定义为 class 的问题,这样它们就不会在触发器 function 上立即消失,或者直接我需要将它们定义为 class。

Anyway, thank you derHugo now need to solve different problems:D无论如何,谢谢 derHugo 现在需要解决不同的问题:D

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM