- Home /
for() loop skipping the first entry. Scripting error?
Hey guys - thanks for looking at my question.
I'm making a small cardgame. I have a script set up that 'deals' the card at the beginning. It's supposed to 1. place the cards in the start position (for solitaire) and 2. assign a random cardTexture to it.
This works perfectly, but the loop seems to skip the very first card, which gets dealt without any material applied.
I'll walk you through my code:
- depending on number of the card, get instantiated at a certain place
- pick a random element of the cardtypes array (Two of Spades, for instance. It has the same order as the textures array)
- create a material, apply the texture that corresponds to the cardtype
- apply the material to the card and apply the cardtype as the name
- delete the material and cardtype from the arrays so they wont be re-used
All these steps work for all cards, except the very first card (i=0) skips the applying the material step for some reason.. If I check the arrays at the end they are empty though..
function Start () {
for(i=0;i<52;i++){
if(i<23) Instantiate(card,Vector3(0,i*0.01,3),Quaternion.identity);
else if(i<30) Instantiate(card,Vector3((12-2*(i-23)),0.00,-0.0),Quaternion.identity);
else if(i<36) Instantiate(card,Vector3((12-2*(i-30)),0.01,-0.3),Quaternion.identity);
else if(i<41) Instantiate(card,Vector3((12-2*(i-36)),0.02,-0.6),Quaternion.identity);
else if(i<45) Instantiate(card,Vector3((12-2*(i-41)),0.03,-0.9),Quaternion.identity);
else if(i<48) Instantiate(card,Vector3((12-2*(i-45)),0.04,-1.2),Quaternion.identity);
else if(i<50) Instantiate(card,Vector3((12-2*(i-48)),0.05,-1.5),Quaternion.identity);
else if(i<51) Instantiate(card,Vector3((12-2*(i-50)),0.06,-1.8),Quaternion.identity);
//pick a rendom element from the cardtypes array
var randomPick = Random.Range(0,51-i);
//create a material and apply a texture from the cardTextures array - which has the same order as cardtypes. Also rename the card.
var cardMaterial : Material = new Material(Shader.Find("Diffuse Detail"));
cardMaterial.mainTexture = cardTextures[randomPick];
card.renderer.material = cardMaterial;
card.name = ""+cardTypes[randomPick];
//remove the element from the arrays
cardTypes.RemoveAt(randomPick);
cardTextures.RemoveAt(randomPick);
yield new WaitForFixedUpdate ();
}
Debug.Log(""+cardTextures); //this is EMPTY so all textures are selected and deleted, why not applied? :S
}
Many thanks in advance!
Answer by Seregon · Apr 24, 2011 at 10:49 PM
I think the problem here is actually the order in which you create the card and apply the texture. You first instantiate a card from a prefab 'card' presumably declared elsewhere in the script:
if(i<23) Instantiate(card,Vector3(0,i*0.01,3),Quaternion.identity);
and then later change the material attached to the prefab:
card.renderer.material = cardMaterial;
whereas you really want to change the material attached to the card you just instantiated. What you are in effect doing is changing the prefab, so that the next time through the loop, this altered prefab is spawned. This explains why the first card doesn't get textured, but the rest do.
The easiest way to fix this is to swap the order in which you instantiate the card, and attach a texture, so that you attach the texture first. However, changing your prefab each iteration isn't an ideal method, and you would be better off saving a reference to the last spawned card and changing that material attached.
I've put the fixed code below. The changes are the definition of the SpawnCard var, and assigning the result of the instantiate calls to that var, this is the card which has just been created. Where you assigned the texture and name of the card, I've changed 'card' to 'SpawnedCard'. Hope this helps:
function Start () {
for(i=0;i<52;i++){
var SpawnedCard;
if(i<23) SpawnedCard = Instantiate(card,Vector3(0,i*0.01,3),Quaternion.identity);
else if(i<30) SpawnedCard = Instantiate(card,Vector3((12-2*(i-23)),0.00,-0.0),Quaternion.identity);
else if(i<36) SpawnedCard = Instantiate(card,Vector3((12-2*(i-30)),0.01,-0.3),Quaternion.identity);
else if(i<41) SpawnedCard = Instantiate(card,Vector3((12-2*(i-36)),0.02,-0.6),Quaternion.identity);
else if(i<45) SpawnedCard = Instantiate(card,Vector3((12-2*(i-41)),0.03,-0.9),Quaternion.identity);
else if(i<48) SpawnedCard = Instantiate(card,Vector3((12-2*(i-45)),0.04,-1.2),Quaternion.identity);
else if(i<50) SpawnedCard = Instantiate(card,Vector3((12-2*(i-48)),0.05,-1.5),Quaternion.identity);
else if(i<51) SpawnedCard = Instantiate(card,Vector3((12-2*(i-50)),0.06,-1.8),Quaternion.identity);
//pick a rendom element from the cardtypes array
var randomPick = Random.Range(0,51-i);
//create a material and apply a texture from the cardTextures array - which has the same order as cardtypes. Also rename the card.
var cardMaterial : Material = new Material(Shader.Find("Diffuse Detail"));
cardMaterial.mainTexture = cardTextures[randomPick];
SpawnedCard.renderer.material = cardMaterial;
SpawnedCard.name = ""+cardTypes[randomPick];
//remove the element from the arrays
cardTypes.RemoveAt(randomPick);
cardTextures.RemoveAt(randomPick);
yield new WaitForFixedUpdate ();
}
Debug.Log(""+cardTextures); //this is EMPTY so all textures are selected and deleted, why not applied? :S
}
Thank you SO $$anonymous$$UCH. You are absolutely one hundred percent right! Whow, I wish I could somehow repay you for this - I've been going insane over this all bloody day. Thank you!
Answer by Peter G · Apr 24, 2011 at 09:13 PM
for(i=0;i<52;i++){
if(i<23) Instantiate(card,Vector3(0,i*0.01,3),Quaternion.identity);
else if(i<30) Instantiate(card,Vector3((12-2*(i-23)),0.00,-0.0),Quaternion.identity);
else if(i<36) Instantiate(card,Vector3((12-2*(i-30)),0.01,-0.3),Quaternion.identity);
else if(i<41) Instantiate(card,Vector3((12-2*(i-36)),0.02,-0.6),Quaternion.identity);
else if(i<45) Instantiate(card,Vector3((12-2*(i-41)),0.03,-0.9),Quaternion.identity);
else if(i<48) Instantiate(card,Vector3((12-2*(i-45)),0.04,-1.2),Quaternion.identity);
else if(i<50) Instantiate(card,Vector3((12-2*(i-48)),0.05,-1.5),Quaternion.identity);
else if(i<51) Instantiate(card,Vector3((12-2*(i-50)),0.06,-1.8),Quaternion.identity);
I don't know if this is your problem (it affects that last card) but your final iteration doesn't fit any of these specifications. i = 51
will be the last iteration and as you can see that doesn't meet any requirements.
And this line:
var randomPick = Random.Range(0,51-i);
if i = 51, then this will always equal 0. I'm not sure if that's what you wanted, but if another iteration happened to choose 0, then there will be no texture to go along with this.
You're absolutely right about this, I also caught this but changing it doesn't actually fix it though o.O and when I don't fix the Random.Range the last iteration will pick the final name, so I can then catch it and fix it. So there must be even an other mistake somewhere o.O I'm just going to start over fresh and rethink every step of the way xD thanks though!
You are absolutely genius for spotting these two errors though - I have been spending the entire day going crazy over this stupid script and I didn't spot it until an hour ago.
Answer by Uzquiano · Apr 24, 2011 at 03:48 PM
Hi,
I would suggest you to do this line out of the for()
var cardMaterial : Material = new Material(Shader.Find("Diffuse Detail"));
I mean, before the for()
That would create one material and assign 52 different textures to it throughout the loop - ending on the last one. All cards would be assigned this one material. The goal is 52 cards with 52 different textures (therefore, diff mat.). I do think you're right the issue is at/around that line - thanks for trying to help :)
So, what you are trying is to show more than one card at the same time... well, sorry I though that only one card was shown at a time...
I will take a look to your code again.
Let me know if you solve it, and how :)
I would say that the problem is in this line:
var randomPick = Random.Range(0,51-i);
Are you using the float version or the int version?
Hei, yes I was following your issue al evening long... so I feel kind of stupid too ;) but Peter G and Statement are really good. I so much to learn still :)
Anyway, now it is over :)
Answer by jahroy · Apr 24, 2011 at 08:28 PM
I don't see it in the code you have posted, but make sure you don't ever check anything like this:
if ( i ) {
doSomething();
}
If i is equal to zero this will evaluate as false. I had a similar situation where one iteration of my loop was getting skipped because i represented an offset into an array that I looked up. I thought was making sure that the lookup function returned a valid result, but 0 was a valid result that was getting skipped.
Heh thanks, I won't. But as you said, that can't be what's causing this :p
Your answer
Follow this Question
Related Questions
How do i get texture from GUI box? 1 Answer
Texture2D to Texture3D 2 Answers
Attaching scripts to meshes with multiple materials 2 Answers
Quality loss on texture 1 Answer