Intro to Buttons
Buttons are the fundamental unit of user-defined interaction of any UI, and hence in gooey. Although you can set callbacks to any widget, the common practice is that buttons are the widgets that execute logic.
Constructor
The constructor is UIButton and its signature is:
idis the string ID.xandyare the offsets with respect to the anchor point. Note that, as directed in the Fundamentals page, your sprites should have its origin point set to top left, to allow for correct positioning in gooey.widthandheightare the desired width and height for the button.textis a ScribbleDX string that represents the text that will be rendered inside the button (for the "normal" state - see below).spriteis the sprite asset used to render the button.relative_tois the anchor point, as usual from theUI_RELATIVE_TOenum.
Assigning logic to the interaction
Like any other widget, buttons support callbacks for each mouse event, as described in the Binding and pre/post-render callbacks tutorial. However, the most common interaction is using UI_EVENT.LEFT_RELEASE, since this is the normal way people use buttons with the mouse. Other than that, you can follow the guide mentioned above to set up a callback for the button.
Changing the appearance of a button
A button in gooey can have up to four different states (normal, mouseover, click and disabled). For each of these you can change the text displayed, the sprite/image displayed and the ScribbleDX format. The setter/getter notation is straightforward, but for extra clarity, the following table summarizes the methods available for setting up the appearance of buttons for each of these:
| Button state | Description | Text method | Text format method | Sprite method | Image method |
|---|---|---|---|---|---|
| Normal | The default appearance | setText |
setTextFormat |
setSprite |
setImage |
| Mouseover | When user hovers over the button | setTextMouseover |
setTextFormatMouseover |
setSpriteMouseover |
setImageMouseover |
| Click | When the user left-clicks the button | setTextClick |
setTextFormatClick |
setSpriteClick |
setImageClick |
| Disabled | When the button is disabled | setTextDisabled |
setTextFormatDisabled |
setSpriteDisabled |
setImageDisabled |
By default, when you create a new button, gooey assigns all texts, formats and sprites to be the same.
Example
Let's create a main menu using buttons. I used mandinhart's Cozy Icons kit for this example. The imagined example will be a main menu which consists of four buttons: Play, Challenges, Options and Quit. Challenges will be locked at first, since the player needs to unlock them first by winning a run on the "regular" game mode.
First, I'll create a panel, but set it to not move or resize, so it stays fixed on the center of the screen:
After this is ready, we can start creating the buttons. For each button, I will create the widget, then set the sprites and text formats, and then I'll add it to the panel. I will add better interaction later, but for now I will just add a placeholder code for the time being, so you can check it out. The code for the first button, for example, is as follows:
Straightforward, right? Let's create the rest (I'm now removing the var local variable declaration from button, just to be kosher):
Note that the Challenges button has extra stuff (as highlighted). The main reason is I'm setting up the sprite and text format for the disabled state, and then I'm actually disabling the button.
This is all we need, but let me go a bit further and change the interaction to something we can see in an embedded example, instead of using show_debug_message, which will be more difficult (this will imply some extra code). Basically, the idea is that, when a button is clicked, we create a small "popup" panel, informing the user what option was picked, and preferably disappears after ~1.5 seconds. Let's do this.
I will create a helper function that we will call on each interaction, that will create the panel, and we will use the method function to pass a local variable to that function so we can vary the text shown. I will use a time source to destroy it after 90 frames. Before creating the panel though, I'll make sure it does not exist, by destroying it first if it does (this will make sure that, for example, if you click on Play and then quickly click on Options, the info shown to the user is the relevant one). The code for the helper function is the following:
Note in the highlighted line that we are using a variable called text, which is not defined anywhere! This is the variable we need to "feed" by using method, when we set the callback. Let's modify the code of the first button to use this function:
Note we are setting the value of text to the result of _button.getText(), which is basically the "Play" string.
I don't understand that last piece of code!
What we are doing here is a "trick" to send the value of a local variable (in this case, _button.getText()) to the inside of a function (in this case, print_option). Since we cannot explicitly pass an argument to the print_option (because of the way setCallback is defined, which only accepts a function name as parameter, and not an array of optional arguments), we want to have the value of _button.getText() available to us; so we assign this to a text variable, put it inside a struct, and then use method to bind the function to our struct. This makes the text value available within the function.
This trick is used in GameMaker to circuvent a feature that, in the "current runtime" (as of 2024.13) is not available, and is present in other programming languages, called closures. If you are interested in learning more about this, you can follow this feature request.
Our final, interactive example looks like this: