- Home /
NullReferenceException array
I have a serious problem with this segment of code.....the last part of it when I index through the array it always gives me NullReferenceException but I know the list isnt empty and my Cel class has a position and an h cost to it.
//testt.js
#pragma strict
class testt extends MonoBehaviour //// the representation of a GridCell made from Cells
{
var agentTransform : Transform;
var enemyTransform : Transform;
var parentCell : Cel;
var lowestCost : float;
var list : List.<Cel> = new List.<Cel>();
var cube : Transform;
var hit : RaycastHit;
var distance : int = 10;
var color : Color;
var v : int ;//number of cells
var i : int;
var x : int;
var c : int;
var cellSize : int ;//cell size
var cellSizeX : int;
var cellSizeZ : int;
var scale : int;
var cells : Cel[,];//2d array ------ that ---- accepts only cells
var cel : Cel;
var currentPos : Vector3;
var topLeftCorner : Vector3;
function Start()
{
lowestCost = Mathf.Infinity;
v = 6;
cellSize = 4;
cel.obj = agentTransform;
cel.enemy = enemyTransform;
cel.color = Color.red;
scale = 2;
topLeftCorner =Vector3 (transform.position.x-transform.localScale.x/scale ,transform.position.y ,transform.position.z-transform.localScale.z/scale);
}
function Update()
{
cells = new Cel[v,v];///the size of the 2d array
cellSizeX = transform.localScale.x / cellSize;//width
cellSizeZ = transform.localScale.z / cellSize;//height
for(i = 0 ; i < v ; i ++)
{
for(x = 0 ; x < v ; x ++)
{
////THE CURRENT POSITION AND TYPE OF CELLS////
//print(x);
currentPos = topLeftCorner + Vector3(i*cellSizeX,0,x*cellSizeZ); ////current position of the cell in i,x coordonates
cells[i,x] = cel;////each of cells of coordonates [1,1] or cells[1,2] etc will equal one cell
cells[i,x].celPos =currentPos;
////THE CURRENT POSITION AND TYPE OF CELLS////
////not good
parentCell = cells[i,x].currentCellParent;//parrentCell = the first cell in the list
////not good
//if(list != null)
///{
// list.Clear();
//}
////ADD NEIGHBOUR CELLS////
if(i+1 < v && x+1 < v)
{
if(!list.Contains(cells[i+1,x+1]))////this is better////but still not good////only if list contains the i+1,x+1 if not then add
{
list.Add(cells[i+1,x+1]);////this is better////but still not good////only if list contains the i+1,x+1 if not then add
}
}
if(i-1 > 0 && x-1 > 0)
{
if(!list.Contains(cells[i-1,x-1]))
{
list.Add(cells[i-1,x-1]);
}
}
if(i-1 > 0 && x+1 < v)
{
if(!list.Contains(cells[i-1,x+1]))
{
list.Add(cells[i-1,x+1]);
}
}
if(i+1 < v && x-1 > 0)
{
if(!list.Contains(cells[i+1,x-1]))
{
list.Add(cells[i+1,x-1]);
}
}
if(x+1 < v)
{
if(!list.Contains(cells[i,x+1]))
{
list.Add(cells[i,x+1]);
}
}
if(x-1 > 0)
{
if(!list.Contains(cells[i,x-1]))
{
list.Add(cells[i,x-1]);
}
}
if(i+1 < v)
{
if(!list.Contains(cells[i+1,x]))
{
list.Add(cells[i+1,x]);
}
}
if(i-1 > 0)
{
if(!list.Contains(cells[i-1,x]))
{
list.Add(cells[i-1,x]);
}
}
////ADD NEIGHBOUR CELLS////
//print(list.Count);
////THE LOWEST COST////
for(c = 0 ; c < list.Count ; c++)
{
if(list != null)
{
//list[c] = cells[i,x];////????////
//print("abba");
Instantiate(cube,list[c].celPos,transform.rotation);
if(list[c].h < lowestCost)
{
lowestCost = list[c].h;
}
}
}
////THE LOWEST COST////
////ADD THE LOWEST CELL TO LIST////
if(agentTransform != null)
{
if(cells[i,x].h == lowestCost && !agentTransform.GetComponent(pathFind).theOpenList.Contains(cells[i,x]))
{
cells[i,x].currentCellParent = cells[i,x];////not good
agentTransform.GetComponent(pathFind).theOpenList.Add(cells[i,x]);
}
}
////ADD THE LOWEST CELL TO LIST////
////ADD THE FIRST CELL TO LIST////
if(Physics.Raycast(cells[i,x].celPos , Vector3.up , hit,distance))
{
if(hit.transform.tag == "agent" && hit.transform.GetComponent(pathFind).theOpenList.Count == 0)
{
hit.transform.GetComponent(pathFind).theOpenList.Add(cells[i,x]);
Instantiate(cube,cells[i,x].celPos,transform.rotation);
print(cells.length);
}
}
Debug.DrawRay(cells[i,x].celPos,Vector3(0,10,0), cells[i,x].color);
////ADD THE FIRST CELL TO LIST////
}
}
}
}
//Cel.js
#pragma strict
class Cel ////the representation of a Cell
{
var h : float;
var obj : Transform;
var enemy : Transform; ////the enemy and its distance
var distance : Vector3; ////the distance from this cell to the enemy
var celPos : Vector3; ////this cells position
var color : Color; ////this cells color
var availible : boolean = true;
var inList : boolean = false;
var trueT : boolean = false;
var road : boolean = false;
var object : boolean = false;
var currentCellParent : Cel;//////the parent of this cell
function Cel (position : Vector3, object : Transform, enemyPos : Transform, parent : Cel, hCost : float)
{
h = hCost;
celPos = position;
obj = object; //the object(cellunit) from witch we get the object position, distance,color
enemy = enemyPos;
currentCellParent = parent; //this is better
if(enemy != null)
{
distance = obj.position - enemy.position;
h = distance.magnitude * 10;
}
}
function Update()
{
}
}
The error only appears at runTime and I cant figure out why.....the error always directs me to the part where I try to access the h or position by indexing the list.I really need help.
When you say it only appears at "runTime" do you mean in builds but not in the editor? or just when you click play?
Can you provide which line number the error refers to?
Also can you provide the code where you initialize cells and list? [also, list is not a good name to use for a list, because often list is a reserved word]
You need to
1-Post the whole code if you want us to be able to test it in Unity.
2-Give the exact error message telling us what line the error is on.
Do 2D arrays actually work like this in js var cells : Cel[,];
?
yeah, I just can't find anything online about that syntax in JS
Answer by Peter G · Jul 26, 2013 at 07:57 PM
This is kind of a long explanation. You aren't creating your cells correctly. I'm sorry to say that, but there's no way around it. It looks like you are trying to create one cell then clone it v*v
times to create the entire grid. There's nothing wrong with that idea, but you made Cel
a reference type (as all classes are). What you are actually doing is creating one Cell. Then creating v*v
references to the same cell. Every time you update that cell's position, you are just changing the position of the original cell.
What you need to do is either:
Make cell a value type which it probably should be to begin with. That is your best solution. Just change it to:
class Cel extends System.ValueType that way when you clone it, you will actually copy all the information from one instance to the next.
You can create a new instance of
Cel
for each square if you want. Then you just can't clone it.
That should almost solve all your problems. You have a second problem also. This is what was actually causing your null reference.
if(i+1 < v && x+1 < v) {
if(!list.Contains(cells[i+1,x+1]))////this is better////but still not good////only if list contains the i+1,x+1 if not then add
{
list.Add(cells[i+1,x+1]);////this is better////but still not good////only if list contains the i+1,x+1 if not then add
}
}
This problems a little harder to see. cells[i+1 , x+1]
is probably null on the first frame. You create the whole list of cells, but since Cel
is reference type, the whole array initializes to null
. Since you're going through and creating the rows in order (the double for
loops). cells[i+1 , x+1]
won't actually reference anything until you get to it in the loop (which won't be until v+1) iteration later. Hence when you index them later. list[c]
is still full of lots of nulls.
I think your best solution is to create the whole grid in Start()
and then just do your pathfinding checks in the Update()
. It doesn't look like your grid changes much frame to frame so its best to initialize once and be done with it anyway. The other nice thing about using a value type for your Cel
is you can't get a null reference.
class testt extends MonoBehaviour //// the representation of a GridCell made from Cells
{
var parentCell : Cel;
var list : List.<Cel> = new List.<Cel>();
var v : int ;//number of cells
var i : int;
var x : int;
var c : int;
var cellSize : int ;//cell size
var cellSizeX : int;
var cellSizeZ : int;
var scale : int;
var cells : Cel[,];//2d array ------ that ---- accepts only cells
var cel : Cel;
var currentPos : Vector3;
var topLeftCorner : Vector3;
function Start()
{
lowestCost = Mathf.Infinity;
v = 6;
cellSize = 4;
cel.obj = agentTransform;
cel.enemy = enemyTransform;
cel.color = Color.red;
scale = 2;
topLeftCorner =Vector3 (transform.position.x-transform.localScale.x/scale ,transform.position.y ,transform.position.z-transform.localScale.z/scale);
cells = new Cel[v,v];///the size of the 2d array
cellSizeX = transform.localScale.x / cellSize;//width
cellSizeZ = transform.localScale.z / cellSize;//height
for(i = 0 ; i < v ; i ++)
{
for(x = 0 ; x < v ; x ++)
{
////THE CURRENT POSITION AND TYPE OF CELLS////
//print(x);
currentPos = topLeftCorner + Vector3(i*cellSizeX,0,x*cellSizeZ); ////current position of the cell in i,x coordonates
cells[i,x] = cel;////each of cells of coordonates [1,1] or cells[1,2] etc will equal one cell
cells[i,x].celPos =currentPos;
////THE CURRENT POSITION AND TYPE OF CELLS////
parentCell = cells[i,x].currentCellParent;//parrentCell = the first cell in the list
}
}
}
function Update()
{
for(i = 0 ; i < v ; i ++)
{
for(x = 0 ; x < v ; x ++)
{
//Now do all your checks and stuff.
}
}
}
}
class Cel extends System.ValueType {
//Stuff
}
Thanks for the reply...now I understand how much I still have to go through.....the thing that eludes me....what is the difference betwen a simple class Cel and class Cel extends System.ValueType....I mean what role does the SystemValueType has AND what effect does it have on classes...I also want to know the differences betwen classes with and without valueType. I tested the script with and without the valueType and it gives me different results and I want to understand why.Some example code would be nice.
Extending ValueType makes it a struct rather than a class. It doesn't look suitable for being a struct to me though.
Hmmm. I liked it as a struct. It's relatively small, and I don't think it will change frequently, and it gets cloned like he wants. Why don't you like it as a struct @Eric5h5?
And to Nk.Andrei, structs and classes have lots of differences. I would recommend googling it to learn more. Here's a basic overview.
Answer by perchik · Jul 26, 2013 at 07:59 PM
I think there's all kinds of things wrong in your script. To answer your question though,
I don't see anywhere that you actually initialize a Cel object. Even when you create the list, allocating the space for Cels is different than creating a new Cel (by calling it's constructor). Since a Cel is never constructed, by default it has no h value