This is a small post on how to conveniently and optimally pack an arbitrary number of incoming script arguments into an array.
Background
GameMaker allows variable argument count through the built-in arguments array. However, it's not exactly an array - you cannot use any array functions on it, and you cannot get a reference to it either - not too unlike JavaScript's arguments, really.
So you usually end up making a real array and copying the contents to it if you need to:
var args = array_create(argument_count); for (var i = 0; i < argument_count; i++) args[i] = argument[i];
And that's a bit of an overhead for something that you might need often.
Obviously, we can do better.
The code
GameMaker has C-style macros. That is, the macro's contents will be inserted at place of it's use during parsing, meaning that you can do all sorts of wacky stuff with them. However, for some reason, GML macros very specifically are not allowed to access argument[] array, so we'll have to get a bit creative:
#macro argument_array __argument_array #macro argument_index __argument_index #macro argument_make_array var __argument_array = array_create(argument_count); for (var __argument_index = 0; __argument_index < argument_count; __argument_index++) __argument_array[__argument_index]
(in GMS1 you'd add each of these using the macro editor instead)
and then you could use it like
/// scr_test(...values) argument_make_array = argument[argument_index]; show_debug_message(argument_array); // {{1,2,3}} if doing scr_test(1,2,3)
As this probably made absolutely no sense, let's break this down a bit:
The first two macros set up alias for future local variables so that we get auto-completion for them and so that GM code editor doesn't highlight them as instance variables for fact of being unaware of macro expansion.
Then, the slightly longer macro combines declaration of these variables with a loop to fill out the array, stopping just before we'd assign a value to the next array item:
// <macro starts> var __argument_array = array_create(argument_count); for (var __argument_index = 0; __argument_index < argument_count; __argument_index++) __argument_array[__argument_index] // <macro ends> = argument[__argument_index]; show_debug_message(__argument_array);
Thus, this way we produce a direct equivalent of the best-case code, except pretty much all of it is contained within a macro.
And, since this results in conventional macroname = value, the code editor will not be confused about unusual syntax.
That's about it, really. Have fun!
I applaud the creativity. Thanks a lot!
The pain that afflicted me for a long time was relieved at once. Thank you so much for your generosity to share your knowledge.
Awesome stuff a bit annoying that the macros have the limitations with the argument keyword, but it’s definitely a lot better than the overhead mentioned in your article.
What does ‘overhead’ mean in this context? Does it have any performance difference?
The end result is exactly the same – I meant in the sense of having to type that out / copy from somewhere / paste from snippets (if you use those)