-1
\$\begingroup\$

I am using Unity. I created a Background class and a Cube class which are empty. Also I have a GameEngine class.

I have a 5x5 background prefabs on the game screen. I want every background to have a cube object. So I wrote public Background b; in Cube class.

GameEngine

using UnityEngine;
using System.Collections;

public class GameEngine : MonoBehaviour {

    public GameObject backgroundPrefab;
    public GameObject CubePrefab;

    public int X = 5, Y = 5;

    void Start () {
        Background b;
        Cube c;

        for (int i = 0; i < X; i++)
            for (int j = 0; j < Y; j++) {
                Vector3 pos = new Vector3(backgroundPrefab.transform.localScale.x * (i - (X - 1) / 2f), 0, backgroundPrefab.transform.localScale.z * (j - (Y - 1) / 2f));
                b = Instantiate(backgroundPrefab, pos, Quaternion.identity) as Background;
                c = Instantiate(CubePrefab, pos, Quaternion.identity) as Cube;
                //c.b = b;
            }
    }

    void Update () {

    }
}

It works like that but when I uncomment that line, it gives me that:

NullReferenceException: Object reference not set to an instance of an object
GameEngine.Start () (at Assets/Scripts/GameEngine.cs:20)

How can I attach every cube object to the background objects? And why is this not working? Isn't b is an instance of Background?

\$\endgroup\$

2 Answers 2

0
\$\begingroup\$

It looks like the problem might be that you're trying to cast the results of Instantiate to a Background and Cube, respectively. The "as" keyword in C# will return null if the requested cast is not appropriate. Double-check what type Instantiate returns...

Even though you defined "Background" and "Cube" classes, you probably made them as script components of their respective GameObject prefabs. Instantiate probably returns GameObjects and GameObjects != script component classes. Script component classes are subclasses of MonoBehavior (or something like that), and those instances need to be accessed by the GetComponent method of the GameObject.

edit: Ya see, check this out, looks like you want this:

After cloning an object you can also use GetComponent to set properties on a specific component attached to the cloned object.

using UnityEngine;

public class InstantiateComponentExample : MonoBehaviour
{
    // Instantiate a prefab with an attached Missile script
    public Missile missilePrefab;

    void Start()
    {
        // Instantiate the missile at the position and rotation of this object's transform
        Missile clone = (Missile)Instantiate(missilePrefab, transform.position, transform.rotation);
    }
}

(see http://docs.unity3d.com/ScriptReference/Object.Instantiate.html)

Conceptually, if every Cube is supposed to have a Background, then can you just create a GameObject that has the Background and Cube already together and make that combo GameObject into a prefab?

\$\endgroup\$
1
  • \$\begingroup\$ To clarify, Instantiate returns an instance of the same type as the prefab you put in. So if your prefab is of type GameObject, it will return a GameObject (boxed as a UnityEngine.Object if you're not using the generic Instantiate<T>). If ultimately you want the Cube & Background components attached to the objects, you can use those as the types of your public variables. Then the inspector will enforce that only objects with the appropriate component can be assigned to those fields. Instantiate will still spawn the whole object with the component attached, not a free-floating component. \$\endgroup\$
    – DMGregory
    Commented Aug 8, 2016 at 3:24
-1
\$\begingroup\$

OP please clarify what I commented in my answer. This answer has wrong details I'd like to clarify before fixing it.

With respect to the written code, although having a GameObject variable out there, it is not a priori linked to anything.

If you have done more steps related to this answer, then please notify and I adapt it. For what I know right now, it seems these steps are missing.

You declared your public variables:

public GameObject backgroundPrefab;
public GameObject CubePrefab;

In the properties editor: You will select your object and add your GameEngine component (or select your object already having such custom component you created). You will see a slot named backgroundPrefab, with a combobox. Set the appropriate value from the combobox, which will be an already-instantiated object to prototype from (prefabs also count to this respect). This also applies to CubePrefab.

Just after you did that, the CubePrefab public variable will hold a value other than null, and you will be able to clone it. Otherwise you are getting just null as well, and then sentences like c.b = b explode appropriately.

Please note: Initialize does not support setting custom values to the properties in the behaviors. If using code instead of the editor, you will do like this:

using UnityEngine;
using System.Collections;

public class GameEngine : MonoBehaviour {

    public GameObject backgroundPrefab { get; private set; };
    public GameObject cubePrefab { get; private set; };
    public Background b { get; private set; };
    public Cube c { get; private set; };
    public int X = 5 { get; private set; };
    public Y = 5 { get; private set; };

    void InitializeWholeData(GameObject backgroundPrefab, GameObject cubePrefab, int X, int Y) {
        this.backgroundPrefab;
        this.cubePrefab;
        this.X = X;
        this.Y = Y;
        for (int i = 0; i < X; i++) {
            for (int j = 0; j < Y; j++) {
                Vector3 pos = new Vector3(backgroundPrefab.transform.localScale.x * (i - (X - 1) / 2f), 0, backgroundPrefab.transform.localScale.z * (j - (Y - 1) / 2f));
                this.b = Instantiate(backgroundPrefab, pos, Quaternion.identity) as Background;
                this.c = Instantiate(CubePrefab, pos, Quaternion.identity) as Cube;
                this.c.b = this.b;
            }
        }
    }
}

This code is untested

Then you create, somewhere else, your object like this:

GameObject foo = new GameObject("foo");
foo.AddComponent<GameEngine>().InitializeWholeData(aBackgroundPrefab, aCubePrefab, 10, 10);
\$\endgroup\$
4
  • \$\begingroup\$ Thank you for the answer. I had already set the values of backgroundPrefab and cubePrefab in combobox. Since I try to reach c and b, I just added {get; set;} next to them. But it still gives that error in that line c.b = b;. \$\endgroup\$ Commented Aug 8, 2016 at 1:57
  • \$\begingroup\$ Please explain more in your question so I can edit it properly: Do you want to clone your backgrounds (they being GameObjects) and attach them a cube (which would be another GameObject for each background)? Or do you care only about their behaviors? (difference: behaviors are just their scripts, while objects have such scripts, and meshes, and so). \$\endgroup\$ Commented Aug 8, 2016 at 15:37
  • \$\begingroup\$ Carify it bringing more context to the question: When will you set the properties (design, runtime, both)? What use will you make of the cubes and backgrounds? Would you like to parent your backgrounds to the object with this behavior, or leave them as separate objects (as they are today)? \$\endgroup\$ Commented Aug 8, 2016 at 15:39
  • \$\begingroup\$ I don't know if I can clarify it well as my English is not so good but I just simply want to have a background script attach to the cube so that when I instantiate the cube(GameObject I think), I can control the corresponding background (GameObject I think). \$\endgroup\$ Commented Aug 9, 2016 at 22:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .