Skip to content

Intro

In this short tutorial, we will add some sound effects to gooey and will add some animation to demonstrate how this can be done.

In reality, nothing in this tutorial is gooey-specific - we will use standard techniques and combine them with gooey methods to make them work together.

Adding sound effects

We can add hover and click sound to our interactable widgets. We already imported the hover and click sounds in the previous tutorial, so we're ready to use them. Let's define two methods that we can use on every interaction:

Game / Create
self.hover_sound = function() {
    if (Game.options.audio.sounds_enabled)  audio_play_sound(snd_Hover, 50, false);
}

self.click_sound = function() {
    if (Game.options.audio.sounds_enabled)  audio_play_sound(snd_Click, 50, false);
}

Once these are ready, we can use them in all of our widgets. We'll use MOUSE_ENTER for hovering sounds and LEFT_CLICK for clicking sounds. For example, for our Pause menu:

Game / Draw GUI
_button.setCallback(UI_EVENT.MOUSE_ENTER, self.hover_sound);
_button.setCallback(UI_EVENT.LEFT_CLICK, self.click_sound);

As another example, we can add the same sounds to the tabs in our Options panel, with a little help from getTabControl, which gets the group that contains the tab buttons, and then calling getChildren in a loop to get all buttons:

Game / Draw GUI
    var _children = _panel.getTabControl().getChildren();
    for (var _i=0, _n=array_length(_children); _i<_n; _i++) {
        var _button = _children[_i];
        _button.setCallback(UI_EVENT.MOUSE_ENTER, self.hover_sound);
        _button.setCallback(UI_EVENT.LEFT_CLICK, self.click_sound);
    }

Adding a custom cursor

gooey includes macro variables in the configuration file to setup a custom cursor sprite. The library has the ability to process a default cursor, as well as interact and drag cursors, along with resize cursors for panels. Only certain widgets are processed for interaction: sprites, surfaces, canvases, grids, groups and texts are excluded.

Cursor handling

Since 2025.11, gooey includes improved cursor sprite handling, as well as the possibility to set any widget (e.g. sprites, surfaces and text) as "interactable" via .setInteractable, meaning that gooey will assign the interaction cursor sprite when it's over them, and the drag cursor sprite when the left mouse button is clicked.

We can then use some of the sprites our asset pack already contains:

__Configuration__ Script
#macro      UI_CURSOR_DEFAULT                       cursor_01
#macro      UI_CURSOR_INTERACT                      hand_open_01
#macro      UI_CURSOR_DRAG                          hand_closed_01

We can also set the cells of the inventory as interactable, so even when they're not normally processed for cursor interaction, they can:

Game / Draw GUI
_grid.getCell(_row, _col).setInteractable(true);

With this change, we can see that gooey processes our custom cursors automatically!

Adding animation

We can use any tweening library or technique to animate any gooey widget. The general way of doing this is by tweening a desired variable and then using gooey methods to set this variable where appropriate inside gooey (for example, setDimensions to set position or size).

For tweening, in this case I have already imported my Animatron library, which allows you to create a tween of any instance or struct variable. Let's for example, animate the Pause menu when we press ESC, so that it flies from the top of the screen. To do this, we'll:

  • Create a variable (for example, Game.pause_menu_y) in the Game's Create event
  • Set the initial y offset value of the Panel_Pause panel to the variable of Game.pause_menu_y instead of 0;
  • Use setPreRenderCallback to dynamically set its y to the value of Game.pause_menu_y.
Game / Create
self.pause_menu_y = -700;
Game / Draw GUI
if (!ui_exists("Panel_Pause")) {
    var _panel = new UIPanel("Panel_Pause", 0, Game.pause_menu_y, 350, 250, green_panel, UI_RELATIVE_TO.MIDDLE_CENTER);
    _panel.setResizable(false).setMovable(false).setTitle("Game Paused").setTitleFormat("[fnt_UI][fa_top][fa_center][scale,3]");
    _panel.setPreRenderCallback(function() {
        ui_get("Panel_Pause").setDimensions(,Game.pause_menu_y);
    });
    // ...

If we run it now, we can see the panel will be hidden when we pause the game. To run an animation using Animatron, we can add the tween line to our self.pause method as follows:

Game / Create
self.pause = function() {
    animate("Pause_Menu_Animation", Game, "pause_menu_y", 0, 30, curve_ElasticInv, false, false,,,time_source_global);
    Game.fsm.trigger("Paused");
    time_source_pause(time_source_game);
    ui_get("Panel_Pause").setVisible(true);
};

Here, we're telling Animatron to animate the Game.pause_menu_y variable from its current value to 0 in the span of 30 frames, using the curve_ElasticInv animation curve (these curves are also included in the Animatron library). The next two arguments specify that the animation does not loop and that the specified target value of 0 is not a "relative" value but an "absolute" value. Finally, we set the time_source_global animation curve parent, so even if we pause the game and all instances of time_source_game, the animation still runs.

This will correctly animate the menu when paused. To animate it the other way around when we resume, we can make a very similar call in our self.resume. The only difference is that, since we do not want to resume the game until the animation finishes, we wrap it up in a callback that fires when the animation is at 100%:

Game / Create
self.resume = function() {
    animate("Pause_Menu_Animation", Game, "pause_menu_y", -700, 30, curve_Elastic, false, false,[{time: 1, callback: function() {
        ui_get("Panel_Pause").setVisible(false);
        Game.fsm.trigger("Playing");
        time_source_resume(time_source_game);   
    }}],,time_source_global);
};

This way, we can see that we can easily use Animatron (or any other tweening library) to animate widgets in gooey!

The final result

Animation, sound and cursor
Adding animation, sounds and custom cursors is easy with gooey.