Unity: Index was outside the bounds of the Array - c#

im developing with Unity for about a year now and very often I got this Error:
IndexOutOfRangeException: Index was outside the bounds of the array.
I know that that error means that the given index is bigger then the array itself. But I dont think that the Array is bigger than the used value.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProceduralGeneration : MonoBehaviour
{
public GameObject[,] tiles = new GameObject[3000, 3000];
public GameObject[] prefabs;
int sizeyet = 0;
GameObject obj;
public int renderdistance;
int[,] map;
// Start is called before the first frame update
void Start()
{
map = CreateMap(map);
for (int i = 0; i < map.Length; i++)
{
for (int j = 0; j < map.Length; j++)
{
obj = Instantiate(prefabs[map[i,j]], new Vector2(i, j), Quaternion.identity);
tiles[i, j] = obj;
}
}
}
public int[,] CreateMap(int[,] map)
{
map = new int[4000, 4000];
for(int i = 0; i < 3000 - 1; i++)
{
for(int j = 0; i < 3000 - 1; j++)
{
map[i, j] = Mathf.RoundToInt(Mathf.PerlinNoise(i, j) * 10);
}
}
return map;
}
// Update is called once per frame
void Update()
{
}
}
I very often canceled project because I couldn't fix this error.
If my English is not so good, excuse me. Im a german student.

There are a few problems here. Firstly, there's a typo in CreateMap:
for(int j = 0; i < 3000 - 1; j++)
Note how you're using i in the condition instead of j - so that loop will never terminate, assuming that i is less than 2999 to start with. But even changing that won't fix the bigger problem. Let's look at the rest of the code.
Here's how you initialize map:
map = new int[4000, 4000];
And here's how you initialize tiles:
public GameObject[,] tiles = new GameObject[3000, 3000];
So map.Length is 16000000, because that's the total size of the array.
Now let's look at your loop:
for (int i = 0; i < map.Length; i++)
{
for (int j = 0; j < map.Length; j++)
{
obj = /* irrelevant */
tiles[i, j] = obj;
}
}
So your code is a bit like this:
GameObject[,] tiles = new GameObject[3000, 3000];
for (int i = 0; i < 16000000; i++)
{
for (int j = 0; j < 16000000; j++)
{
tiles[i, j] = something;
}
}
Can you see how that's clearly going to go way out of bounds?
Even if the code behaved as you expected it to, tiles is 3000x3000 and map is 4000x4000, so that would be a problem.
I suggest you create some constants, and use those everywhere:
private const int MapWidth = 4000;
private const int MapHeight = 4000;
public GameObject[,] tiles = new GameObject[MapWidth, MapHeight];
...
// Then later...
for (int i = 0; i < MapWidth; i++)
{
for (int j = 0; j < MapHeight; j++)
{
tiles[i, j] = ...;
}
}
// And in CreateMap:
map = new int[MapWidth, MapHeight];
for (int i = 0; i < MapWidth; i++)
{
for (int j = 0; j < MapHeight; j++)
{
map[i, j] = Mathf.RoundToInt(Mathf.PerlinNoise(i, j) * 10);
}
}

Related

