Unity - null reference exception error when creating new array - c#

I have a script that should be generating an array of random animations, whenever the array is set to a new animation array an error is popping up. weapons is a scriptableObject class that contains an empty animation array.
[SerializeField]
AnimationCollections animationCollections;
public WeaponObject[] MakeWeapons()
{
WeaponObject[] weapons = new WeaponObject[2];
for (int i = 0; i < weapons.Length; i++)
{
// this is where unity says the error is
weapons[i].Attacks = new AnimationClip[(Random.Range(2, 5) * 2)];
weapons[i].attackBlends = new float[weapons[i].Attacks.Length / 2];
for (int z = 0; z < weapons[i].Attacks.Length; z++)
{
weapons[i].Attacks[z] = animationCollections.animations[Random.Range(0, animationCollections.animations.Length)];
if (weapons[i].attackBlends.Length < z)
{
weapons[i].attackBlends[z] = Random.Range(0f, 1f);
}
}
}
return weapons;
}
if anyone could help i'd really appriciate it!

You have to initialize the elements of the array, until you do that, they will be null. Therefore invoking their members will throw a NullReferenceException.
You should add e.g
weapons[i] = new WeaponObject();

Related

How to optimize this loop that purges duplicate vertices?

I have this bit of code here
var vertexIndexDictionary = new Dictionary<Vector3, int>();
for (int i = 0; i < triangles.Length; i++)
{
for (int j = 0; j < 3; j++)
{
var vertex = triangles[i][j];
if (!vertexIndexDictionary.ContainsKey(vertex))
{
vertexIndexDictionary.Add(vertex, vertexIndexDictionary.Count);
}
}
}
var vertices = vertexIndexDictionary.Keys.ToArray();
which goes through the triangles array and gets rid of duplicate vertices. This triangle array can get very large, and so the running time gets really long as well. Is there some way I can achieve the same thing but faster? E.g. with another data type?
Edit:
Triangles array is initialized like this:
var triangles = new Triangle[count];
and triangle struct is
struct Triangle {
public Vector3 a;
public Vector3 b;
public Vector3 c;
public Vector3 this[int i]
{
get
{
switch (i)
{
case 0:
return a;
case 1:
return b;
default:
return c;
}
}
}
}
You could get direct access to the entry stored inside the vertexIndexDictionary, with the low-level CollectionsMarshal.GetValueRefOrAddDefault method. Using this API you can reduce the dictionary searching operations from 2-3 to just 1 per iteration. Also you could consider avoiding using the LINQ ToArray method, because LINQ in general is not the tool of choice when performance is of uttermost importance. In this particular case avoiding the ToArray is unlikely to provide any tangible benefit (because the LINQ happens to be internally optimized for sources that implement the ICollection<T> interface), but I'll show you how to do it anyway:
for (int i = 0; i < triangles.Length; i++)
{
for (int j = 0; j < 3; j++)
{
Vector3 vertex = triangles[i][j];
ref int valueRef = ref CollectionsMarshal.GetValueRefOrAddDefault(
vertexIndexDictionary, vertex, out bool exists);
if (!exists) valueRef = vertexIndexDictionary.Count;
indices[i * 3 + j] = valueRef;
}
}
Vector3[] vertices = new Vector3[vertexIndexDictionary.Keys.Count];
vertexIndexDictionary.Keys.CopyTo(vertices, 0);

Parse 2d int array to List of BubbleDataPoints

I have an algorithm which makes use of a grid which is implemented via an int[,] in C#. I would like to graph the output in Blazor using the Bubble chart of blazor chart.Js. Preferably I would like to create separate datasets depending on the value of the int. 0 = empty/ignore, 1 = particular object type, 2 = particular object type.
I'm having an issue with picking out the data and converting it to the BubbleDataPoint(x,y,r) which the chart expects. I would like the x,y to correspond to the array index e.g. graph[1,1] = 1 would be bubbledatapoint(1,1,1) etc. I implemented an IEnumerable method in my class so that I could use foreach or .select on the int values but not sure how to get the array indices out.
public IEnumerable<int> GridValues()
{
for (int x = 0; x < grid.GetLength(0); x++)
{
for (int y = 0; x < grid.GetLength(1); y++)
{
yield return grid[x,y];
}
}
}
Thanks,
Ok, so for anyone interested I went with this method. I initially wanted to avoid looping over the array until I realised that 2D arrays don't implement IEnumerable and I was doing a half-way method but then just decided to go with this.
public IEnumerable<BubbleDataPoint> GridToDataPoints()
{
for (int x = 0; x < grid.GetLength(0); x++)
{
for (int y = 0; y < grid.GetLength(1); y++)
{
yield return new BubbleDataPoint(Convert.ToDouble(x), Convert.ToDouble(y), Convert.ToDouble(grid[x, y]));
}
}
}

