Clearing and adding an array?

I’m writing code for a menu system. Rather than hard-coding all of the values, I’m creating a dynamic system that will work with all my game menus, so things like how many items are on the menu and where they are drawn on the screen are all variables that could change.

I need a way to remember a single float value for each item on the menu so when I draw the cursor I know where to put it. Naturally that means an array. My plan is to add a value to that array each time I draw an item on the screen, (while that variable is still known.) This means I need to also reset this array each frame or else the array would continually expand every frame.

First of all, for some reason I thought there was a method to add a new value to an array. But as I look at the documentation, only javascript arrays have an “add” function. (And I’ve never used javascript before, so I don’t know why I remember there being an “Add” function.) So how do I dynamically add a value to an array?
Can I just do something like myArray[myArray.Length] = value?

But the bigger issue I’m facing is resetting the array after each frame. I don’t see that functionality anywhere. How do I clear out an array back to having no content so I can add all the values again for a new frame?

It sounds like you want a C# List rather than an array. List behaves more like a JavaScript array with add methods etc…

To add to the end of list you can use Add()
To clear the list you can use Clear()

See List<T> Class (System.Collections.Generic) | Microsoft Learn

Sounds like you’re thinking of List.

List<float> someNumbers = new List<float>();
someNumbers.Add(2f);
Debug.Log("The first number is " + someNumbers[0]);
Debug.Log("There is "+someNumbers.Count+" element.");

Arrays are fixed-length, but most of the time people use a List instead, which is dynamically-sized and has methods to Add, Remove, and Clear.

I’m having trouble understanding what you’re trying to accomplish with this list, though. If each element is associated with a specific menu item, then presumably you are relying on the indices of this list matching the list of menu items in order to tell which is which, and in that case you probably don’t want to Add/Clear every frame, you probably just want to update the corresponding value every time you update each menu item.

(Although organizationally, the more traditional thing to do in an object-oriented language would be to create a data structure that holds both the menu item and its position all together in a single object.)

Although it’s not even clear that you need a new variable at all, since the menu items probably already have coordinates stored in their Transform…

Basically, you may be able to simplify this whole solution if you take a step backward and explain more clearly what you’re trying to accomplish.

Okay, a List then. That must have been what I’ve used in the past.

What kind of overhead does a list bring with it? I imagine there are situations where I would be better off using one or the other; I suspect that a list is more expensive to the system. It’s good to be apprised of what difference these systems make before I go overboard with them.

Well first off, I’m separating the display of items on the menu from the functionality of the menu. That seems kind-of like a requirement to me since these matters have to be accessed in different functions; the “update” function actually retrieves player input, and the “OnGUI” function actually draws things on the screen. So the way I see it, I need a universal “index” value anyway, just so I can keep the functionality and the rendering on the same page.
95% of my menus are just single-dimensional lists anyway, so tracking selections via a single index value makes the most sense.

To “take a step back” here, I used to have my menus handled inside my game manager, and I’m moving them to their own classes since I have more than two menus in the game. My plan is to create a base menu class with the common functionality and then create each menu screen as its own class (extended form the base class.) When a menu is opened I’m just going to spawn the script into the scene, and delete it when the menu closes. That way I can easily make finite changes to any menu that has special designs.

The functionality I’m planning for the basic menu, when drawing it within the child class, is to call various functions I have created. An example might look like this:

DrawMenuFrame(MenuWidth, MenuHeight, bDrawTopDeco, bDrawBottomDeco);

        DrawHeaderText("Pause Menu");
        DrawItemText("Return to Game", currentLine, true);
        DrawItemText("Music: On", currentLine, true);
        DrawItemText("Change Controls", currentLine);
        DrawAlignedText("Additional information about an option", LeftEdge, currentLine, RightEdgeOffset, 1);
        DrawItemText("More options", currentLine, true);

        DrawCursorInSelectionMatrix();

The commands to draw each item or text or etcetera (I am rendering more than just the “selectable” items) include the code to keep track of where they are drawn on the screen, so my code just calls the functions in order.
To get the cursor to appear by the correct item, my thinking is to have an array (Well, a list, it seems,) that gets values added to it each time the menu draws a selectable item. Since the items are all drawn in order, the list will reflect those values in order. So when I draw the cursor I just have to grab the value for the current index from the list to know where the cursor gets drawn.

But since the code to draw the menu is drawn every single frame, this would cause the list to get duplicate values added to it each frame. So either I add a bool to check every frame if we are adding those values or not, or I just reset the list each frame. I guess the former would be slightly less taxing on the system, but the latter makes it easier for me to dynamically change the menu when I start tweaking variables in the inspector.

The main one is that, when using an array, you have to see the fixed size as a feature and not a bug. When you create an array, you know it’ll be the same size for its entire lifetime, and can rely on that.

