Cycling through a list

Hi folks, I have a question on a List.

I have a series of blocks which I have assigned to a list.

I am attempting to change their colour by cycling thorugh them but I am unsure of the correct way to phrase the code.

I have the following…

I’m not sure where I should put ’ blocks ’ and how exactly I should format it in the code so as to cycle through each iteration.
Help appreciated
2h
```csharp

  • public void NewColour(float newColourNumber)
    {
    startColourNumber = newColourNumber

    for (int i = 0; i < blocks.Count; i++)
    {
    Debug.Log ("Number of Blocks = " + blocks.Count);
    if (newColourNumber == 1) {
    rend.material.color = Color.blue;
    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
    } else if (newColourNumber == 2) {
    rend.material.color = Color.red;
    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
    } else if (newColourNumber == 3) {
    rend.material.color = Color.yellow;
    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
    }
    }

}*

```

blocks[i].rend.material.color = Color.blue;

anything along the lines of this???

foreach(var block in blocks)
{
     switch(newColourNumber)
     {
            case 1:
                 block.rend.material.color = Color.blue;
                 break;
             case 2:
                 block.rend.material.color = Color.red;
                 break;
             case 3:
                 block.rend.material.color = Color.yellow;
                 break;
     }
}

Edit: Updated based on your follow-up comment. You could also use blocks if you leave it as a for loop. Use a switch though instead of if-statements. Easier to read and more efficient.

@LionFische , can you explain in more detail what you’re trying to do? I don’t quite understand what you mean by “blocks” or by “by cycling through them.” Are you trying to move colors from one block to another, or just set all the blocks to the same color? And, can you show us your entire block-color-setting script, and not just part of it (so we can see how ‘blocks’ is declared, for example)?

I’ll just take a stab at it, and suppose that by “blocks” you mean cubes (or other block-shaped models) in the scene, by “list” you mean a list or array of GameObject into which you have dragged these scene objects, and that your goal is simply to set them all to a given color.

In that case, you should begin by writing a method that sets all of a set of objects to a given color, like this.

void SetColor(GameObject[] objects, Color color) {
    foreach (GameObject obj in objects) {
        obj.GetComponent<Renderer>().sharedMaterial.color = color;
    }
}

This further assumes you are using an array rather than a List; but just change the first parameter type to List if that’s what you prefer.

Now, it sounds like you want to pick a color based on some integer, rather than an actual Color value. In that case, I would suggest that you add a public array of Color to your script, and use the integer to index into that array. That way, you can use Unity’s color picker to select your color in the editor.

I’ve no idea if any of this is helpful, but I hope it is… provide more detail, and we can provide a better answer.

Good luck,

  • Joe

Thanks Dustin.

I’m a little confused here.

The new var block. I’m not sure how to implement that.

I have a series of blocks that I add to the List, like a breakout type setup. I want these blocks to change colour with a slider. I have this working on one block but want to cycle through all blocks in the List.

The block you mention in blocks, I’m not sure how to declare that. Do I declare a new gameObject type at the start of the script? But then in the inspector what do i do, add the prefab?

Sorry, I’m quite new to this.

2h

Oh and my newColourNumber is a float which causes an issue.

2h

Hi Joe, thanks for the reply.

I have a small project. I’m creating a breakout type game using UI elements. So I have some sliders that I use to move the player object, alter it’s colour etc.

Above that, I have the blokes that I fire a ball at. I also want to apply a slider effect to them to change their colour with one slider.

My thought was to put all the blocks in a List, and then when I move the slider, I would cycle through the List and apply the colour change to all blocks in the list.

Here is the basic code I have used on one block.

using UnityEngine;
using System.Collections;

public class ChangeColour : MonoBehaviour {

    private Renderer rend;

    public float startColourNumber = 2.0f;

    void Start()
    {
        rend = GetComponent<Renderer> ();
        NewColour (startColourNumber);
    }

