bgList.Add(bg1);
bgList.Add(bg2);
bgList.Add(bg3);
bgList.Add(bg4);
bgList.Add(bg5);
//Initialize all background objects
for (int i = 0; i < bgList.Count; i++)
{
bgList[i] = new Sprite();
bgList[i].Scale = 2.0f;
}
Is this a legitimate way to do this? Basically, the question boils down to "Can I initialize a list of objects using a for loop?
I'm getting "This Object will never not be null" warnings on the bg1, bg2, bg3, bg4, and bg5 objects, and that's making me wonder if this technique isn't allowed.
These statements are not equivalent:
bg1 = new Sprite();
and
bgList.Add(bg1);
bgList[0] = new Sprite();
The latter will not assign the reference to the new instance to bg1. It just stores the new instance in the 0th location.
So using a collection and loop to instantiate a number of variables is not a working short-cut. You have to instantiate each variable explicitly, or use an array or collection from the first place.
a foreach would be easier for sure, and y you should be able to do it, but imo you can also add the items in the loop something like.
for (int i = 0; i < bgList.Count; i++)
{
var bglistitem = new Sprite()
bhlistitem.Scale = 2.0f;
bgList.Add(bglistitem);
}
Related
I have a list of all spawned objects in the game. I'm trying to search through that list to find only objects that are tagged "Road Tag", get their transform position, and convert it to a new variable.
If I use
Debug.Log(spawnedObjects[i].transform.position;
It actually prints out the x, y, z coordinates fine. But I don't know how to assign them to a new Vector3 variable. The syntax for arrays seems to be different.
I have tried:
roadCoordinates[i] = new Vector3(spawnedObjects[i].transform.position.x, spawnedObjects[i].transform.position.y, spawnedObjects[i].transform.position.z);
and
roadCoordinates[i] = spawnedObjects[i].transform.position;
public static Vector3[] roadCoordinates;
public static void FindSpawnedRoads()
{
loopCount = spawnedObjects.Count;
for (int i = 0; i < loopCount; i++)
{
if (spawnedObjects[i].tag == "Road Tag")
{
//This prints perfectly
Debug.Log(spawnedObjects[i].transform.position);
//This gives me NullReferenceException
roadCoordinates[i] = new Vector3(spawnedObjects[i].transform.position.x, spawnedObjects[i].transform.position.y, spawnedObjects[i].transform.position.z);
Debug.Log(roadCoordinates[i]);
}
}
}
I want the variable to be set to the Vector3 coordinates of roadCoordinates[i].
I instead get NullReferenceException. Unless I print SpawnedObjects in which it prints the coordinates like I want.
You have to initialize the roadCoordinates array otherwise you would get the NullReferenceException error. Other than that your logic is okay. You can solve this by adding this line after loopCount assignment:
roadCoordinates = new Vector3[loopCount];
What happens when you do not initialize your array is you create a variable named roadCoordinates but there is no memory allocated or referenced for this variable. Therefore, it does not point to anything in the memory and when you try to use it it says i can't reference to any memory block.
As you mentioned in your question that you have a list of all spawned object you can also store these points in a List then you do not have to allocate any memory, you can just add elements to the list.
List<Vector3> roadCoordinates = new List<Vector3>()
Then you can add elements using roadCoordinates.Add(spawnedObjects[i].transform.position)
If you need to store the indexes of spawned object that has a Road Tag you can use a Dictionary
Dictionary<int, Vector3> roadCoordinates = new Dictionary<int, Vector3>()
Then you can add elements like roadCoordinates.Add(i,spawnedObject[i].transform.position)
You should probably use array.push() (see: https://docs.unity3d.com/ScriptReference/Array.Push.html) instead of writing 'roadCoordinates[i]', as this array is still empty. By using 'push', you add the new position/3D vector to the end of the array, which also works if the array is still empty. I hope this helps you out!
PS: if you first initialize the array to be of a certain length as suggested by the other answer, you will have a lot of empty array items as not every item in your loop is a 'Road tag'.
Yes, as Alexander suggests, using Lists is the way to go. You don't need to use a dictionary as you already know that the roadCoordinates List will only contain items of tag 'Road Tag'.
public static List<Vector3> roadCoordinates = new List<Vector3>();
public static void FindSpawnedRoads()
{
loopCount = spawnedObjects.Count;
for (int i = 0; i < loopCount; i++)
{
if (spawnedObjects[i].tag == "Road Tag")
{
roadCoordinates.Add(new Vector3(spawnedObjects[i].transform.position.x, spawnedObjects[i].transform.position.y, spawnedObjects[i].transform.position.z));
}
}
}
Using Lists is better in this case, because we do not know from the start how many objects we are going to have.
List<Vector3> roadCoordinates = new List<Vector3>();
...
roadCoordinates.Add(new Vector3(...));
Here is the tutorial about lists.
When creating a array of objects of a class and the number of objects in the array is only determined at runtime, how can I initialize each object in the array differently?
For example, SimpleJob is a class. I want to create an array of objects of SimpleJob, and initialize them differently
SimpleJob[] jobs = new SimpleJob[nbJobs];
for (int i = 1; i <= nbJobs; ++i)
{
jobs[i-1] = new SimpleJob(i, false);
}
I call new twice for each object in the array.
Is it a good way, or just wasting the allocated memory? I am relating to my knowledge about new in C++.
You are not calling new twice.
SimpleJob[] jobs = new SimpleJob[nbJobs];
This creates an array of potential references to SimpleJob objects. The array doesn't actually contain any SimpleJob objects yet. And no SimpleJob objects are created anywhere. Each element of the array is a null reference.
Note that in C#, variables of a class type are always references to objects.
Tip: Instead of using arrays, use List<> objects.
List<SimpleJob> jobs = new List<SimpleJob>();
for (int i = 1; i <= nbJobs; ++i)
{
jobs.Add(new SimpleJob(i, false));
}
Then you don't need to know how many entries you are going to have.
here is the code adding data to the list, after which i return the list. Problem is that the last set of data seems to be overwriting everything else in the list
for (int k=0; k < jsonObject["mydetails"].GetArray().Count; k++)
{
//add the corresponding data from the sample array
obj.accountNumber = jsonObject["mydetails"].GetArray()[k].GetObject()["id"].GetString();
obj.accountName = jsonObject["mydetails"].GetArray()[k].GetObject()["name"].GetString();
obj.accountBall = jsonObject["mydetails"].GetArray()[k].GetObject()["age"].GetString();
mylist.Add(obj);
}
Your code isn't adding any new objects to the list, it modifies and adds the same object. In the end, the list contains X references to the same object instance.
In general it is consider bad practice to declare a variable outside the scope in which it is used. You could have avoided this problem by writing:
var myArray=jsonObject["mydetails"].GetArray();
for (int k=0; k < myArray.Count; k++)
{
var myJsonObject=myArray[k].GetObject();
var obj=new MyAccountObject();
obj.accountNumber = myJsonObject["id"].GetString();
...
}
Notice that instead of calling GetArray() and GetObject() in each line (essentially doing the job of extracting the array multiple times) I stored them in separate variables. This will result in far less CPU and memory usage.
You always add the same object obj to the list. You need to create a new in the top of the loop.
for (int k=0; k < jsonObject["mydetails"].GetArray().Count; k++)
{
obj = new ObjectType(); // you know better the type of the object you want to create.
//add the corresponding data from the sample array
obj.accountNumber = jsonObject["mydetails"].GetArray()[k].GetObject()["id"].GetString();
obj.accountName = jsonObject["mydetails"].GetArray()[k].GetObject()["name"].GetString();
obj.accountBall = jsonObject["mydetails"].GetArray()[k].GetObject()["age"].GetString();
mylist.Add(obj);
}
Without the the line obj = new ... you change the properties accountNumber, accountName and accountBall of the same object instance. At the end you add always that object reference to the list. So it seems that the last run of the loop changes all objects.
What I'm trying to do is define my own type that contains 2 ints to use in a 2-dimensional array. The application for this is using the array indexes as x,y coordinates for objects in 2-d space to be displayed. So object with data stored at array[13,5] would be displayed at x=13,y=5, and the properties of that object could be retrieved with array[13,5].property1, for example. The type I've defined is extremely simple:
chunkBlocks.cs:
public class chunkBlocks {
public int blockType;
public int isLoaded;
}
then, I initialize the array:
chunkBlocks[,] _bData = new chunkBlocks[17, 17];
This all compiles/runs without error. The NRE is thrown when I try to assign a value to one of the properties of the type. For debugging, I have the code written as:
_bData[i, n].blockType = 5;
and the NRE is thrown specifically on the .blockType portion. I've tried changing the type to initialize with 0 values for both ints to no avail:
public class chunkBlocks {
public int blockType = 0;
public int isLoaded = 0;
}
I've Googled around and searched SO, and I've not been able to turn up anything. I'm sure it's a relatively simple matter, but I'm not experienced enough to be able to pinpoint it.
Thanks!
You need to initialize every instance of the array:
_bData[i, n] = new chunkBlocks();
Now assign the value to it:
_bData[i, n].blockType = 5;
You will have to initialize every instance, you just have declared them in the array.
I think you should do this:
for(int i = 0;i<17;i++)
{
for (int j = 0; j < 17; j++)
{
_bData[i, j] = new chunkBlocks ();
}
}
Given a class:
class clsPerson { public int x, y; }
Is there some way to create an array of these classes with each element initialized to a (default) constructed instance, without doing it manually in a for loop like:
clsPerson[] objArr = new clsPerson[1000];
for (int i = 0; i < 1000; ++i)
objArr[i] = new clsPerson();
Can I shorten the declaration and instantiation of an array of N objects?
The constructor must be run for every item in the array in this scenario. Whether or not you use a loop, collection initializers or a helper method every element in the array must be visited.
If you're just looking for a handy syntax though you could use the following
public static T[] CreateArray<T>(int count) where T : new() {
var array = new T[count];
for (var i = 0; i < count; i++) {
array[i] = new T();
}
return array;
}
clsPerson[] objArary = CreateArray<clsPerson>(1000);
You must invoke the constructor for each item. There is no way to allocate an array and invoke your class constructors on the items without constructing each item.
You could shorten it (a tiny bit) from a loop using:
clsPerson[] objArr = Enumerable.Range(0, 1000).Select(i => new clsPerson()).ToArray();
Personally, I'd still allocate the array and loop through it (and/or move it into a helper routine), though, as it's very clear and still fairly simple:
clsPerson[] objArr = new clsPerson[1000];
for (int i=0;i<1000;++i)
clsPerson[i] = new clsPerson();
If it would make sense to do so, you could change class clsPerson to struct Person. structs always have a default value.