Interfaces - coldrockgames/gml-raptor GitHub Wiki

Raptor offers some interfaces for you to implement into your objects.

Interfaces in GML

Well, GML does not have interfaces. But raptor does. Kind of. But not in the C#/Java/OO style. But close to.

There are two functions available in raptor for your interfaces:

What is an Interface in Raptor?

  • It is a constructor function. You can make any constructor an interface.
  • It has an (optional) ctor function (there's a raptor macro for it), which will be executed after the interface has been applied on the target instance/object.
  • It may declare any functions and they will be added to the instance or object, the interface is implemented on.
  • It may even declare variables, but this should be done in the ctor function, as that one gets executed in the context of the already vital target instance.

Example of an interface

function ILoggable() constructor {
    
    ctor {
        __log_string = undefined;
    }

    get_log_string = function() {
        if (__log_string == undefined) 
            __log_string = $"{MY_CLASS_NAME} {some_variable} {some_status}";
        
        return __log_string;
    }
}

Now imagine, you have a game object (or struct class) which shall implement that interface to create standardized log messages. You would do it like this:

// CREATE EVENT of a game object
event_inherited();
implement(ILoggable);
function my_code_class() constructor {
    implement(ILoggable);
}

What happens here?

  • The implement function creates an instance of ILoggable by invoking the constructor.
  • This instance is then struct_joined into the current object. This means, all functions and members of the interface function will be transferred to the target instance. Methods will be rebound using method(...) to inherit the new scope.
  • Then the ctor function is invoked (if it exists).
  • After executing, ctor is removed from the instance.
flowchart TD

    A["implement(ILoggable)"] --> C["inst = New ILoggable();"]
    C --> D["struct_join(target, inst);"]
    D --> E[Add to interfaces list]
    E --> F{"ctor exists?"}
    F -- Yes --> G["ctor();"]
    G --> H["struct_remove(self, ctor);"]
    H --> I
    F -- No --> I[end]

Interface Implementation Functions

As you can see in the jdoc below, interface functions may even have arguments! You can use any constructor in your game as interface to rebind it (or: implement it) in any other instance, no matter whether it's a code class or a game object.

implement(interface_type)

/// @func	implement(_interface, ...constructor_arguments...)
/// @desc	Works like an interface implementation by copying all members
///		and re-binding all methods from "interface" to "self"
///		Creates a hidden member __raptor_interfaces in this struct which contains
///		all implemented interfaces, so you can always ask "if (implements(interface))..."
///		NOTE: Up to 15 constructor arguments are allowed for "_interface"
///		This function will create one instance and copy/rebind all elements to self.
function implement(_interface) {

implements(instance, interface_type)

This is the reflection counter-part, telling you, whether a specified instance implements the specified interface_type. You may supply the interface_type either as a string (name of the class) or the type.

Although the first argument is named struct, this works for game objects as well, as they are kind of a struct too.

/// @func	implements(struct, _interface)
/// @desc	Asks the specified struct whether it implements the specified interface.
function implements(struct, _interface) {