A library for easily creating GameMaker debug views
Inspectron is a library designed to help you easily create debug views for objects in your game, and lets you easily customize what values get displayed using a simple fluent API. Inspectron calculates the best place to put the debug view, ensuring that it's sized appropriately and remains entirely on screen, and automatically closes the view if the target object is destroyed.
Here's an example of Inspectron working out-of-the-box in the Windy Woods template project:
Inspectron can automatically generate a debug view for built-in variables on an instance, as you can see above, but it also allows you to easily customize what values get displayed for objects you create.
Here's an example of the custom inspection for my GameMaker UI library, YUI:
First, import the .yymps package from the Releases page into your project. Once that's done, you have a few options for how to enable Inspectron in your project, but the fastest way to see what Inspectron can do is to enable the default mouse gesture, which is as easy as setting one config macro.
To start, open the InspectronConfig script asset in the project root and set INSPECTRON_GESTURE_ENABLED
to true:
// whether to automatically call InspectronSetGesture with the gesture settings below
#macro INSPECTRON_GESTURE_ENABLED true
Once this is set, Inspectron will configure the default mouse gesture, Shift+Middle-Click, to open the Inspectron debug view for any instance under the mouse cursor. If INSPECTRON_AUTO_INSPECT_ENABLED
is true (which it is by default), Inspectron will automatically display many of the common built-in variables for those instances (and allow you to edit some of them!). You can see what this looks like in that first Windy Woods screenshot above.
You can customize which button and which modifier key to use in the config macros below that line:
// mouse button and optional modifier key to trigger Inspectron if enabled above
#macro INSPECTRON_GESTURE_MOUSE_BUTTON mb_middle
#macro INSPECTRON_GESTURE_MODIFIER vk_shift // set to undefined for no modifier
The automatic gesture method will show the Inspectron view for all instances under the mouse cursor, but if your game is complex you may want to customize which objects actually get included in the view, especially if you want to differentiate between instances that draw in the game world vs instances that draw to the GUI layer.
To do that, you'll need an object event to trigger Inspectron, where you can customize what Inspectron does. For example, you can add a Global Middle Released event to a controller object in your game. Once you have that, you'll want to call InspectronGo()
with some custom arguments. For example:
// in Global Middle Released event
InspectronGo(obj_character_base, obj_gui_base, "Characters and GUI");
- The first parameter tells Inspectron which kind of instances to look for in the game world, using room coordinates.
- The second (optional) parameter tells Inspectron which kind of instances to look for in the GUI layer.
- You can pass
undefined
if you don't want Inspectron to check for GUI instances.
- You can pass
- The third (optional) parameter is simply a name for the debug view. You can set up different gestures for inspecting different kinds of objects, so the name can help you remember which one is being shown (and will be listed in the Views menu at the top of the GameMaker debug overlay).
- If you don't pass a name,
"Inspectron"
will be used by default.
- If you don't pass a name,
- There is a fourth (optional) parameter, which can be a function that returns a name to display for a given instance. For example, if your characters have a
name
variable, you can passfunction (instance) { return instance.name; }
, and thatname
will be displayed in the Inspectron debug view, and in the dropdown to choose which instance to inspect if multiple are overlapping (see screenshots above).- By default, Inspectron will show the numeric ID of the instance and the name of the GM object from the instance's
object_index
variable (as seen in the screenshots above).
- By default, Inspectron will show the numeric ID of the instance and the name of the GM object from the instance's
The built-in variables that Inspectron can display automatically are convenient, but you'll likely want to make your custom variables on objects inspectable as well. Inspectron makes this very easy, by providing a fluent API to tell Inspectron what variables to display and how to display them. Inspectron will then take care of making the underlying dbg_
function calls for you to display the Debug view.
You should define the Inspectron fields for an object at the very end of the Create event of your object. For example:
// in obj_player Create Event
...
// All the other code in your create event
...
Inspectron()
.Section("player")
.Watch(nameof(player_health), "Health")
.Checkbox(nameof(invulnerable))
.BuiltIn()
The above code will tell Inspectron to show:
- A section named "player".
- The current value of the
player_value
variable on the obj_player instance.- The second parameter tells Inspectron to use
"Health"
as the label, instead of re-using the variable name ("player_health"
).
- The second parameter tells Inspectron to use
- A checkbox to allow you to set the
invulnerable
variable on the obj_player instance totrue
orfalse
. - The standard set of built-in variables that Inspectron can display by default.
- You can go look at the function to see how it's set up! It's just using the same functions you can use elsewhere.
The fluent API means you can keep calling Inspectron field functions in sequence until you've defined everything you want to display.
NOTE: the first parameter must be the name of the variable on the instance that you want to display, as a string. It's best practice to use the nameof()
function provided by GML, as if you later rename that variable where it's defined, the nameof()
function will report an error.
Actually you don't really have to do anything special here. If you define an Inspectron on a parent object, and then call Inspectron.Etc()
on a child object, Inspectron will automatically include the parent inspectron in the child object's definition, at the end. This works no matter how many object parent/child relationships you set up.
You may want to include a .Section
or .Header
in child objects to make clear about which variables belong to which object. The same is true for constructor functions that inherit another constructor.
.BuiltIn()
- Adds the default list of inspections for built-in instance variables, e.g. x, y, sprite_index, etc.- These are not included by default when defining a custom Inspectron on an object/struct, you have to call this function yourself if you want them!
.Section(label)
- Creates a dbg_section with the providedlabel
.Header(header)
- Creates a dbg_text withheader
formatted as[ header ]
(useful for separating groups of variables inside a section).Label_(label)
- Creates a dbg_text withlabel
as the text.Button(label, on_click)
- Creates a dbg_button withon_click
as the button's function.Watch(field_name, [label])
- Creates a dbg_watch for the provided field name, with an optional customlabel
.Color(field_name, [label])
- Creates a dbg_color for the provided field name, with an optional customlabel
.Checkbox(field_name, [label])
- Creates a dbg_checkbox for the provided field name, with an optional customlabel
.TextInput(field_name, [label])
- Creates a dbg_text_input for the provided field name, with an optional customlabel
.Slider(field_name, min, max, [label])
- Creates a dbg_slider for the provided field name with the specifiedmin
andmax
values, and an optional customlabel
.Sprite(field_name, [label])
- Creates a dbg_sprite for the provided field name, with an optional customlabel
- NOTE: Not recommended for large sprites as dbg_sprite will render the sprite at full size. You may want to use
.SpritePicker()
instead (see below)
- NOTE: Not recommended for large sprites as dbg_sprite will render the sprite at full size. You may want to use
.Picker(field_name, choices, [label])
- Creates a dropdown wth the providedchoices
Array as options. The name in the dropdown will be whateverstring(choice)
returns..LabeledPicker(field_name, choices, labels, [label])
- Creates a dropdown wth the providedchoices
Array as options, where the labels will be the corresponding string from thelabels
Array..FontPicker(field_name, [label])
- Creates a dropdown listing the current font for the named field, and allowing the user to pick from the list of all fonts.SpritePicker(field_name, [label])
- Creates a dropdown listing the current sprite for the named field, and allowing the user to pick from the list of all sprites.FilteredSpritePicker(field_name, filter_func, [label])
- Creates a dropdown listing the current sprite and allowing the user to pick from a filtered list of spritesfilter_func
is of the form(sprite_asset, sprite_name) -> Bool
, where returningtrue
will include that sprite in the list.
.AssetPicker(field_name, asset_type, asset_name_func, [label])
- Creates a dropdown listing the current asset for the named field, and lists all of the assets of the providedasset_type
using theasset_name_func
to determine the name to display- NOTE: This is provided so that you can create Asset Pickers for things besides Font and Sprite, but over time Inspectron will get more functions for each Asset type as I get around to it
.Include(field_name, [label])
-field_name
should be the name of variable pointing to another GM instance or struct, with its own Inspectron defined on it. A label will be rendered, followed by all of the fields defined by the Inspectron on the referenced instance/struct (which can.Include()
more instances/structs!), indented accordingly.- This can be very useful if, for example, your character instance has a
weapon
variable which is an instance or struct with its own variables. Define an Inspectron on that instance/struct and it can be displayed in the character's Inspectron!
- This can be very useful if, for example, your character instance has a
.AtTop()
- You can call this after defining any other field (including.Header()
/.Button()
/etc) to ensure that the field will be displayed at the top of the Inspectron debug view, even if the object or struct is later extended by another inspectron (e.g. in the child object).- This can be useful with
.Button()
, for example, to expose some common functionality at the top of the inspector.
- This can be useful with
Some other functions may be defined in the Inspectron script file but should be considered experimental (and hence unsupported) if not listed above.