- Home /
Adding Instantiated Objects to ArrayList but it returns null C#
Hello, I have an obstacles manager that keeps track of all obstacles in the scene, instantiating them and then supposed to destroy them. In order to do this I wanted to keep references to the Instantiated objects in an ArrayList (or List but I'm having the same issue in both).
When I add the Instantiated object to the ArrayList the index count goes up but when I try to access the index it returns null. I can see the objects in the scene so I don't understand the problem.
Here is my code, I commented out one section but thats another route I was taking to see if it would solve the issue. Any help would be great.
public int maxObstacles, minObstacles;
public float minCreateTime, maxCreateTime;//Randomize time to create objects between these 2 values
private float createTime, currentTime; //Random amount of time between the creation of obstacles
private Vector3 obstacleBounds;//The position for which to remove the obstacle from the scene list
public Transform cameraTransform;
public GameObject[] obstacleTypes;
private Transform tempObstacle;
private ArrayList obstaclesInSceneList;//Obstacles currently in the scene
// Use this for initialization
void Start ()
{
obstaclesInSceneList = new ArrayList();
createTime = Random.Range(minCreateTime, maxCreateTime);
currentTime = 0;
}
// Update is called once per frame
void Update ()
{
if(obstaclesInSceneList.Count <= minObstacles && obstaclesInSceneList.Count <= maxObstacles)
{
if(currentTime >= createTime)
{
createTime = Random.Range(minCreateTime, maxCreateTime);
currentTime = 0;
tempObstacle = Instantiate(obstacleTypes[Random.Range(0, obstacleTypes.GetLength(0) - 1)],
new Vector3(Random.Range(-(Screen.width /2), (Screen.width /2)),cameraTransform.position.y - Screen.height, 0),
transform.rotation) as Transform;
Debug.Log("Temp is null" + tempObstacle == null);
obstaclesInSceneList.Add(tempObstacle);
/*obstaclesInSceneList.Add(Instantiate(obstacleTypes[Random.Range(0, obstacleTypes.GetLength(0) - 1)],
new Vector3(Random.Range(-(Screen.width /2), (Screen.width /2)),cameraTransform.position.y - Screen.height, 0),
transform.rotation) as Transform);*/
}
}
//Check to see if any of the obstacles are off screen above the camera
obstacleBounds = new Vector3(0, cameraTransform.position.y + Screen.height, 0);
Debug.Log(obstaclesInSceneList.Count);
try
{
for(int i = 0; i < obstaclesInSceneList.Count; i++)
{
if(obstaclesInSceneList[i].position.y > obstacleBounds.y)
{
obstaclesInSceneList.Remove(obstaclesInSceneList[i]);
}
}
}
catch
{
Debug.Log("Something is null");
}
currentTime +=1;
}
Answer by Bunny83 · Jun 28, 2012 at 03:06 AM
You stepped into the as-cast trap....
You declared your obstacleTypes array as GameObject array. That's not a problem, but when you instantiate you try to cast the instantiated object to Transform which of course fails since a GameObject isn't a Transform. Because you used the as-cast you don't get any casting error. The cast just returns null.
Btw. Why do you use an ArrayList? It's slow and requires casting since it's not strongly typed. Use a generic List<>
instead. First you should decide if you want to store GameObject references or Transform references and adjust your obstacleTypes array and the cast.
The generic List requires the System.Collections.Generic
namespace.
I was using that earlier but I read that iOS does not support the List(). I would like this clarified since I would like to keep all of this cleaner. Currently I do have the items going into the List correctly without being null, now I have the problem of them not being destroyed. I show the code I used below.
Again the same mistake. You store Transforms in the array. A Transform can't be an Obstacle. It seems you are a bit confused about your types. If all of your prefabs have an Obstacle script attached, you might want to use this type ins$$anonymous$$d of Transform or GameObject. You can also instantiate the prefab if you provide a reference to any of the attached components.
So you should:
change obstacleTypes to
public Obstacle[] obstacleTypes;
You have to re-assign your prefabs when you change the type of the array. You can of course only assign prefabs that have such a script attached.
Your
tempObstacle
also has to be an Obstacle now and your cast should of course cast to that type.Furthermore tempObstacle should be a local variable and not a member variable.
When you destroy them, you don't need to test the reference if it's an Obstacle since all references are Obstacle or null, so testing for null would make sense. If it's null you can of course remove it from the list.
Next thing is, when you call Destroy with a reference to an Obstacle component, you will just destroy the component, not the whole gameobject it is attached to. If you want to destroy the whole GameObject, you have to use:
Destroy(obstaclesInSceneList[j].gameObject);
. This of course only works with a strongly typed List which is now supported on all platforms afaik.
AH the last thing you said worked! I didn't put up all of my code but I did all of that before hand but was they still weren't deleting. The Destroy(obstaclesInSceneList[j].gameObject); works though! Thank you :D
Answer by DaveA · Jun 27, 2012 at 06:50 AM
Problem in removing? 'Remove' will change the Count, so the indexes will be off. Use 'foreach' instead of 'for'
Well it's even before that. Right after I instantiate and add to the ArrayList I could do something like I did with Debug.Log("Temp is null" + tempObstacle == null); and it would return true stating that index is null.
If Instantiate returns null, then something went wrong there. Did you assign GameObjects to all the entries in obstacleTypes, like with the Inspector?
So I now have it actually assigning the indexes but now I can't destroy the object in the scene. I even tried a test where it would change the position of the obstacle to where the camera is so I know it is accessing the object. Here's what I'm now doing in the destroy area
obstacleBounds = new Vector3(0, cameraTransform.position.y + Screen.height, 0);
try
{
foreach(Obstacle obs in obstaclesInSceneList)
{
if(obs.transform.position.y > obstacleBounds.y)
{
obs.isActive = false;
//Test code
//obs.transform.position = cameraTransform.position
//Destroy (obs); //Creates an error since it can't
//access the next object in the arraylist
}
}
for(int j = 0; j < obstaclesInSceneList.Count; j++)
{
if(obstaclesInSceneList[j] is Obstacle)
{
Obstacle tempObstacle = (Obstacle)obstaclesInSceneList[j];
if(!tempObstacle.isActive)
{
Destroy((Obstacle)obstaclesInSceneList[j]);
obstaclesInSceneList.RemoveAt(j);
Debug.Log ("Removed: " + j);
Destroy (tempObstacle);
Debug.Log("Destroyed: " + j);
}
}
}
}
catch($$anonymous$$issingReferenceException e)
{
Debug.Log(e.ToString());
}
I don't understand why it won't destroy the obstacle
btw, foreach doesn't work either. The enumerator of the ArrayList or List class will check the version of the List which is incremented if you change anything, even when you assign a value to an existing element. Generally there are two ways to iterate through a list when you want to remove elements:
Use a while loop and increment the count variable only when you didn't remove an element this iteration.
Count backwards. That's the easiest way, but you have to be careful with the bounds.
for(int j = obstaclesInSceneList.Count-1; j >= 0; j--) {
I'm trying the backwards for loop but still nothing. Here's the current code for it.
obstacleBounds = new Vector3(0, cameraTransform.position.y + Screen.height, 0);
try
{
for(int j = obstaclesInSceneList.Count-1; j >= 0; j--)
{
if(obstaclesInSceneList[j] is Obstacle)
{
if(((Obstacle)obstaclesInSceneList[j]).transform.position.y > obstacleBounds.y)
{
Destroy((Obstacle)obstaclesInSceneList[j]);
obstaclesInSceneList.RemoveAt(j);
continue;
}
}
}
}
catch($$anonymous$$issingReferenceException e)
{
Debug.Log(e.ToString());
}
Answer by ramp · Jan 08, 2013 at 12:37 PM
1.create ArrayList for numbers of obstacles that's you want instantiate . 2.Use a Switch case for different position .
var obstacles : GameObject[];
private var delta_time : int;
private var stopTime : float = 0;
private var scene_load_time : float = 0.0; private var loop_counter : int = 0;
private var caseCalled : int = 0;
var pos1 : Vector3; var pos2 : Vector3; var pos3 : Vector3; var pos4 : Vector3;
function Start () { CaseCalled(); }
function Update () { if(stopTime > delta_time) { var temp_time : int = scene_load_time/30; if(temp_time == loop_counter) { loop_counter += 1; if(loop_counter > 6) { loop_counter = 6; } }
for(var i =0; i< loop_counter ; i++)
{
CaseCalled();
}
stopTime = 0;
}
stopTime += Time.deltaTime;
scene_load_time += Time.deltaTime;
}
pos1 = Vector3(Random.Range(-500,500),400,0);
pos2 = Vector3(-500,Random.Range(-360,400),0);
pos3 = Vector3(Random.Range(-500,500),-360,0);
pos4 = Vector3(500,Random.Range(-360,400),0);
switch(caseCalled)
{
case 0 :
Instantiate(obstacles[Random.Range(0,7)],pos4,Quaternion.EulerAngles(-89.5,0,0));
break;
case 1 :
Instantiate(obstacles[Random.Range(0,7)],pos1,Quaternion.EulerAngles(-89.5,0,0));
break;
case 2 :
Instantiate(obstacles[Random.Range(0,7)],pos2,Quaternion.EulerAngles(-89.5,0,0));
break;
case 3 :
Instantiate(obstacles[Random.Range(0,7)],pos3,Quaternion.EulerAngles(-89.5,0,0));
break;
default :
Instantiate(obstacles[Random.Range(0,7)],pos3,Quaternion.EulerAngles(-89.5,0,0));
}
}