Cannot cast Source from Type
Hey guys I've just run into an error I havn't encountered before, I've been dabbling in Unity-c# for a little while so hopefully getting stuck on this isn't too noobie.
What I'm trying to do is fill my 'public static Tile_Levels[] tilesAll;' with all children Tile_Levels that are children to the transform this script is attached to. The error is occurring on the foreach loop between Tile_Levels in transform.
void ProcessTiles(){
tilesAll = new Tile_Levels[numberOfTiles];
int TileNo = 0;
foreach (Tile_Levels childtile in transform)
{
tilesAll[TileNo] = childtile;
TileNo ++;
}
AssignMines ();
}
Thankyou for your time, if I havn't given enough information just ask for what you want!
Answer by Glurth · Nov 06, 2015 at 05:40 PM
It looks like you are trying to iterate (foreach) through the transform itself, which is NOT an array, list or other collection. That being said, it does CONTAIN a collection of children, an important distinction (IS vs HAS).
perhaps something like this is what you are looking for?...
...
Tile_Levels[] tileLevelChildrenArray=transform.GetComponentsInChildren< Tile_Levels >();
foreach(Tile_Levels childtile in tileLevelChildrenArray)
...
The GetComponentsInChildren will find all children that contain a component of type "Tile_Levels". (I'm making the assumption this class is a MonoBehavior, a.k.a. "a component".) The results will put into an array, which you CAN iterate through.
Edit: looking at your code a bit more, you may not even WANT a foreach loop after calling GetComponentsInChildren, since it looks like THAT is why you were looping... not sure though.
Thank you, that did solve my problem, as you can probably see I don't use foreach loop every much. I'm sorry to ask you further for help but I'm now getting an error from the actual loop part from my foreach and I don't know how to fix it. I'm getting error Array index is out of range because of tileNo, I've tried changing it to other things and using the arrays.length but still isn't working, If you dont want to/cant solve this then I'll accept your answer anyway, thank you!
" I'm getting error Array index is out of range because of tileNo"
I'm not quite sure WHY you are using a loop in this situation, but I'll be happy to explain the error. The "index" it is reffering to is the number you are putting inside the brackets. "out of range" means than the index you are feeding it is TOO LARGE for the actuall array. dont forget, you specified exactly how large the array was when you created it, in this line:
tilesAll = new Tile_Levels[numberOfTiles];
so, if you try to "index" the array with a number that is equal to or larger than "numberOfTiles", it will spit out an "out of range" error.
The next logical question is obviously: How do I know how large to make the array? that depends on how you are going to use it, but in this situation, you I think you want to use the size of the array you are going to iterate through with the foreach:
....
Tile_Levels[] tileLevelChildrenArray=transform.GetComponentsInChildren< Tile_Levels >();
numberOfTiles = tileLevelChildrenArray.Length; //use the Length member. all arrays have this.
tilesAll = new Tile_Levels[numberOfTiles];
....
also, FYI: if you prefer for(;;) to foreach(), this is "pretty much"(but NOT exactly) equivalent for a full array iteration
int max= array.Length;
for(int i=0;i<max;i++)
{
currentElement = array[i];
....
}
and
foreach(ElementType currentElement in array)
{
....
}
Okay, thank you so much for your help again, I really appreciate it, I'm learning... slowly. I just have one more issue... sorry. Logically, in my $$anonymous$$d everything should be working however when I try call the stored Tile_Levels element in the array from a child of the object, I get Null returned. The children of $$anonymous$$anager_Levels all have Tile_Levels attached as I'm sure you can tell, but when the children call "print ($$anonymous$$anager_Levels.tilesAll[1]);" in start() I get null return. I think this may be because the start() function on Tiles_Levels finishes it's call before $$anonymous$$anager_Levels assigns the elements to the array but i have no idea how to go about fixing that. I'm sorry if this is really messy and for being so clueless, I really am trying to learn. Thank you again, very much. Here's my script for $$anonymous$$anager_Levels incase it helps.
public class $$anonymous$$anager_Levels : $$anonymous$$onoBehaviour {
public static Tile_Levels[] tilesAll;
void Start () {
ProcessTiles ();
}
void ProcessTiles(){
numberOfTiles = transform.childCount;
tilesAll = new Tile_Levels[numberOfTiles];
Tile_Levels[] tileLevelChildrenArray = transform.GetComponentsInChildren< Tile_Levels >();
for (int tilesProcessed = 0; tilesProcessed < numberOfTiles; tilesProcessed++) {
Tile_Levels processingtile = tileLevelChildrenArray[tilesProcessed];
processingtile.ID = tilesProcessed;
tilesAll[tilesProcessed] = processingtile;
}
Assign$$anonymous$$ines ();
}
Hmm, afraid I'm not really clear on the new issue, in particular, this line confuses me: " when I try call the stored Tile_Levels element in the array from a child of the object, I get Null returned."
Still, I think this may warrant a new question, at this point.
FYI: Though I have not used it, I think there is a way on the site to notify users, when you post a question. Feel free to notify to ask for help.
numberOfTiles = transform.childCount;
This return the number of transform children and is not guaranteed to be the same as the number of components (it return all components on this game object, then children gameobjects, then grandchildren, and so on). If you have a child without a Tile_Levels component, you'll go out of bounds. Also if you have a child with more than one Tile_Levels component, you won't get every component.
I'll slide in slightly off topic and vanish just as quick.
"... which is NOT an array, list or other collection."
No, but foreach operates on IEnumerable, which arrays, lists and other collections ARE, and is what foreach
require.
"... an important distinction (IS vs HAS)"
Well, this is analogous to say that the List HAS an array, and IS not the array... or that a certain Collection HAS a List that HAS an array. It doesn't matter how it it stores the data (arrays, linked lists, trees, whatever), they all IS-a IEnumerable, just like Transform.
Transform IS an IEnumerable so I don't think it's folly to attempt to use foreach on a transform.
public class Transform : Component, IEnumerable
The problem is that it doesn't specify the type so a cast has to be performed from System.Object to the type you wish to use. It just happens to be that Transform will yield Transform components and no other components - resulting in a cast failure at runtime.
OH! I had no idea transform was enumberable! (love this site- thank you!) What order does it enumerate them?
Same as GetChild(0) to GetChild(N - 1).
Note that calling foreach will create an enumerator object for the enumeration.
public IEnumerator GetEnumerator()
{
return new Transform.Enumerator(this);
}
I don't know if that object is immediately discarded by the runtime, but if it isn't, then it means it'll make an allocation every time it enters the foreach (because foreach call GetEnumerator), generate garbage (since it was only used for the loop) and may cause the garbage collector to collect garbage, stalling the game until garbage collection is complete. If performance is a real concern (hobbyists need not concern unless they want to do it for practice/fun), it is more efficient to access each child with GetChild(i) in a good old for loop because:
You don't allocate an object on the heap
You won't risk waking up the garbage collector
You won't have to pay the overhead of the method calls to increment and retrieve the next object
However, IEnumerables are nice to use for quick prototyping, especially with LINQ and such. I typically don't care about NOT using enumerators until I actually have a performance problem.
Answer by Statement · Nov 07, 2015 at 08:45 PM
You already get an array from GetComponentsInChildren so you don't need to create a new array.
void ProcessTiles()
{
tilesAll = transform.GetComponentsInChildren<Tile_Levels>();
for (int i = 0; i < tilesAll.Length; ++i)
{
tilesAll[i].ID = i;
}
AssignMines();
}