Search Unity

Instantiating a Script's GameObject at a specific location

Discussion in 'Scripting' started by littlepigboy5, Feb 25, 2017.

  1. littlepigboy5

    littlepigboy5

    Joined:
    Sep 2, 2015
    Posts:
    28
    First I will explain the functionality (it's tetris by the way). I have two scripts. One script is called "Controller" and is attatched to an empty gameObject in my scene. It contains an array of GameObjects that is populated with a prefab for each of the tetris pieces I have created. Then I have a TetrisPiece Script that I attatch to each of the prefabs. They each of a public GameObject variable that I set to their respective prefabs in the Inspector. My Controller script is supposed to queue up a piece and then move it to selected, but I am getting a Null Reference exception that I will post below.

    NullReferenceException
    Controller.newQueuedPiece (Int32 i) (at Assets/Scripts/Controller.cs:63)
    Controller.Start () (at Assets/Scripts/Controller.cs:32)

    Here is the necessary code from the Controller Script:
    public class Controller : MonoBehaviour {

    public GameObject l;
    public GameObject backwardsL;
    public GameObject lStacked;
    public GameObject rStacked;
    public GameObject square;
    public GameObject tPiece;
    public GameObject tallPiece;
    System.Random randy = new System.Random();
    GameObject[] goArr;

    TetrisPiece selectedPiece;
    TetrisPiece queuedPiece;
    int level;
    void Start () {
    goArr = new GameObject[] {l, backwardsL, lStacked, rStacked, square, tPiece, tallPiece};
    level = 1;
    newQueuedPiece(randy.Next(6));
    newSelectedPiece();
    }

    void newSelectedPiece() {
    this.selectedPiece = this.queuedPiece;
    this.selectedPiece.speedChange(levelForSpeed[level]);
    this.selectedPiece.startMoving();
    newQueuedPiece(randy.Next(6));
    }

    void newQueuedPiece(int i) {
    this.queuedPiece = new TetrisPiece(this.goArr);
    Instantiate(this.queuedPiece.gameObject, new Vector3(12.9f, 23.25f, -2.0f), new Quaternion(0, 0, 0, 0));
    }

    }

    Here is the necessary code from the tetrisPiece Script:
    public class TetrisPiece : MonoBehaviour {

    public GameObject piece;

    public TetrisPiece(GameObject go) {
    this.piece = go;
    }

    }​
    Why am I getting this NullReference Exception?
     
  2. DanielQuick

    DanielQuick

    Joined:
    Dec 31, 2010
    Posts:
    3,137
    Please use code tags when posting code.

    MonoBehaviours should not be created by using new, but by using AddComponent. However it doesn't look like you are trying to create a new component, but to find one.

    I suspect what you are trying to do is Instantiate the piece, then assign queuedPiece to the instance's TetrisPiece component.
    Code (csharp):
    1. GameObject newPiece = (GameObject) Instantiate(this.goArr[i], new Vector3(12.9f, 23.25f, -2.0f), Quaternion.identity);
    2. this.queuedPiece = newPiece.GetComponent<TetrisPiece>();
    To answer your question, you are getting a null reference because you created a new TetrisPiece and asked for its .gameObject variable which doesn't exist.
     
  3. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Why is TetrisPiece a MonoBehaviour. Do you plan on attaching this script to a GameObject? Or is it just a data class to keep track of various Tetris Pieces in your game? If its just designed as a data class remove the MonoBehaviour from it and change this line:
    Code (CSharp):
    1. this.queuedPiece = new TetrisPiece(this.goArr);
    to:
    Code (CSharp):
    1. this.queuedPiece = new TetrisPiece(this.goArr[i]);
    You want to pass the index of the object in the goArr not the reference to the entire array to your tetrisPiece constructor.

    If TetrisPiece is supposed to be attached to a game object and do things like Start,Update. Then you have to rethink how your doing this. Monos aren't meant to be created with new. They are created by attaching them to GameObjects in your scene.. or being instantiated from a prefab. Though I suspect from your code your wanting this to be a data object that has a reference to the GO that the piece is on the screen.
     
  4. littlepigboy5

    littlepigboy5

    Joined:
    Sep 2, 2015
    Posts:
    28
    Maybe you could tell me the best way to implement the functionality I desire. I thought that each piece needed a script in order to move at all. Basically, I want an emptygameobject to have a controller script and that controller script has two tetris pieces stored as variable: selectedPiece and queued piece. When a piece moves from the queue to Selected, a new piece is created and queued piece is set equal to that new piece. That I think I can do, but how should I handle each tetris piece? I have a prefab for each piece and my plan was to attatch the Tetris piece script to each piece so that on Update() it could move down by 1. But, in order for it to attatch to the prefab, it needs to be monobehavior. But for it to be controlled in another script, it needs to be a class.
     
  5. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    MonoBehaviours are classes. If you create a Tetris Piece script that is a monobehaviour.. that means its a class that inherits monobehaviour. Attach this script to all your Prefabs. When you instantiate a Prefab. Unity automatically creates on the components on that prefab, as well as scripts. It does do a new TetrisPiece just like you think you need to but it does it behind the scenes. Just put your script on your prefab and it will run when you instantiate the prefab.