NullReferenceException in child class when referring to member of parent [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
Pretty much the title. I first set it in the first method and as soon as I wanna call it up it says it´s empty. Even in the Inspector it says that it´s set to the right thing but it can´t be called for some reason.
The two relevant code snippets:
public class WUZ_Unit : Leader
{
public override void UpdatePosition()
{
vecPos = GameObject.Find("WUZ(Clone)").transform.position;
Debug.Log(this + " the grid: " + grid);
**position = grid.GetNode((int)vecPos.x, (int)vecPos.y);**
}
}
and:
public abstract class Entity : MonoBehaviour {
public void InitiateGrid(Gridmanager g)
{
anim = GetComponent<Animator>();
if (anim.gameObject.activeSelf)
{
anim.SetBool("IsAlive", true);
}
grid = g;
Debug.Log(this + " set " + grid);
}
}
what the console spits out on the first Debug Log:
and what the console spits out on the second Debug Log:
This is the Error Code in Text:
NullReferenceException: Object reference not set to an instance of an object
WUZ_Unit.UpdatePosition () (at Assets/Scripts/Unit/WUZ_Unit.cs:21)
GameHandler.UpdateAllMoves () (at Assets/Scripts/GameHandler.cs:1805)
GameHandler.Start () (at Assets/Scripts/GameHandler.cs:1697)
The asked for code regarding instantiation:
public void GenerateCharacters(int x, int y, GameObject c, int i)
{
GameObject go = Instantiate(c) as GameObject;
//Entity e = go.GetComponent<Entity>();
//StartCoroutine(e.SpawnAnim());
if (i == 0)
{
Unit u = go.GetComponent<Unit>();
go.GetComponent<Enemy>().enabled = false;
u.enabled = true;
u.InitializeUnits();
u.healthBarEnemy = healthBarEnemy;
u.healthBarAlly = healthBarAlly;
u.healthMeter = healthbarMeter;
u.highlightAttack = highlightAttack;
u.highlightIndicator = highlightIndicator;
u.highlightMove = highlightMove;
u.InitiateGrid(grid);
u.SetPos(x, y);
GeneratePosition(u, x, y);
u.PlayerChange(gamePhase);
go.GetComponent<Enemy>().enabled = false;
}
This is the asked for code regarding updateposition:
public void UpdateAllMoves()
{
Debug.Log("updating all moves");
//Updating the grid status
grid.UpdatePosition();
Unit[] ul = unitList.ToArray();
for (int i = 0; i < ul.Length; i++)
{
ul[i].UpdatePosition();
}
Enemy[] el = enemyList.ToArray();
for (int i = 0; i < el.Length; i++)
{
el[i].UpdatePosition();
}
CheckforCheckUnit(grid);
CheckforCheckEnemy(grid);
ConvertAllMoves();
grid.ClearNodeMoves();
grid.UpdatePosition();
UpdateNodes();
grid.UpdatePosition();
for (int i = 0; i < ul.Length; i++)
{
**ul[i].UpdatePosition();**
}
for (int i = 0; i < el.Length; i++)
{
el[i].UpdatePosition();
}
CheckforCheckUnit(grid);
CheckforCheckEnemy(grid);
ConvertAllMoves();
grid.ClearNodeMoves();
grid.UpdatePosition();
UpdateNodes();
}
so I made sure that vecPos is not the problem:
Debug.Log(this + " the grid: " + grid + " the vecPos " + vecPos.x + " " + vecPos.y);
What the console spits out:
WUZ (WUZ_Unit) the grid: the vecPos 2 28
UnityEngine.Debug:Log(Object)
WUZ_Unit:UpdatePosition() (at Assets/Scripts/Unit/WUZ_Unit.cs:20)
GameHandler:UpdateAllMoves() (at Assets/Scripts/GameHandler.cs:1805)
GameHandler:Start() (at Assets/Scripts/GameHandler.cs:1697)
more clarification code:
public void GettingCharacters()
{
Debug.Log(StaticPara.player1Units.Length);
for(int i = 0; StaticPara.player1Units.Length > i; i++)
{
unitList.Add(StaticPara.player1Units[i].GetComponent<Unit>());
int x = startingTilesBlue[i].xPos;
int y = startingTilesBlue[i].yPos;
GenerateCharacters(x, y, StaticPara.player1Units[i], 0);
}
for (int i = 0; StaticPara.player2Units.Length > i; i++)
{
enemyList.Add(StaticPara.player2Units[i].GetComponent<Enemy>());
int x = startingTilesRed[i].xPos;
int y = startingTilesRed[i].yPos;
GenerateCharacters(x, y, StaticPara.player2Units[i], 1);
}
}
void Start()
{
grid = gridGO.GetComponent<Gridmanager>();
grid.CreateGrid();
//setting up ui and the game
gamePhase = 0;
phaseStatusString = "Move Phase";
endPhaseButton.GetComponent<Button>().interactable = false;
ability_ALX = true;
//spawning character Models
GenerateStartingPositions();
GettingCharacters();
//Updating their stats
Unit[] ul = unitList.ToArray();
for (int i = 0; i < ul.Length; i++)
{
ul[i].healthMax = ul[i].healthBase;
ul[i].healthCurrent = ul[i].healthMax;
ul[i].damageCurrent = ul[i].damageBase;
}
Enemy[] el = enemyList.ToArray();
for (int i = 0; i < el.Length; i++)
{
el[i].healthMax = el[i].healthBase;
el[i].healthCurrent = el[i].healthMax;
el[i].damageCurrent = el[i].damageBase;
}
SelectKing();
**UpdateAllMoves();**
}
Here is the Update Nodes Function:
public void UpdateNodes()
{
for(int i = 0; i < unitList.Count; i++)
{
for(int j = 0; j < unitList[i].possibleMoves.Length; j++)
{
for(int k = 0; k < unitList[i].possibleMoves[j].Count; k++)
{
unitList[i].possibleMoves[j][k].moveableByUnit.Add(new CheckAssist(unitList[i], j));
}
}
for (int j = 0; j < unitList[i].possibleAttacks.Length; j++)
{
for (int k = 0; k < unitList[i].possibleAttacks[j].Count; k++)
{
unitList[i].possibleAttacks[j][k].attackableByUnit.Add(new CheckAssist(unitList[i], j));
}
}
for (int j = 0; j < unitList[i].possibleAttackIndicators.Length; j++)
{
for (int k = 0; k < unitList[i].possibleAttackIndicators[j].Count; k++)
{
unitList[i].possibleAttackIndicators[j][k].attackableByUnit.Add(new CheckAssist(unitList[i], j));
}
}
for (int j = 0; j < unitList[i].possibleAttacksInactive.Length; j++)
{
for (int k = 0; k < unitList[i].possibleAttacksInactive[j].Count; k++)
{
unitList[i].possibleAttacksInactive[j][k].passiveAAByUnit.Add(new CheckAssist(unitList[i], j));
}
}
}
for (int i = 0; i < enemyList.Count; i++)
{
for (int j = 0; j < enemyList[i].possibleMoves.Length; j++)
{
for (int k = 0; k < enemyList[i].possibleMoves[j].Count; k++)
{
enemyList[i].possibleMoves[j][k].moveableByEnemy.Add(new CheckAssist(enemyList[i], j));
}
}
for (int j = 0; j < enemyList[i].possibleAttacks.Length; j++)
{
for (int k = 0; k < enemyList[i].possibleAttacks[j].Count; k++)
{
enemyList[i].possibleAttacks[j][k].attackableByEnemy.Add(new CheckAssist(enemyList[i], j));
//Debug.Log("added attack to" + enemyList[i].possibleAttackIndicators[j][k].xPos + " " + enemyList[i].possibleAttackIndicators[j][k].yPos);
}
}
for (int j = 0; j < enemyList[i].possibleAttackIndicators.Length; j++)
{
for (int k = 0; k < enemyList[i].possibleAttackIndicators[j].Count; k++)
{
enemyList[i].possibleAttackIndicators[j][k].attackableByEnemy.Add(new CheckAssist(enemyList[i], j));
//Debug.Log("added attack to" + enemyList[i].possibleAttackIndicators[j][k].xPos + " " + enemyList[i].possibleAttackIndicators[j][k].yPos);
}
}
for (int j = 0; j < enemyList[i].possibleAttacksInactive.Length; j++)
{
for (int k = 0; k < enemyList[i].possibleAttacksInactive[j].Count; k++)
{
enemyList[i].possibleAttacksInactive[j][k].passiveAAByEnemy.Add(new CheckAssist(unitList[i], j));
}
}
}
}
The problem seems to be that some line among these:
CheckforCheckUnit(grid);
CheckforCheckEnemy(grid);
ConvertAllMoves();
grid.ClearNodeMoves();
grid.UpdatePosition();
UpdateNodes();
grid.UpdatePosition();
is modifying the Units in unitList in some way that sets the Unit.grid value to null.
Something else you might consider is adding GridManager as a parameter to UpdatePosition():
public override void UpdatePosition(GridManager gameGrid) {
vecPos = GameObject.Find("WUZ(Clone)").transform.position;
Debug.Log(this + " the grid: " + gameGrid);
position = gameGrid.GetNode((int)vecPos.x, (int)vecPos.y);
}
and then in UpdateAllMoves, include it in the calls. e.g.:
...
el[i].UpdatePosition(grid);
...
ul[i].UpdatePosition(grid);
...
I fixed my own Code and here is how:
unitList.Add(StaticPara.player1Units[i].GetComponent<Unit>());
int x = startingTilesBlue[i].xPos;
int y = startingTilesBlue[i].yPos;
GenerateCharacters(x, y, StaticPara.player1Units[i], 0);
I added the Unit script from the passed the GameObject rather than the Unit script from the instantiated Gameobject meaning I changed variables that were not even in the List
Thanks for all the help #ruzihm
EDIT: Yes I did I moved unitList.Add from GettingCharacters() to GenerateCharacters()

filling 2d array compiler telling me i'm referencing an object that doesn't exist

I can't figure out why it's telling me the object is null when I'm trying to fill the array with an object that I'm constructing.
public int size;
// Use this for initialization
public void Start()
{
size = 10;
Unit[,] array = new Unit[size,size];
int i, j;
for(i = 1; i<=size; i++)
{
for(j=0;j<size;j++)
{
if(i>=1&&j>=1)
{
array[i, j] = new Unit(array[i - 1, j].getHeight(), array[i, j - 1].getHeight());
}
else if(i>=1)
{
array[i, j] = new Unit(array[i - 1, j].getHeight(), 0);
}
else
{
array[i, j] = new Unit(0, 0);
}
}
}
for (i = 0; i <= size; i++)
{
for (j = 0; j <= size; j++)
{
Debug.Log(array[i,j].getHeight());
}
}
}
the Objects I am creating come from a constructor; Unit(int,int)
It says line 23. I'm assuming that it means that the object doesn't exist in the the array but i'm creating the object so IDK
Two erros that I see, the first is that the first for loop should be for(i = 0; i<size; i++) as c# is base 0. This would give you the null object because when you try to assign
if(i>=1&&j>=1)
{
array[i, j] = new Unit(array[i - 1, j].getHeight(), array[i, j - 1].getHeight());
}
when i=1, array[0,j] was never assign (since i started in 1), so it's value is null.
The other is in the last group of loops, as the conditions should be the following:
for (i = 0; i < size; i++)
{
for (j = 0; j < size; j++)
{
Debug.Log(array[i,j].getHeight());
}
}
Because since C# is base 0, the indexes goes from 0 to size-1

How to multiply a matrix in C#?

I cannot get this method to work. It intends to multiply a matrix by a given one. Could someone help me to correct it please?
class Matriz
{
public double[,] structure;
//Other class methods
public void multiplyBy(Matrix m)
{
if (this.structure.GetLength(1) == m.structure.GetLength(0))
{
Matriz resultant = new Matriz(this.structure.GetLength(0), m.structure.GetLength(1));
for (int i = 0; i < this.structure.GetLength(0) - 1; i++)
{
for (int j = 0; j < m.structure.GetLength(1) - 1; j++)
{
resultant.structure[i, j] = 0;
for (int z = 0; z < this.structure.GetLength(1) - 1; z++)
{
resultant.structure[i, j] += this.structure[i, z] * m.structure[z, j];
}
}
}
this.structure= resultant.structure;
}
else
{
Console.WriteLine("Selected matrixs cannot be multiply");
}
}
}
Read this MSDN Magazine article by James McCaffrey and use the code below as an extension method. They use a jagged array which is more convenient and sometimes faster than a 2D array. Change any data[i][j] to data[i,j] to make the code work with a 2D array.
public static double[] MatrixProduct(this double[][] matrixA,
double[] vectorB)
{
int aRows=matrixA.Length; int aCols=matrixA[0].Length;
int bRows=vectorB.Length;
if (aCols!=bRows)
throw new Exception("Non-conformable matrices in MatrixProduct");
double[] result=new double[aRows];
for (int i=0; i<aRows; ++i) // each row of A
for (int k=0; k<aCols; ++k)
result[i]+=matrixA[i][k]*vectorB[k];
return result;
}
public static double[][] MatrixProduct(this double[][] matrixA,
double[][] matrixB)
{
int aRows=matrixA.Length; int aCols=matrixA[0].Length;
int bRows=matrixB.Length; int bCols=matrixB[0].Length;
if (aCols!=bRows)
throw new Exception("Non-conformable matrices in MatrixProduct");
double[][] result=MatrixCreate(aRows, bCols);
for (int i=0; i<aRows; ++i) // each row of A
for (int j=0; j<bCols; ++j) // each col of B
for (int k=0; k<aCols; ++k)
result[i][j]+=matrixA[i][k]*matrixB[k][j];
return result;
}
public static double[][] MatrixCreate(int rows, int cols)
{
// creates a matrix initialized to all 0.0s
// do error checking here?
double[][] result=new double[rows][];
for (int i=0; i<rows; ++i)
result[i]=new double[cols];
// auto init to 0.0
return result;
}
This is the modified version of my method, as far as I've been testing this approach works fine.
public void multiplicarPor(Matriz m)
{
if (this.estructura.GetLength(1) == m.estructura.GetLength(0))
{
Matriz resultante = new Matriz(this.estructura.GetLength(0), m.estructura.GetLength(1));
for (int i = 0; i < this.estructura.GetLength(0); i++)
{
for (int j = 0; j < m.estructura.GetLength(1); j++)
{
resultante.estructura[i, j] = 0;
for (int z = 0; z < this.estructura.GetLength(1); z++)
{
resultante.estructura[i, j] += this.estructura[i, z] * m.estructura[z, j];
}
}
}
this.estructura = resultante.estructura;
}
else
{
Console.WriteLine("No se pueden multiplicar estas matrices");
}
}

Method for Sorting 2D Matricies, How can i make the method generic?

public static void Sort2DArray(int[,] matrix)
{
var numb = new int[matrix.GetLength(0) * matrix.GetLength(1)];
int i = 0;
foreach (var n in matrix)
{
numb[i] = n;
i++;
}
Array.Sort(numb);
int k = 0;
for (i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = numb[k];
k++;
}
}
}
I'm curious how can I make this method generic. I wish that it could sort double matrices, string matrices and so on and so forth.
You can use IComparable interface as a generic type T specifier.
See those links
How to Sort 2D Array in C#
How do I sort a two-dimensional array in C#?
http://www.informit.com/guides/content.aspx?g=dotnet&seqNum=151
I have solved it. the method looks like this:
public static void Sort2DArray<T>(T[,] matrix)
{
var numb = new T[matrix.GetLength(0) * matrix.GetLength(1)];
int i = 0;
foreach (var n in matrix)
{
numb[i] = n;
i++;
}
Array.Sort(numb);
int k = 0;
for (i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = numb[k];
k++;
}
}
}

