Some of you may be familiar with RousrSuite - the ill documented extension that is included with the other Rousr extensions. RousrSuite is a collection of small GML Extensions, generally each with a singular purpose, that are used by Rousr projects.
The current make-up of RousrSuite is:
- RousrCore - a grab-bag set of functions used at the core of most
Rousrcode. This includes much of the basic functionality we’ve wrapped up… such as
ensure_fontwhich store a global for the current
draw_set_*variable and when passed a color or font, they’ll do a
draw_setcall if its not already that. Of course, there’s things like math and debugging functions in here as well!
- RousrDs - a set of new data structures that are based on arrays, as well as some helper functions when working with the native
- RousrInput - an (unfinished) set of functions to wrap up the paradigm of named actions being mapped to controller inputs in an attempt to add a layer of abstraction to input.
- RousrUI - an (unfinished) set of UI widgets and basic GUI functionality you’d expect. This is intended for in-game use, which differs from the ImGuiGML debug-use case.
It’s available to be downloaded on the YYMP, but mainly is intended to be used internally by our extensions. I do hope one day it’s an extensively usable library of functions for anyone!
In GML, I find the use of arrays to be very convenient, especially once I had gotten used to the “Create on Write” vs using references to arrays to ensure we’re operating on the same one when accessing them from other scopes than they were created from. The clear benefit over the other
ds_ types is that there’s no need to call a destroy on them, they’re seemingly auto-garbage collected. This makes some of the more OOP paradigms I’ve talked about much cleaner to implement - we’re not relying on a destroy / clean up hook and can just let these objects fall out of scope when we’re finished… or potentially pool them.
So, arrays are useful and convenient, but I wanted them to be slightly more reliable as a container. For one, native arrays can’t be shrunk - they can grow larger and the pointer will remain the same, but if you want to shrink one, you’re out of luck and you need to create an entirely new array, copying the data to it. Also, with the blackbox of
array_length_1d and not being aware of what its doing, I also like having the ability to store alongside the array simply how large it is.
sr_array is an Array Object (as I call them) that wraps the normal 1D array that is native to GML. It’s a fairly simple construct, where
sr_array_create() returns one, and you can optionally pass it an existing array (and size) for convenience (and micro-optimizing):
Generally though, I just use the default version and allow it to create its own new array:
So what does this return? An array with this layout:
At this point, its highly likely you’re still asking yourself: But Why?!
Simply-put: the primary purpose of doing this is that anything that holds a reference to this array can retain the reference to this array, even if the [ actual array ] is destroyed and recreated.
(Note: The reason that in the debugger Arrays show up with a hex value is that they’re actually pointers, rather than an id or index like the
ds types or even resources store)
The reason that we want to do this in the first place is so that we can freely resize the array, grow or shrink it, and not worry that all instances with variables holding the array now need to know that the old array is invalid and they need a new reference to the new array. As I mentioned before, you can grow an array and retain the same pointer to it, but if you want to shrink an array the only way to do this is to create a brand new array and
array_copy to it.
size_of_actual_array is not literally the same value as what
array_length_1d returns, but rather, it’s the size of the currently “in use” elements of
actual_array. By doing this, we can subtract from that number to shrink the array as far as logic is concerned, but it’s still actually holding a pointer to the same memory as before.
You’ll note that in this example, we haven’t removed 15, and that’s on purpose. Since we’ve decremented the 3 to a 2, the internal array can stay there - no need to allocate any new memory or clone the array - we now simply know “only the first 2 elements are valid.” One downside is that this does mean that the array always occupies the max element count its ever reached in memory, and I admittedly haven’t really benchmarked how much of an issue that is, but if it were ever to get out of control, the clear option does allow you to reset the internal array.
So now that we’ve got the basics of the
sr_array down, let’s talk a little bit about how it works under the hood.
sr_array includes a bunch of functions to manipulate the array, but the things that it can do that a normal array can’t are: inserting new elements in the middle of the array and removing elements from an array.
sr_array_insert creates a brand new array as the data array of the
sr_array and use
array_copy to copy the original array to the newer, 1-element larger array, making space to insert the new element.
sr_array_remove also creates a brand new data array, but this one is 1-element smaller, with the element at the passed index omitted from copying. Generally, this means we’ll do two copies: copy the first portion of the array, add our element at the inserted index, and finally copy the remaining portion of the original array in the case of a insert, or we copy the portion before and portion after the removed index in the case of a remove.
sr_array is an accessor function that follows a pattern I tend to use: If you pass a value, then it acts as a setter, setting the value at
_val while if you omit the value, it acts as a getter, returning the value at
In addition to these functions, we also have push/pop functionality for adding / removing elements to both the front and end of the array as well as some functionality for finding a value in the array, pushing unique elements to the array, or just clearing the data contained in the array.
sr_array is designed to be fast to implement and convenient to use, the one last downside to mention is that it does mean the
 accessor will not play nicely with
sr_array, and you’ve gotta remember to access your arrays using the
sr_array accessor function. So if you do adopt using these guys, when you start debugging strange array accesses, make sure you’re using
sr_array accessors if they’re
sr_arrays. I still mess this up.
which is a little unfortunate, but without accessor chaining (i.e.,
var _thing = _array_of_arrays[_i][_thing_index])) it actually ends up being a bit convenient since you can nest the calls if necessary.
Ok, this guy isn’t as advanced as the mixins from the last article, but I liked the consistency of ending on a thing and calling it an “Advanced Topic.” (I just broke the fourth wall I think).
sr_stack_array is a stack data structure built similar to the
sr_array with some minor differences in API and what the values it stores mean. It exists as an easy drop-in and forget stack datastructure, without the need to do the
ds_create/destroy pattern of a
ds_stack since we have no need to destroy it.
A Top value of
-1 means that the stack is empty, and we don’t pay attention to whatever
array_length_1d is of the stack of elements -
Top is all that matters.
In addition to
sr_stack_array_create the following functionality exists - it’s a bit smaller of an API than an
sr_array though it has a much more specific use than the more general purpose
These functions do exactly what you’d think - the first will tell you what the top index of the stack is, how large it is, while the second returns a boolean of whether or not the stack is empty.
Peek will return the value of the top of the stack, or at the
_index from the Bottom of the stack if
_index is a positive value, or from the Top of the stack if it’s a negative… but does not change the stack.
Manipulating the Stack
Pop will return the value at the Top of the stack and decrease it by one, while the push simply adds
_val to the top of the stack.
That’s all I’ve got for you this update, but next update we’ll take a look at another RousrSuite extension:
However, I’m looking to hear from you what you might want to learn more about, particularly:
- Programming Patterns
- General habits / standards