DataBuilder - coldrockgames/gml-raptor GitHub Wiki
The DataBuilder
is a struct class widely used in raptor as it helps you designing your classes with the builder pattern.
You find informations about this pattern on many websites (including wikipedia), but many of those sites explain the pattern in a weird, overcomplicated way.
The builder pattern is quite simple:
- Most builder classes have a parameterless constructor (which works great with the Savegame System).
- Instead, you set your values through a series of
.set_*
function calls, which allreturn self
, so you can connect the calls directly. - Depending on what the class does, an optional
.build()
method is also implemented, which assembles all the informations it received.
Throughout raptor, you find many builder-pattern classes, some of them are:
- Animation
- StateMachine
- The ControlTree, and therefore most of raptor's entire UI Subsystem
- The Savegame System (in fact, the savegame functions even are all
DataBuilder
s.
So, you likely have already used the builder pattern multiple times.
It looks like this:
animation_run(self, 0, 30, acMyCurve)
.set_move_distance(100,100)
.set_rotation_target(180)
.set_scale_target(0.5, 0.5)
.add_finished_trigger(...)
;
See those connected function calls? animation_run().set().set().set().add_finished_trigger(...)
?
This is the builder pattern! You may connect your calls in one go.
It is a very simple base class, containing a data
variable and offering a .set_data(...)
function, which follows the builder pattern.
So, with a DataBuilder
, you can write code like:
function MyDataClass : DataBuilder {}
// invoke it like
var foo = new MyDataClass()
.set_data("var1", 0)
.set_data("var2", true)
.set_data(...)
// ... and so on ...
It will then have var1, var2 and all you set in the data
variable:
foo.data.var1
foo.data.var2
// ... and so on ...
In the Savegame System for instance. You may do this with every savegame_* function:
function someFunc() {
var important_variable = true;
savegame_save_game_async(FILE_NAME, FILE_CRYPT_KEY)
.set_data("important", important_variable)
.on_finished(function(_data) {
if (_data.important) { /* do something */ }
});
}
You set any variable in the data member of the worker class for the savegame and you will receive your data in the on_finished
and on_failed
callbacks. So you may add local data from the calling function, which might be needed in the callback.
Used smart, this is a great concept of forwarding data to anonymous functions, which might not be available there otherwise.
This child class of the DataBuilder
combines the DataBuilder-concept with the Property Binding concept, by offering a .binder()
function and allowing you to create a DataBuilder with bindable properties, so you can pull/push/watch the properties of this class.
It works identical to the DataBuilder, and allows in addition:
function MyDataClass : BindableDataBuilder {}
// invoke it like
var foo = new MyDataClass()
.set_data("var1", 0)
.set_data("var2", true)
.set_data(...)
.binder()
.bind_push("var1", mygameobject, "x");
Now the content of your "var1" will be pushed to the mygameobject
instances' x
coordinate whenever the value changes.
Those two classes combine the functionality of the VersionedDataStruct with a DataBuilder and allow you even savegame-aware DataBuilders to be created.