Cannot redraw points which have been set to NULL

I have the following setup:
A TeeChart control with a Colorgrid, and a Points Series added to it:
grid = tChart2.Series[0] as Steema.TeeChart.Styles.ColorGrid;
points = tChart2.Series[1] as Steema.TeeChart.Styles.Points;
To init them, I do:
Random rnd = new Random();
for (int i = 0; i < 128; i++)
{
for (int j = 0; j < 128; j++)
{
grid.Add(j, rnd.Next(255), i);
}
}
for (int i = 0; i < 20; i++)
{
double x = rnd.Next();
double y = rnd.Next();
points.Add(x, y);
}
tChart2.Refresh();
And then I have a button on my form:
private void button1_Click(object sender, EventArgs e)
{
Random rnd = new Random();
for (int i = 0; i < 128; i++)
{
for (int j = 0; j < 128; j++)
{
grid.YValues[j + 128 * i] = rnd.Next(255);
}
}
for (int i = 0; i < 20; i++)
{
points.SetNull(i);
}
for (int i = 0; i < rnd.Next(20); i++)
{
points.XValues[i] = rnd.Next(128);
points.YValues[i] = rnd.Next(128);
}
points.BeginUpdate();
points.EndUpdate();
}
But the points do not get drawn. When I remove the for-loop containing the SetNull() statement, then they do get drawn, but I want to be able to clear the points (or hide the points don't want to be seen) without using the Points.Clear()/Points.Add(x, y) methodology.
I've also tried each of the following, but there's no difference.
points.TreatNulls = Steema.TeeChart.Styles.TreatNullsStyle.DoNotPaint;
points.TreatNulls = Steema.TeeChart.Styles.TreatNullsStyle.Ignore;
points.TreatNulls = Steema.TeeChart.Styles.TreatNullsStyle.Skip;
Does anyone know how to accomplish this?
Ok, the problem is caused when you set null all of points. You must know if you use method SetNull the point color is set transparent to make invisible the point. Therefore, if you want solve your problem you only need reset the colors of points you want visible, doing SetNull again or change the points color manually and combining the operation with TreatNullsStyle set to Ignore. In my opinion, I think the best option is use SetNull again as I do in next code:
public Form1()
{
InitializeComponent();
InitializeChart();
}
Steema.TeeChart.Styles.ColorGrid grid;
Steema.TeeChart.Styles.Points points;
private void InitializeChart()
{
grid = new ColorGrid(tChart1.Chart);
points = new Points(tChart1.Chart);
tChart1.Aspect.View3D = false;
Random rnd = new Random();
for (int i = 0; i < 128; i++)
{
for (int j = 0; j < 128; j++)
{
grid.Add(i, rnd.Next(255), j);
}
}
for (int i = 0; i < 20; i++)
{
double x = rnd.Next(100);
double y = rnd.Next(100);
points.Add(x, y);
}
}
private void button1_Click(object sender, EventArgs e)
{
Random rnd = new Random();
for (int i = 0; i < 128; i++)
{
for (int j = 0; j < 128; j++)
{
grid.YValues[j + 128 * i] = rnd.Next(255);
}
}
for (int i = 0; i < 20; i++)
{
points.SetNull(i);
}
for (int i = 0; i < rnd.Next(20); i++)
{
points.XValues[i] = rnd.Next(128);
points.YValues[i] = rnd.Next(128);
points.SetNull(i, false);
}
points.TreatNulls = TreatNullsStyle.Ignore;
}
Could you tell us if previous code works in correct way for you?
I hope will helps.
Thanks,

Categories