    public void NewColour(float newColourNumber)
    {
        startColourNumber = newColourNumber;

        if (newColourNumber == 1)
        {
            rend.material.color = Color.blue;
            //Debug.Log ("NewColourNumber Value = " + newColourNumber);
        } else
            if (newColourNumber == 2)
            {
                rend.material.color = Color.red;
                //Debug.Log ("NewColourNumber Value = " + newColourNumber);
            } else
                if (newColourNumber == 3)
                {
                    rend.material.color = Color.yellow;
                    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
                }
    }
}

I’m trying to modify it at the moment to create a list, but running into problems.

2h.

Here is screenshot to you you an idea

I think you’ve put the cart ahead of the horse possibly… You should be able to copy and paste my example verbatim…

“foreach(var block in blocks)”…
that loops through the “blocks” collection, at every iteration it gives you access to the current block (so it’s like a shortcut for blocks*).*
Are all of your blocks always the same color as eachother? Could you use a shared material instead of a different material per instance? Then you could change the color of the shared material and have all of the blocks change color with one property update instead of looping…

1 Like

http://docs.unity3d.com/ScriptReference/Renderer-sharedMaterials.html

Edit: If the blocks are all the same mesh (assuming 3D), using a shared material could also reduce your draw calls by batching them I believe.

Okay, thanks. Was unaware of the shared material option. Just starting out!

I’ll look into that now.

Thanks,
2h

Hi Dustin, I’ve used a shared material now. When the game initially starts, all colours set as they should. There is no update after I use the slider though.

2h

I don’t understand your code to be honest. Not familiar with Switch. I’m not sure how Switch will apply to my Slider.

As for the (var block in blocks), that also confuses me. Should I be defining a Gameobject blocks at the beginning of my code and then in the inspector adding the blocks to the List?

Sorry, I’m not that familiar. It’s tricky starting out.

2h.

OK, I think Dustin’s on the right track. If all your blocks are going to look the same, then you should just use a shared material (i.e., same material for all of them). Indeed, you get this automatically if your blocks are all instances of the same prefab, which they should be.

If you don’t understand what I just said, then you should put your breakout game on the back burner for a week, and spend this week working through tutorials. Prefabs and instantiation are core concepts in Unity.

Assuming you’re still with me, you should be able to test the basic concepts here manually:

  • Run your game.

  • Find the Material in your project that all your blocks are using. Select it.

  • Change its color in the Inspector. Observe that all the blocks change color.

And actually, step 1 is optional — this will work the same way at edit time, too. Is this all working so far?

If so, then the question becomes very specific: how do you do the same thing in code that you just did manually? …And the answer is simple: you just make a script with a public Material property, and then assign a new Color to that Material in your code.

(Then maybe your next question will be: how do you hook up a slider so that it invokes this color-changing script with a variety of colors? But let’s take it one at a time!)

1 Like

You totally lost me by talking about defining GameObjects, etc. I have no idea what your data structure is… no idea how your sliders work, what kind of controls they are, what kind of events handle them… what they update. That gets to what I sort of meant by putting the cart in front of the horse… I admire your gumption but I think you need to take a little step back and learn some of the basics first. One thing I would highly recommend is just reading some blogs, watching some videos, maybe get a pluralsight subscription and learn the basiscs of C#, then or maybe at the same time, go through some of the tutorials in the Learn section so you can get a feel for how it all works together.

foreach reference:

switch reference:

‘foreach’ and ‘switch’ are some pretty basic constructs and you should get a good handle on those among other things. I know it seems like the boring part and it’s hard but I can assure you that if you learn the basics first, then it will make the fun stuff (building your games) go much much faster and be more enjoyable.

Hi folks.

Neither of the above are working out.

