Little Helpers - coldrockgames/gml-raptor GitHub Wiki

This is a group of helper functions that did not fit anywhere else and are too few (and too small) to get their own script for each.

is_between
is_between_ex

Test, if the specified value is between the lower_bound and the upper_bound, where
is_between tests the range including both bounds, and
is_between_ex tests excluding both bounds.

/// @function			is_between[_ex](val, lower_bound, upper_bound)
/// @description		test if a value is between lower and upper bounds
/// @param {real/int} value
/// @param {real/int} lower_bound
/// @param {real/int} upper_bound
/// @returns {bool} y/n
function is_between(val, lower_bound, upper_bound) {
function is_between_ex(val, lower_bound, upper_bound) {

is_any_of

/// @function			is_any_of(val, ...)
/// @description		Specify any number of parameters after "val".
///				Determines if val is equal to any of them.
/// @param {any} val	The value to find
/// @param {any} ...	List of values to search
/// @returns {bool}	y/n
function is_any_of(val1, val2, val3, ) {

percent
percent_mult

Gets, how many % value is of total.
percent returns the full value (Example: val 30, total 50 -> returns 60(%)) and
percent_mult returns a multiplier for the value, so 0.6 instead of 60.

/// @function		percent(val, total)
/// @description	Gets, how many % "val" is of "total"
/// @param {real} val	The value
/// @param {real} total	100%
/// @returns {real}	How many % of total is val. Example: val 30, total 50 -> returns 60(%)
function percent(val, total) {
function percent_mult(val, total) {

is_child_of

GameMaker's object_is_ancestor has a little flaw: It returns false if the object is exactly the ancestor. If you test object_is_ancestor(myGameObject, myGameObject) you receive false because it is not derived from myGameObject.
This function here will return true in this case (and also uses object_is_anchestor, so you get the same results, except that the case child==parent also returns true).

/// @function					is_child_of(child, parent)
/// @description				True, if the child is exactly parent type or derived from it
/// @param {object_index} child
/// @param {object} parent
/// @returns {bool}
function is_child_of(child, parent) {

asset_of

Small inline-helper to convert json-strings, that contain asset names to asset indices.

/// @func	asset_of(_expression)
/// @desc	Checks whether _expression is the NAME of an asset (like "objEnemy") 
///		and returns asset_get_index(_expression) if yes, otherwise _expression is returned.
function asset_of(_expression) {
	gml_pragma("forceinline");
	return is_string(_expression) ? asset_get_index(_expression) : _expression;
}

layer_of

/// @func	layer_of(_instance)
/// @desc	retrieve the layer name or depth of _instance
///		if instance is nullish, -1 is returned (gms default for "no layer")
function layer_of(_instance) {

address_of

Note

This function is extremely powerful, as it reliably is capable of uniquely identifying struct- and object points even in the HTML runtime! Javascript does not support pointers, so comparing two identical structures would result in a false positive comparison in HTML, if you just compare the hashes of the instances. This function manages the difference and returns a solid pointer simulation even for HTML! 🎯🚀

/// @func	address_of(_instance)
/// @desc	Similar to name_of, but returns only the pointer 
///		(a unique, but fake, pointer in html5) of the instance
///		as a string, without its type name or other informations
///		or undefined, when _instance is undefined
function address_of(_instance) {

typename_of

/// @func	typename_of(_object_or_script_type)
/// @desc	Gets the type name (= asset name) of either an object or a script asset
function typename_of(_object_or_script_type) {

name_of

/// @func	name_of(_instance)
/// @desc	If _instance is undefined, undefined is returned,
///		otherwise MY_NAME or object_get_name of the instance is returned,
///		depending on the _with_ref_id parameter.
///		To cover the undefined scenario, this function is normally used like this:
///		var instname = name_of(my_instance) ?? "my default";
/// @param {object_index} _instance	The instance to retrieve the name of.
function name_of(_instance, _with_ref_id = true) {

object_tree

/// @func	object_tree(_object_or_instance, _as_strings = true)
/// @desc	Gets the entire object hierarchy as an array for the specified object type or instance.
///		At position[0] you will find the _object_or_instance's object_index and at the
///		last position of the array you will find the root class of the tree.
function object_tree(_object_or_instance, _as_strings = true) {

class_tree

/// @func	class_tree(_class_instance)
/// @desc	Gets the entire class hierarchy as an array for the specified instance.
///		At position[0] you will find the _class_instance's name and at the
///		last position of the array you will find the root class name of the tree.
///		NOTE: This function only works if you used the "construct" function of raptor
///		and the argument MUST BE a living instance of the class!
function class_tree(_class_instance) {

is_class_of

Exact class match

/// @func	is_class_of(_struct, _class_name)
/// @desc	Returns, whether the struct has used the "construct" command 
///			and the type is the specified class_name
function is_class_of(_struct, _class_name) {

is_child_class_of

Exact class match or child_of

/// @func	is_child_class_of(_struct, _class_name)
/// @desc	Returns, whether the struct has used the "construct" command 
///			and the type is the specified class_name
///			or the specified _class_name appears anywhere 
///			in the inheritance chain of this _struct
function is_child_class_of(_struct, _class_name) {

run_delayed
run_delayed_ex
run_delayed_exf

Executes the specified func after a waiting time of delay frames.

NOTE: The Animation ListPool is used to count the frames, as the functionality uses an internal raptor function to achieve the delay. Keep in mind, that calling animation_abort_all on the owner specified here will also stop this delayed execution.
run_delayed_ex runs the function exclusively, and invokes animation_abort_all before starting the waiter.
run_delayed_exf runs the function exclusively, and invokes animation_finish_all before starting the waiter.

See abort() vs finish(), if you are unsure, what that means.

/// @function		run_delayed[_ex](owner, delay, func, data = undefined)
/// @description	Executes a specified function in <delay> frames from now.
///			Behind the scenes this uses the __animation_empty function which
///			is part of the ANIMATIONS ListPool, so if you clear all animations,
///			or use animation_run_ex while this is waiting for launch, 
///			you will also abort this one here.
///			Keep that in mind.
/// @param {instance} owner	The owner of the delayed runner
/// @param {int} delay		Number of frames to wait
/// @param {func} func		The function to execute
/// @param {struct} data	An optional data struct to be forwarded to func. Defaults to undefined.
function run_delayed(owner, delay, func, data = undefined) {
function run_delayed_ex(owner, delay, func, data = undefined) {
function run_delayed_exf(owner, delay, func, data = undefined) {

method_exists
invoke_if_exists

/// @function 		method_exists(_instance, _method)
/// @description 	Checks, whether a method with the specified name exists in _instance
/// @returns {bool}	True, if a method with that name exists, otherwise false
function method_exists(_instance, _method) {
/// @function 		invoke_if_exists(_instance, _method, ...)
/// @description 	Invoke the method, if it exists, with all arguments specified after the
///			_instance and _method arguments.
///			NOTE: GameMaker supports a maximum of 16 arguments, 2 are already used for
///			_instance and _method, so this leaves a maximum of 14 arguments for your call
/// @returns {any} 	The return value of the method or undefined, if the method does not exist
function invoke_if_exists(_instance, _method) {

with_tag

/// @function 		with_tag(_tag, _func, _data = undefined)
/// @description 	Executes the specified function for all object instances that are tagged
///			with the specified tag.
///			NOTE: The function is temporary bound to the instance, so
///			the code IN the function will run in the scope of the instance!
///			You may also specify any _data object to be sent into each of 
///			the invoked functions
function with_tag(_tag, _func, _data = undefined) {

collider_first
collider_cleanup

/// @function collider_first()
/// @description Checks, if this is the first collision between self and other
///		 (means: there has not been the same collision in the previous frame),
///		 and returns true, if that's the case.
///		 The function has no arguments, as it uses "self" and "other", like you
///		 would, when coding in the collision event
function collider_first() {
/// @function collider_cleanup()
/// @description This function is called in the "Room End" event of the RoomController.
///		 It removes all cached collisions and works like a full reset.
function collider_cleanup() {

construct_or_invoke

/// @function construct_or_invoke(_script, args...)
/// @description Tries to create the specified function (succeeds, if it is a constructor),
///		 and if that fails, just invokes it and returns the result.
///		 All arguments you specify are sent to the function.
function construct_or_invoke(_script, arg1, arg2, arg3,) {

struct_join
struct_join_into
struct_join_no_rebind
struct_join_into_no_rebind

Using the functions ending with _no_rebind will not rebind methods in the structs to the new struct, instead the method pointers are just copied.

/// @function		struct_join(structs...)
/// @description	Joins two or more structs together into a new struct.
///			NOTE: This is NOT a deep copy! If any struct contains other struct
///			references, they are simply copied, not recursively converted to new references!
///			ATTENTION! No static members can be transferred! Best use this for data structs only!
/// @param {struct...} any number of structs to be joined together
function struct_join(structs) {
/// @function		struct_join_into(target, sources...)
/// @description	Integrate all source structs into the target struct by copying
///			all members from source to target.
///			NOTE: This is NOT a deep copy! If source contains other struct
///			references, they are simply copied, not recursively converted to new references!
///			ATTENTION! No static members can be transferred! Best use this for data structs only!
function struct_join_into(target, sources) {

struct_move

Move multiple members from one struct to another. If you move methods, they will be rebound.

Caution

You can not move static members!

/// @func	struct_move(_source, _target, _members...)
/// @desc	Moves members from the _source struct to the _target struct.
///		member existance is checked before move, only existing will be created in _target.
///		If the first _member argument is an array, it is considered, that this array contains
///		the names of the members to move.
function struct_move(_source, _target, _members) {

string_match

A comfortable wildcard engine, allowing you to create mask- oder filter-expressions.

Filter character is * and can be placed like this:

Position Description Example
* at the start of the string Means "string ends with" *llo -> hello
* at the end of the string Means "string starts with" he* -> hello
* at both ends Means "contains" *ell* -> hello
* somewhere in the middle Means "start and end with" he*o -> hello but also hey-ho
Combine * freely! Any number, any place He*o*Wo*d* matches Hello, World too
/// @func	string_match(str, wildcard_str)
/// @desc	Checks whether a string matches a specific wildcard string.
///		Wildcard character is '*' and it can appear anywhere in the string, any number of times.
///		* at the beginning means "ends_with" (hello -> *llo)
///		* at the end means "starts_with" (hello -> he*)
///		* on both ends means "contains" (hello -> *ell*)
///		* somewhere in the middle means "starts with and ends with" (hello -> he*o)
///		You may combine the above in any way you like! ("Hello, World" -> "He*o*Wo*d*")
///		NOTE: if no '*' is in wildcard_str, then a == exact match counts!
///		Examples:
///		string_match("hello", "hel*") -> true
///		string_match("hello", "*hel*") -> true
///		string_match("hello", "*hel") -> false
/// @returns {bool}	
function string_match(str, wildcard_str) {

string_interpret_compare
string_interpret_execute

These are two of the most powerful helper functions.
They interpret a string at runtime against a living object or class instance and return:

  • (_compare): whether the specified variable in the instance has the value you are looking for, or
  • (_execute): execute the string against the specified object and return the result
/// @func	string_interpret_compare(_str, _instance, _with_inheritance = true)
/// @desc	Interprets a string that may contain dot-notation, like
///		"myinst.data.name:value" and interprets this against the supplied instance.
function string_interpret_compare(_str, _instance, _with_inheritance = true) {
/// @func	string_interpret_execute(_str, _instance)
/// @desc	Interprets a string that may contain dot-notation, like
///		"myinst.data.name" and interprets this against the supplied instance.
function string_interpret_execute(_str, _instance) {

Some examples on these two functions:

string_interpret_compare

You supply a string and a value to check. It is interpreted and compared with the instance. The result is a boolean, telling you, whether the values match or not. string_interpret_compare("data.initialization.class_name:BossEnemy", objInstance); This will look into objInstance and check, if it has a data.initialization.class_name (following the entire call chain, the dot-notation!). The value of this class_name is compared to "BossEnemy". If the object is a BossEnemy, this returns true, otherwise false.

string_interpret_execute

Similar to _compare, but this function will return you the value. string_interpret_execute("data.initialization.class_name", objInstance); Calling this will return you, whatever value objInstance has stored in its data.initialization.class_name member.

This is a very convenient way to get information out of an object on a string basis, like when you load those strings from a json file in highly configurable games, where most of the runtime data is configured through json files.

extract_init

/// @func	extract_init(_struct, _remove = false)
/// @desc	Extracts an "init" member of the specified struct, if it exists,
///		and returns it. Optionally, the "init" is also removed from the _struct.
///		This is especially useful for instance creation, when you read data 
///		from json configuration files, that might or might-not contain init structs.
///		Use it like "instance_create(...., extract_init(json));
function extract_init(_struct, _remove = false) {

asset_from_string
asset_to_string

These functions serialize/deserialize an assets name to its reference and vice versa for saving object/asset types to json and load them back.

/// @func	asset_from_string(_asset_name)
/// @desc	Recreates the asset index from a type name read from json or a savegame
function asset_from_string(_asset_name) {
/// @func	asset_to_string(_asset)
/// @desc	Convert an asset to a string to be saved to json or a savegame
function asset_to_string(_asset) {

color_from_array
color_to_array

These functions convert a color to and from a 3-elements-array to be saved or restored from a json file.

/// @func	color_from_array(_rgb_array)
/// @desc	Reads a 3-element-array into an rgb color from a json array
function color_from_array(_rgb_array) {
/// @func	color_to_array(_color)
/// @desc	Converts any color to a 3-element-array, which can be stored in a json
function color_to_array(_color) {

get_sprite_scale_for
scale_sprite_to
scale_sprite_aspect_width
scale_sprite_aspect_height

/// @func	get_sprite_scale_for(_target_width, _target_height, _into = undefined)
/// @desc	Calculates the required x/y scale for the sprite 
///		to reach the desired width/height.
///		Result is written to _into_coord2 (if supplied) and returned as Coord2.
function get_sprite_scale_for(_target_width, _target_height, _into = undefined) {
/// @func	scale_sprite_to(target_width, target_height)
/// @desc	Scale an instances' sprite so that it has the desired dimensions.
function scale_sprite_to(target_width, target_height) {
/// @func	scale_sprite_aspect_width(new_width)
/// @desc	Scale an instances' sprite to a new width by keeping the aspect ratio
///		(this means, the yscale will be calculated based on the new xscale)
function scale_sprite_aspect_width(new_width) {
/// @func	scale_sprite_aspect_height(new_height)
/// @desc	Scale an instances' sprite to a new height by keeping the aspect ratio
///		(this means, the xscale will be calculated based on the new yscale)
function scale_sprite_aspect_height(new_height) {

image foreach_async

This pro-only feature gives you a very powerful tool to run loops through large data lists (or complicated, expensive calculations), without freezing/stalling the render loop of gamemaker.

You tell the function the maximum amount of microseconds for each iteration, and it will interrupt the loop, let a frame render, and continue processing in the next frame. This is as-close-as-you-can-get to multitasking in GameMaker.

/// @func	foreach_async(
///			_struct_or_array, 
///			_micros_per_frame = 500, 
///			_item_callback, 
///			_finished_callback = undefined)
/// @desc	Run through a struct or an array with interrupts 
///		every _micros_per_frame microseconds, rendering the next frame. 
///		This is especially useful on animated loading screens and for all
///		long running operations that shall keep the render loop alive 
///		without stalling the game.
function foreach_async(
	_struct_or_array, 
	_micros_per_frame = 500, 
	_item_callback, 
	_finished_callback = undefined) {

You supply an array or struct to process, the number of microseconds (not millis!) for each iteration, and two callbacks.

The first one, the _item_callback will be invoked for every item from the loop and you can do your calculations with it.
The second one gets invoked only once, when the entire loop has completed.

_item_callback

For every item in the array or struct, this callback gets invoked.

It receives 3 or 4 arguments, depending on the type:

# Argument Description
Array Mode: 3 Arguments
0 _item The currently processed item. This is equal to array[i]
1 _i The index in the array, which is currently processed
2 _array The array, which is currently processed
Struct Mode: 4 Arguments
0 _item The currently processed item. This is equal to struct[$ name[i]]
1 _name The member name of the currently processed struct item
2 _i The index in the names-array, which is currently processed
3 _struct The struct, which is currently processed

Here is an example:

// Processing an array
foreach_async(myarray, 500, 
    function(_item, _i, _array) {
        _array[_i] = _item + 1;
    },
    function(_array) {
        ilog("Processing finished.");
    }
}

// Processing a struct
foreach_async(mystruct, 500, 
    function(_item, _name _i, _struct) {
        _struct[$ _name] = _item + 1;
    },
    function(_struct) {
        ilog("Processing finished.");
    }
}

_finished_callback

As you could see in the example above, the _finished_callback receives 1 argument: The entire array (or struct), when processing is finished.

⚠️ **GitHub.com Fallback** ⚠️