How can i fix the null reference?
I am making a voxel world that generates an unlimited world but my problem is that I am getting a null reference on returning the type of Block. I started getting this error after i started turning the gameobjects.setActive(false). I dont know how to get the return that i need.
WorldScript:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class WorldScript : MonoBehaviour
{
public int[,,] data;
public List<BlockData> blocks;
[System.Serializable]
public class BlockData
{
public string name;
public Vector2 texture;
}
public int chunksAcross = 4;
public int chunksUp = 1;
private int worldX=16;
private int worldY=16;
private int worldZ=16;
public GameObject chunk;
public GameObject[,,] chunks;
public int chunkSize=16;
public float texturesAcross = 4;
public float textureUnit;
// GUI Variables
private float smoothGrass;
private float smoothStone;
private float grassHeightScale;
private float stoneHeightScale;
private float grassExponent;
private float stoneExponent;
private float grassAddition;
private float stoneAddition;
private float waterHeight;
public GameObject player;
public int renderDistance = 50;
void Start ()
{
textureUnit = 1/texturesAcross;
worldX = chunksAcross * chunkSize;
worldY = chunksUp * chunkSize;
worldZ = chunksAcross * chunkSize;
player.transform.position = new Vector3 (chunkSize*chunksAcross/2, 300, chunkSize*chunksAcross/2);
CreateChunks ();
}
void Update ()
{
DistanceToChunk ();
}
void OnGUI ()
{
GUI.Window(0, new Rect(10, 10, 200, 500), OptionsWindow, "Options");
}
void OptionsWindow (int id)
{
GUI.Label(new Rect(10, 30, 1000, 1000), "Grass_Smooth:");
smoothGrass = GUI.HorizontalSlider(new Rect(10, 50, 100, 20), smoothGrass, 1, 100);
GUI.Label(new Rect(10, 70, 1000, 1000), "Grass_HeightScale:");
grassHeightScale = GUI.HorizontalSlider(new Rect(10, 90, 100, 20), grassHeightScale, 1, 100);
GUI.Label(new Rect(10, 110, 1000, 1000), "Grass_Exponent:");
grassExponent = GUI.HorizontalSlider(new Rect(10, 130, 100, 20), grassExponent, 1, 2);
GUI.Label(new Rect(10, 150, 1000, 1000), "Stone_Smooth:");
smoothStone = GUI.HorizontalSlider(new Rect(10, 170, 100, 20), smoothStone, 1, 100);
GUI.Label(new Rect(10, 190, 1000, 1000), "Stone_HeightScale:");
stoneHeightScale = GUI.HorizontalSlider(new Rect(10, 210, 100, 20), stoneHeightScale, 1, 100);
GUI.Label(new Rect(10, 230, 1000, 1000), "Stone_Exponent:");
stoneExponent = GUI.HorizontalSlider(new Rect(10, 250, 100, 20), stoneExponent, 1, 2);
GUI.Label(new Rect(10, 270, 1000, 1000), "Grass_Addition:");
grassAddition = GUI.HorizontalSlider(new Rect(10, 290, 100, 20), grassAddition, 1, 100);
GUI.Label(new Rect(10, 310, 1000, 1000), "Stone_Addition:");
stoneAddition = GUI.HorizontalSlider(new Rect(10, 330, 100, 20), stoneAddition, 1, 100);
GUI.Label(new Rect(10, 350, 1000, 1000), "Water_Height:");
waterHeight = GUI.HorizontalSlider(new Rect(10, 370, 100, 20), waterHeight, 1, 100);
if (GUI.Button(new Rect(20, 400, 160, 80), "Generate Terrain"))
{
GenerateTerrain ();
}
}
void DistanceToChunk ()
{
float distance;
for (int x=0; x<chunks.GetLength(0); x++)
{
for (int z=0; z<chunks.GetLength(2); z++)
{
for (int y=0; y<chunks.GetLength(1); y++)
{
distance = Vector3.Distance(chunks[x, y, z].transform.position,player.transform.position);
if (distance <= renderDistance)
{
if (!chunks[x, y, z].GetComponent<ChunkScript>().isRendered)
{
chunks[x, y, z].SetActive(true);
chunks[x, y, z].GetComponent<ChunkScript>().GenerateMesh();
}
}else{
if (chunks[x, y, z].GetComponent<ChunkScript>().isRendered)
{
chunks[x, y, z].GetComponent<ChunkScript>().ClearMesh();
chunks[x, y, z].SetActive(false);
}
}
}
}
}
}
void GenerateTerrain () // ***** WHERE TO ALTER TERRAIN ***** \\
{ // Noise(x,z, smoothness, height, exponent);
data = new int[worldX,worldY,worldZ];
for (int x=0; x<worldX; x++)
{
for (int z=0; z<worldZ; z++)
{
int dirt = Noise(x,z, smoothStone,stoneHeightScale,stoneExponent);
dirt += Mathf.RoundToInt(stoneAddition);
int grass = Noise(x,z, smoothGrass,grassHeightScale,grassExponent);
grass += Mathf.RoundToInt(grassAddition);
for (int y=0; y<worldY; y++)
{
if (y == grass)
{
data[x, y, z] = 1;
}
if(y < grass)
{
data[x, y, z] = 2;
}
if(y < dirt)
{
data[x, y, z] = 3;
}
}
}
}
SpecialGeneration ();
}
void SpecialGeneration ()
{
for (int x=0; x<worldX; x++)
{
for (int z=0; z<worldZ; z++)
{
for (int y=0; y<worldY; y++)
{
// Create Water
if (Block(x, y, z) == 0)
{
if (y < waterHeight)
{
data[x, y, z] = 5;
}
}
// Create Sand
if (Block (x, y, z) == 1)
{
if (y < waterHeight)
{
data[x, y, z] = 4;
}
}
}
}
}
}
int Noise (int x, int z, float scale, float mag, float exp)
{
return (int) (Mathf.Pow ((Mathf.PerlinNoise(x/scale,z/scale)*mag),(exp) ));
}
void CreateChunks ()
{
chunks=new GameObject[Mathf.FloorToInt(worldX/chunkSize),
Mathf.FloorToInt(worldY/chunkSize),
Mathf.FloorToInt(worldZ/chunkSize)];
for (int x=0; x<chunks.GetLength(0); x++)
{
for (int y=0; y<chunks.GetLength(1); y++)
{
for (int z=0; z<chunks.GetLength(2); z++)
{
chunks[x,y,z] = Instantiate(chunk,new Vector3(x*chunkSize,y*chunkSize,z*chunkSize),new Quaternion(0,0,0,0)) as GameObject;
chunks[x,y,z].transform.parent = transform;
ChunkScript newChunkScript= chunks[x,y,z].GetComponent<ChunkScript>();
newChunkScript.worldGO=gameObject;
newChunkScript.chunkSize=chunkSize;
newChunkScript.chunkX=x*chunkSize;
newChunkScript.chunkY=y*chunkSize;
newChunkScript.chunkZ=z*chunkSize;
chunks[x, y, z].SetActive(false);
}
}
}
}
public int Block(int x, int y, int z)
{
if( x>=worldX || x<0 || y>=worldY || y<0 || z>=worldZ || z<0){
return (int) 1;
}
return data[x,y,z];
}
}
Then my ChunkScript is:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class ChunkScript : MonoBehaviour
{
private List<Vector3> newVertices = new List<Vector3>();
private List<int> newTriangles = new List<int>();
private List<Vector2> newUV = new List<Vector2>();
private Mesh mesh;
private MeshCollider col;
private int faceCount;
public float textureUnit;
public float texturesAcross = 4;
public GameObject worldGO;
private WorldScript world;
public int chunkSize=16;
public int chunkX;
public int chunkY;
public int chunkZ;
public bool isRendered = false;
void Start ()
{
worldGO = GameObject.Find("_World");
world = worldGO.GetComponent<WorldScript>();
chunkSize = world.chunkSize;
mesh = GetComponent<MeshFilter> ().mesh;
col = GetComponent<MeshCollider> ();
textureUnit = world.textureUnit;
}
public void ClearMesh()
{
isRendered = false;
newVertices.Clear();
newTriangles.Clear ();
newUV.Clear();
mesh.Clear();
}
public void GenerateMesh()
{
isRendered = true;
newVertices.Clear();
newTriangles.Clear ();
newUV.Clear();
for (int x=0; x<chunkSize; x++)
{
for (int y=0; y<chunkSize; y++)
{
for (int z=0; z<chunkSize; z++)
{
if(Block(x,y,z)!=0)
{
if(Block(x,y+1,z) == 0)
{
CubeTop(x,y,z,Block(x,y,z));
}
if(Block(x,y-1,z) == 0)
{
CubeBottom(x,y,z,Block(x,y,z));
}
if(Block(x+1,y,z) == 0)
{
CubeEast(x,y,z,Block(x,y,z));
}
if(Block(x-1,y,z)==0)
{
CubeWest(x,y,z,Block(x,y,z));
}
if(Block(x,y,z+1)==0)
{
CubeNorth(x,y,z,Block(x,y,z));
}
if(Block(x,y,z-1)==0)
{
CubeSouth(x,y,z,Block(x,y,z));
}
}
}
}
}
UpdateMesh ();
}
int Block(int x, int y, int z)
{
return world.Block(x+chunkX,y+chunkY,z+chunkZ);
}
void UpdateMesh ()
{
mesh.Clear();
mesh.vertices = newVertices.ToArray();
mesh.uv = newUV.ToArray();
mesh.triangles = newTriangles.ToArray();
mesh.Optimize();
mesh.RecalculateNormals();
col.sharedMesh = null;
col.sharedMesh = mesh;
faceCount = 0;
}
void CubeTop (int x, int y, int z, int blockType)
{
newVertices.Add(new Vector3(x, y, z+1));
newVertices.Add(new Vector3(x+1, y, z+1));
newVertices.Add(new Vector3(x+1, y, z));
newVertices.Add(new Vector3(x, y, z));
Vector2 texturePos = world.blocks[blockType].texture;
TextureCube (texturePos);
}
void CubeBottom (int x, int y, int z, int blockType)
{
newVertices.Add(new Vector3(x, y-1, z));
newVertices.Add(new Vector3(x+1, y-1, z));
newVertices.Add(new Vector3(x+1, y-1, z+1));
newVertices.Add(new Vector3(x, y-1, z+1));
Vector2 texturePos = world.blocks[blockType].texture;
TextureCube (texturePos);
}
void CubeNorth (int x, int y, int z, int blockType)
{
newVertices.Add(new Vector3(x+1, y-1, z+1));
newVertices.Add(new Vector3(x+1, y, z+1));
newVertices.Add(new Vector3(x, y, z+1));
newVertices.Add(new Vector3(x, y-1, z+1));
Vector2 texturePos = world.blocks[blockType].texture;
TextureCube (texturePos);
}
void CubeSouth (int x, int y, int z, int blockType)
{
newVertices.Add(new Vector3(x, y-1, z));
newVertices.Add(new Vector3(x, y, z));
newVertices.Add(new Vector3(x+1, y, z));
newVertices.Add(new Vector3(x+1, y-1, z));
Vector2 texturePos = world.blocks[blockType].texture;
TextureCube (texturePos);
}
void CubeEast (int x, int y, int z, int blockType)
{
newVertices.Add(new Vector3(x+1, y-1, z));
newVertices.Add(new Vector3(x+1, y, z));
newVertices.Add(new Vector3(x+1, y, z+1));
newVertices.Add(new Vector3(x+1, y-1, z+1));
Vector2 texturePos = world.blocks[blockType].texture;
TextureCube (texturePos);
}
void CubeWest (int x, int y, int z, int blockType)
{
newVertices.Add(new Vector3(x, y-1, z+1));
newVertices.Add(new Vector3(x, y, z+1));
newVertices.Add(new Vector3(x, y, z));
newVertices.Add(new Vector3(x, y-1, z));
Vector2 texturePos = world.blocks[blockType].texture;
TextureCube (texturePos);
}
void TextureCube (Vector2 texturePos)
{
newTriangles.Add(faceCount*4);
newTriangles.Add(faceCount*4+1);
newTriangles.Add(faceCount*4+2);
newTriangles.Add(faceCount*4);
newTriangles.Add(faceCount*4+2);
newTriangles.Add(faceCount*4+3);
newUV.Add(new Vector2(textureUnit * texturePos.x+textureUnit, textureUnit*texturePos.y));
newUV.Add(new Vector2(textureUnit * texturePos.x+textureUnit, textureUnit*texturePos.y + textureUnit));
newUV.Add(new Vector2(textureUnit * texturePos.x, textureUnit*texturePos.y + textureUnit));
newUV.Add(new Vector2(textureUnit * texturePos.x, textureUnit*texturePos.y));
faceCount ++;
}
}
The null reference is occurring on the ChunkScript in the part that says:
int Block(int x, int y, int z)
{
return world.Block(x+chunkX,y+chunkY,z+chunkZ); *** This is the line that has the error ***
}
I know it is a ton of code to read but I dont know what else to do. Thank you for helping
Answer by robin-theilade · Sep 05, 2015 at 07:30 PM
@Theacesofspades, My guess is that WorldScript.DistanceToChunk is not waiting for the chunk's Start method to be called after setting it active before callings it's GenerateMesh method which in turn calls the Block method that throws the exception. The start method is required for the field ChunkScript.world to be assigned.
Use breakpoints or Debug.Log to verify the order of calling with the ChunkScript.Block, ChunkScript.Start and WorldScript.GenerateMesh (just after setting the chunk active) methods.
Edit: Extended answer
=== ChunkScript.cs changes ===
Replace the Start
method with this.
void Awake()
{
world = GameObject.FindObjectOfType<WorldScript>();
chunkSize = world.chunkSize;
mesh = GetComponent<MeshFilter>().mesh;
col = GetComponent<MeshCollider>();
textureUnit = world.textureUnit;
}
Changing from Start
to Awake
method means it gets invoked earlier which is needed in this case.
Remove public GameObject worldGO;
.
=== WorldScript.cs changes ===
Remove newChunkScript.worldGO=gameObject;
This can't be the solution because the chunks all get created then I move the player down from above about 5 seconds after the game is started
Thank you so so much. I changed the start function to awake and it worked perfectly. I needed to keep the worldGO though. But thank you so much.