This is my current code. It gives no errors but isn’t working.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ChangeColourArray : MonoBehaviour {

    public Renderer rend;

    public Material sharedMaterial;

    public float startColourNumber = 1.0f;

    public List<GameObject> blocks = new List<GameObject>();

    void Start()
    {
        rend = GetComponent<Renderer> ();
    }

    public void NewColour(float newColourNumber)
    {
        startColourNumber = newColourNumber;

        foreach (GameObject block in blocks) {
            if (newColourNumber == 1) {
                rend.sharedMaterial.color = Color.blue;
                //Debug.Log ("NewColourNumber Value = " + newColourNumber);
            } else if (newColourNumber == 2) {
                rend.sharedMaterial.color = Color.red;
                //Debug.Log ("NewColourNumber Value = " + newColourNumber);
            } else if (newColourNumber == 3) {
                rend.sharedMaterial.color = Color.yellow;
                //Debug.Log ("NewColourNumber Value = " + newColourNumber);
            }
        }
    }
}

The newColourNumber is a dynamic float provided by the Slider UI when I move the slider I have in game.

2h

Well that’s part of your problem… it will never be exactly equal to 1, 2 or 3. Instead you might have to define ranges. Let’s say your slider goes from 0.0f to 3.0f. Then you’d need:

if(newColourNumber >= 0 and newColourNumber < 1)
//make it blue
else if(newColourNumber >= 1 and newColourNumber < 2)
//make it red
else if(newColourNumber >= 2)
//make it yellow

Okay, I seem to have it working folks with the above code.

Thank you for the help.

2h

Yep, that’ll be part of it. Another part will be, even though you have a public Material sharedMaterial, you’re not using it. Instead, you’re using the shared material of the renderer of whatever object this script is attached to. That’s probably not what you want.

Here’s a nudge in the right direction.

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class ChangeColourArray : MonoBehaviour {
    
        public Material sharedMaterial;
    
        public float startColourNumber = 1.0f;
    
        public List<GameObject> blocks = new List<GameObject>();
    
        public void NewColour(float newColourNumber)
        {
            startColourNumber = newColourNumber;
    
            foreach (GameObject block in blocks) {
                if (newColourNumber <= 1) {
                    sharedMaterial.color = Color.blue;
                    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
                } else if (newColourNumber <= 2) {
                    sharedMaterial.color = Color.red;
                    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
                } else {
                    sharedMaterial.color = Color.yellow;
                    //Debug.Log ("NewColourNumber Value = " + newColourNumber);
                }
            }
        }
    }

If this still doesn’t work, please remember to describe how it doesn’t work. Don’t leave us guessing.

Best,

  • Joe

P.S. What does “2h” mean?

Thanks folks, I appreciate both your replies.

I’ve signed up for a course and unfortunately they have thrown us in at the deep-end without a great deal of instruction. I’ve to have a small game using UI components made this week, and in one month from now a full on 3d game. That’s been real battle but I’m getting there!

I’m new to Unity, the UI and new to C#. I’m also trying to come to terms with 3dStudio and Spine and a few others. It’s overload.

I’d much prefer to step back and start from the beginning and work my way up, but for now I’ve just got to get through this. I’ve paid the fees so I’m in for the term though not happy with approach.

I think I’ve actually implemented many of the things you both mentioned.

Foreach() was new to me, thank you for that.

The dynamic float is working fine as I have the value set to whole numbers in the inspector and the slider is functioning perfectly. As to why I have to use a float, I’m unsure. At first I had it set to int, but this did not seem to be dynamic.

I’d also like to gradually blend from one colour to another, but for now, this will do.

Next I’m going to add an audio source and attempt to control it with another slider.

I don’t like working like this myself, but I’ve got to get this work done.

I have a list of courses ready to do in the summer when I have time. It’s actually quite frustrating as sometime this stuff is getting in the way of learning.

Oh, and 2h - my initials are HH. I like the sound of 2h. ;-]

Many thanks,

2h

2 Likes

You can also use Unity’s Mathf.Approximately(newColorNumber, 1) as well. Might be easier to read / less user-error prone.