Read up about List’s “capacity”. Behind the scenes, a List has an array which just happens to be larger than is necessary for the current data, and it pretends that its own .Count is all there is. But what happens when you use .Add one too many times so that the array no longer fits into the capacity? It has to copy everything over to a new, larger array, and dispose of the old one. This resizing is the biggest performance difference between them, and it gets worse the larger the array/list is.

(You can set capacity manually when you create the List, but if you know enough to do that, you can probably make it an array. If you make it larger than necessary you waste memory.)

There’s a reason you hardly ever see huge Lists in code, but if you look at something like a Mesh, which can have an array of tens of thousands of Vector3, or textures which can easily give you a million-pixel array of Color[ ]. The entire benefit of List is Add and Remove, but if you use Add on a huge array, you can get a huge performance hit (and if you don’t use .Add, what’s the point?)

1 Like

You may want to note that it’s pretty unusual to do anything with OnGUI these days. Unity UI (sometimes called UGUI) was created several years ago as a more robust system for creating and managing a UI, and Unity is now working on an even newer system called UI Elements.

You certainly can use OnGUI if you want, but you should be aware that it’s not what people will assume you’re using when you ask for help on the forums.

Regarding your specific issue of drawing the cursor, my impulse would be to modify your loop that draws the menu items so that it checks on each item “is the cursor here? if so, draw it here”. (If drawing it immediately creates Z order issues with subsequent menu items, you can instead save a variable remembering the position of just that one menu item–rather than array with EVERY menu item–so that you know where to draw it at the end of the loop.)

When a language has a resizable array, it is typically implemented under the covers using a fixed-length array plus a counter indicating how many slots in it are currently used. If the data gets too big to fit in that array, it allocates a new, bigger array and switches to that, copying all existing data into it.

Usually there’s also some rules about shrinking the array if it ends up mostly-empty (so that you don’t hog memory forever just because you needed it one time in the past).

This copy operation is expensive, so to avoid needing to do it too often, the array size usually grows exponentially (e.g. doubling each time). That way, if you add a bunch of elements to it one at a time, the amortized cost is only linear with the number of elements added–the longer the list gets, the more expensive the copy becomes, but the less often you have to do it, because it reserves more and more extra space each time. You can imagine “setting aside” a little block of time for every call to Add, and then at some point all of those set-aside time blocks are consumed in one big copy operation. So adding N elements to the list is O(N), even though some of the individual steps may not be O(1).

However, when you’re making a real-time, performance-critical application–which games often are–you may not care how small the amortized cost is if the bill for the giant expensive operation all comes due in a single frame, causing your game to stutter in that particular frame. Therefore, it’s somewhat risky to add/remove from a really big list in performance-sensitive code.

(But remember that “really big” is using computer standards of bigness, not human standards. A list with thousands of elements is “small” for modern machines.)

If you know in advance that your list is going to need to reach a certain size, you can give the computer a hint by requesting a capacity for the list to match that size. This lets the list go directly to the size up-front instead of doing repeated expansions gradually as it grows.

A list of items in your menu is going to be “small” for any sane menu. Although in your case, you don’t really need to clear and refill the list every time; if you wanted to avoid that, then instead of adding positions for each item, you could first check how big the list already is, and if it’s big enough just set the position at the proper index.

if (mylist.Count > index)
{
    mylist[index] = newValue;
}
else
{
    mylist.Add(newValue);
}

Also, again–as best as I can tell–you don’t actually need a list in the first place for your particular situation.

Yeah, and a while back in a older version I was getting error messages saying that OnGUI was going to be depreciated in future versions. But evidently they decided against that and retroactively called it the IMMGUI system or something like that.
I could migrate my code to one of the newer UI systems (And since I’m migrating my menu code this might be the time to do it too) but I really don’t see the point to it anymore. Everything I’m drawing for my HUD and menus is super-simple; mostly just text and some occasional textures. It seems to me that it is easier to just keep with what I know and maintain finite control of my system, rather than abandoning the work I’ve already done, learn a new system, and run into new problems, all so I can… produce the same result with no noticeable gain to my system.

I mean if I’m wrong, by all means tell me about the marvelous wonders of the newer UI systems. Now is the time for me to switch. But honestly I can’t think of anything I want to do that I don’t know how to do already.

That is really smart, actually. I think I should adopt that plan.
I also just started using the list’s length as an easy way for the menu’s functionality to determine how many selectable items are on the menu, rather than having a variable I set manually for each menu. But if that tiny shortcut were really so important I could replace my list.add code with a counter.

But I wanna let the user customize effects for every individual pixel on the screeeeeen!

If you already have a working menu using OnGUI and you are happy with it, then I would probably not migrate.

But if you start a new project that would require you to build a new UI anyway, then you might want to think about building it in a newer system.