Search Unity

NullReferenceException

Discussion in 'Scripting' started by JamesBer, Jan 25, 2018.

  1. JamesBer

    JamesBer

    Joined:
    Jan 25, 2018
    Posts:
    3
    I'm using instantiation to set up a chess board. I've managed to get the board itself to work but cannot do the same for the pieces:

    Code containing the error:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Board : MonoBehaviour
    6. {
    7.     //Assigning GameObjects and Sprites for instantiation
    8.     public GameObject CellPrefab;
    9.  
    10.     public Sprite GreenCell;
    11.     public Sprite YellowCell;
    12.  
    13.     public GameObject PawnPrefab, KnightPrefab, BishopPrefab, RookPrefab, QueenPrefab, KingPrefab;
    14.  
    15.     public Sprite WhitePawn, WhiteKnight, WhiteBishop, WhiteRook, WhiteQueen, WhiteKing;
    16.     public Sprite BlackPawn, BlackKnight, BlackBishop, BlackRook, BlackQueen, BlackKing;
    17.  
    18.     public Material whitePieceMat, blackPieceMat;
    19.  
    20.     public GameObject[,] Squares = new GameObject[8,8];
    21.  
    22.     //This is a list for the columns on the board
    23.     [HideInInspector]
    24.     public static string[] alphabet = new string[] {"A", "B", "C", "D", "E", "F", "G", "H"};
    25.  
    26.     //This function is here to create a delay, so that each of the squares on the board is drawn one by one
    27.     //Beacuse it makes a cool effect.
    28.     public void CreateBoard()
    29.     {
    30.         StartCoroutine(DrawBoard());
    31.         SetupPieces();
    32.     }
    33.  
    34.     //This is the function that actually draws the board
    35.     IEnumerator DrawBoard()
    36.     {
    37.         for (int i = 0; i < 8; i++)
    38.         {
    39.             for (int j = 0; j < 8; j++)
    40.             {
    41.                 yield return 0;
    42.                 Squares[i, j] = Instantiate(CellPrefab, new Vector3(i, j, 0), Quaternion.identity);
    43.                 //Black Squares have must either have both X and Y coordinates even or both odd
    44.  
    45.                 if (i % 2 != 0 && j % 2 != 0 || i % 2 == 0 && j % 2 == 0)
    46.                 {
    47.                     Squares[i, j].GetComponent<SpriteRenderer>().sprite = GreenCell;
    48.                 }
    49.  
    50.                 else
    51.                 {
    52.                     Squares[i, j].GetComponent<SpriteRenderer>().sprite = YellowCell;
    53.                 }
    54.  
    55.                 //These lines give each cell a unique letter and number between "A1" and "H8" so that I can distinguish them later
    56.                 Squares[i, j].transform.SetParent(gameObject.transform);
    57.                 Squares[i, j].name = alphabet[i] + (j + 1);
    58.             }
    59.         }
    60.     }
    61.  
    62.     GameObject[] PieceArrangement;
    63.  
    64.     public void SetupPieces()
    65.     {
    66.         PieceArrangement = new GameObject[8]
    67.         {
    68.             RookPrefab,        // R = 0
    69.             KnightPrefab,      // N = 1
    70.             BishopPrefab,      // B = 2
    71.             QueenPrefab,       // Q = 3
    72.             KingPrefab,        // K = 4
    73.             BishopPrefab,      // B = 5
    74.             KnightPrefab,      // N = 6
    75.             RookPrefab         // R = 7
    76.         };
    77.  
    78.         for (int i = 0; i < 8; i++)
    79.         {
    80.             // SETUP 1st RANK WHITE PIECES
    81.             GameObject WhiteNew = Instantiate(PieceArrangement[i], Squares[i, 0].transform);
    82.             WhiteNew.gameObject.GetComponent<Piece>().white = true;
    83.             WhiteNew.GetComponent<Renderer>().material = whitePieceMat;
    84.  
    85.             // SETUP 2nd RANK WHITE PAWNS
    86.             GameObject PWhiteNew = (GameObject)Instantiate(PawnPrefab, Squares[i, 1].transform);
    87.             PWhiteNew.gameObject.GetComponent<Piece>().white = true;
    88.             PWhiteNew.GetComponent<SpriteRenderer>().sprite = WhitePawn;
    89.  
    90.             // SETUP 7th RANK BLACK PAWNS
    91.             GameObject PBlackNew = (GameObject)Instantiate(PawnPrefab, Squares[i, 6].transform);
    92.             PBlackNew.gameObject.GetComponent<Piece>().white = false;
    93.             PBlackNew.GetComponent<SpriteRenderer>().sprite = BlackPawn;
    94.  
    95.             // SETUP 8th RANK BLACK PIECES
    96.             GameObject BlackNew = (GameObject)Instantiate(PieceArrangement[i], Squares[i, 7].transform);
    97.             BlackNew.gameObject.GetComponent<Piece>().white = false;
    98.             BlackNew.GetComponent<Renderer>().material = blackPieceMat;
    99.         }
    100.     }
    101.  
    102.     public void Rotate()
    103.     {
    104.         for (int i = 0; i < 8; i++)
    105.         {
    106.             for (int j = 0; j < 8; j++)
    107.             {
    108.                 Squares[i, j].gameObject.transform.localPosition = new Vector3(
    109.                     7 - Squares[i, j].gameObject.transform.localPosition.x,
    110.                     7 - Squares[i, j].gameObject.transform.localPosition.y,
    111.                     0);
    112.             }
    113.         }
    114.         print("Board rotated");
    115.     }
    116.  
    117. }
    Game Manager:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GameManager : MonoBehaviour
    6. {
    7.  
    8.     Board board;
    9.  
    10.     void Start()
    11.     {
    12.         board = gameObject.GetComponent<Board>();
    13.         board.CreateBoard();
    14.     }
    15.  
    16.     void Update()
    17.     {
    18.         if (Input.GetKeyDown(KeyCode.Space))
    19.         {
    20.             board.Rotate();
    21.         }
    22.     }
    23. }
    24.  
     
  2. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    1. Look at the line the error is reporting.
    2. Debug variables in that line until you find something null.
    3. Figure out how to make that thing not null.
    In your case

    Code (csharp):
    1. WhiteNew.gameObject.GetComponent<Piece>().white = true;
    The only two things that can be null are 'WhiteNew' and the '<Piece>' component. If 'WhiteNew' exists, then there is no Piece component on it.
     
  3. JamesBer

    JamesBer

    Joined:
    Jan 25, 2018
    Posts:
    3
    Thanks for the quick response, but the code hits the error before it reaches that line. I put a Debug.Log above that line and it didn't do anything, but it did above the previous line. So the error must be on the line above.
     
  4. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    The easiest would be to step through using the debugger.
    Also, always try to make sure the lines of the source file and the snippets you post here match or tell us at least which line it actually is (inside the source file).

    Anyway, it seems the problem occurs due to your way of initializing everything.
    You use a coroutine to populate the squares array, but just right after starting the coroutine (which is going to execute everything in your code immediately until it hits the first yield statement), you call the setup method which does already access the square array's elements.

    So the coroutine will stop before it creates the first element for the square array and yields its control - the next part will be executed in the frame (as you yield 0 - which is basically saying "wait one frame").
    StartCoroutine will now return and the CreateBoard method executes SetupPieces.

    Since the coroutine has not finished (and has not even created a single square/cell whatever you call it), you're about to access null entries in the following line:

    Code (CSharp):
    1.  GameObject WhiteNew = Instantiate(PieceArrangement[i], Squares[i, 0].transform);
     
    Last edited: Jan 27, 2018
  5. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,537
    All null reference exceptions are debugged the same way. The way to debug them is so straightforward that some sites don't even allow posting questions about null ref exceptions.

    Find the line it says is the problem, log the variables until you find something null, use common sense and work backwards until you find out why it is null, then correct the issue.

    If you're using someone elses code and this is an error you are getting (likely) then you need to contact the author, not us.
     
  6. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Based on @Suddoha 's explanation, I'd suggest that you put "SetupPieces();" at the end of the coroutine. Also, change "yield return 0;" to "yield return null;" :)