Unity 5 2DArray, Object pooling

Im trying to make a object pooling system for my WaveSpawner.
This is what I got (objectPool is a 2D array):
objectPool = new GameObject[wave.Length,0];
//set columns
for(int i = 0;i< objectPool.Length;i++)
{
objectPool = new GameObject[i,wave[i].numberToSpawn]; //set row for ech column
}
for (int p = 0; p < wave.Length; p++)
{
for(int i = 0;i<wave[p].numberToSpawn;i++)
{
GameObject gbj = Instantiate(wave[p].spawnObject);
gbj.transform.position = RandomizePositions();
gbj.SetActive(false);
objectPool[p,i]= gbj; //fill 2D array
}
}
Thats the Error I got;
Array index is out of range.
objectPool = new GameObject[wave.Length,0];
You're creating the array with a size of 0 in the second dimension.
objectPool = new GameObject[wave.Length,0];
Second dimension has size 0
for(int i = 0;i< objectPool.Length;i++)
Length return the size of all dimension, use array.GetLength();
You should read how to use 2d dimension array
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays

How can I run code when the contents of an Array change?

Basically, I am creating a voxel-based game. I have an object Chunk with a 3 dimensional array of the object Voxel. In the array of Voxels, the Voxel currently has an isAir bool on it that signifies no voxel being there.
I am trying to add a property to Chunk which returns a 2 dimensional array of Voxel's that are on the surface of the chunk. Currently, this array will always have Voxel.isAir == false in the lower Y values and Voxel.isAir == true in the higher Y values, there is never a clear run on the "Y" axis of the array that is either all "air"s or all Voxel's, and there is never a "air" below a Voxel in the array.
To get only the "Surface" Voxel's, I have added this code to the Chunk:
public Voxel[,,] Voxels { get; set; }
private Voxel[,] _surfaceVoxels = null;
public Voxel[,] SurfaceVoxels
{
get
{
if (_surfaceVoxels == null)
{
_surfaceVoxels = new Voxel[this.Voxels.GetLength(0), this.Voxels.GetLength(2)];
for (var x = 0; x < this.Voxels.GetLength(0); x++)
{
for (var z = 0; z < this.Voxels.GetLength(2); z++)
{
for (var y = 0; y < this.Voxels.GetLength(1); y++)
{
Voxel v = this.Voxels[x, y, z];
var solidAbove = false;
var solidBelow = false;
if (y - 1 >= 0)
{
Voxel vBelow = this.Voxels[x, y - 1, z];
solidBelow = !vBelow.isAir;
}
if (y + 1 < this.Voxels.GetLength(1))
{
Voxel vAbove = this.Voxels[x, y + 1, z];
solidAbove = !vAbove.isAir;
}
if (!v.isAir && !solidAbove && solidBelow)
{
_surfaceVoxels[x, z] = v;
}
}
}
}
}
return _surfaceVoxels;
}
}
Calculating the surface voxels this way is computationally expensive, and i cannot see a faster way of doing this. Because of this I effectively "cache" the surface array, which is fine until the underlying 3 dimensional array is changed, as then the surface voxels will obviously need to be recalculated.
Is there some way on the get of public Voxel[,,] it only returns a clone of the array and not the array itself, and on the set set the entire array and set _surfaceVoxels to NULL, or even better is there some inexpensive way to execute code when values in an array are changed?
Is there some a more efficient way to accomplish what I have explained here that I have overlooked?

Global array in recursive function issue

So i have a globar array and a recursive function. For example, recursive function performs itself 16 times, and bestOrder=array2D line should be reached only twice. Program actually reach it only twice, but bestOrder changes its value every time array2D is changed (array2D[position] = i;) in this line. BestOrder should contain 2 0 3 1 order, but at the end of the function it contains 3 2 1 0 (last value of the array2D). How can i fix that?
private static int[] bestOrder;
private static void Permutate(int[] array2D, int position, Point[] checkpoints)
{
if (position == array2D.Length)
{
if (GetPathLen(checkpoints, array2D) < min)
{
min = GetPathLen(checkpoints, array2D);
bestOrder= array2D;
}
return;
}
for (int i = 0; i < array2D.Length; i++)
{
bool found = false;
for (int j = 0; j < position; j++)
if (array2D[j] == i)
{
found = true;
break;
}
if (found) continue;
array2D[position] = i;
Permutate(array2D, position + 1, checkpoints);
}
}
Arrays are reference type means they are actually not copied when they are assigned to variables or passed to methods. Instead their references are passed (The pointer that points to same location in memory). One way is Clone and cast to actually copy the array.
bestOrder = (int[])array2D.Clone();
Another way is to create empty array. and fill it by elements of another array.
bestOrder = new int[array2D.Length];
for(int i = 0; i < bestOrder.Length; i++)
{
bestOrder[i] = array2D[i];
}

Categories

Resources