Skip to content

Intro

Currently, the game just draws a text label above the player sprite that shows what tool is currently selected, and you can switch tools with the mouse wheel. We want to have a proper toolbar similar to what CRPG games or Farmville present, to select any tool and to graphically show which tool is selected.

Creating the toolbar base

For the sake of consistency, we will use the same techinque as in the HUD tutorial: we will use the Draw GUI event of the Game controller and wrap the gooey code into an exists check, so it only runs once - although as mentioned before, we can also use a script, Create event etc. Keep in mind though, if you put the code in an event such as Draw GUI, that runs every frame, all code shown below should be wrapped in that ui_exists call, to prevent the system from creating multiple panels.

gooey makes rendering the toolbar itself very easy: it's just a panel with a grid. Since we need four slots for the four "tools" (shovel, watering can, axe and plant seeds), we can create a 1x4 grid.

To define the size, we can create a little set of variables and calculations, where basically we dynamically calculate the width and height of the panel based on the numebr of slots, the pixel size of each (square) slot, the margin of the slots and the (horizontal) spacing between each slot.

Once we have this, we can go ahead and create the panel and the grid. We can position the panel 30 pixels above the bottom center of the GUI layer, to make it spaced evenly with the HUD panels we created before:

Game / Draw GUI
if (!ui_exists("Panel_Toolbar")) {
    var _num_slots = 4;
    var _slot_size = 90;
    var _margin = 10;
    var _spacing = 10;
    var _width = _num_slots * _slot_size + 2 * _margin + (_num_slots-1) * _spacing;
    var _height = _slot_size + 2 * _margin;

    var _panel = new UIPanel("Panel_Toolbar", 0, -30, _width, _height, glass_panel, UI_RELATIVE_TO.BOTTOM_CENTER);
    _panel.setResizable(false).setMovable(false).setDragBarHeight(0).setImageAlpha(0.9);

    var _grid = new UIGrid("Grid_Toolbar", 1, 4);
    _grid.setMargins(_margin).setSpacingHorizontal(_spacing);
    _panel.add(_grid);

    // Closing if brace not shown

If we run the game, we can see the toolbar created, although the grid is invisible. Since it currently does not have any widgets, we cannot see whether the spacing/margin looks fine. We can quickly add .setShowGridOverlay(true) to our _grid reference to view it before we add widgets to it:

The toolbar stub made with gooey
The initial toolbar "stub" consisting of a panel and a grid, showing the debug grid overlay in order to check spacing/sizes.

Creating the buttons

Now that we have the toolbar stub, we can remove/comment the grid overlay code (or set it to false) and get to add widgets. In this case, we want to achieve two things:

  1. We should show the currently selected tool graphically - so if they use the mouse wheel to change tool, the toolbar should reflect this; and
  2. We also want to allow the player to click on a specific tool to select it.

For this, we can create some gooey UIButton widgets on each slot. They will graphically show the tool icons already available in the asset pack. We will use the dt_box_9slice_c sprite as the button sprite (and lt_box_9slice_c when mouseovered/clicked), but I went ahead and created a variation of that sprite with a yellow border, to showcase the selected tool (I named it dt_box_9slice_c_selected). Also, we have our UI sprites for the different tools in the UI group in the asset browser. For convenience we will display them as inline sprites in the button Scribble text string, scaled up for visual impact.

Let's create the buttons and set them to the slots. We will make them inherit the width and height of the slot automatically:

Game / Draw GUI
    var _button = new UIButton("Button_Toolbar_dig", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][shovel]", dt_box_9slice_c_selected, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _grid.addToCell(_button, 0, 0);

    var _button = new UIButton("Button_Toolbar_watering", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][water]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _grid.addToCell(_button, 0, 1);

    var _button = new UIButton("Button_Toolbar_axe", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][axe]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _grid.addToCell(_button, 0, 2);

    var _button = new UIButton("Button_Toolbar_plant", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][plant]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _grid.addToCell(_button, 0, 3);

The result:

Toolbar with buttons and icons
Our toolbar after adding buttons.

This already looks fantastic!

Setting up interaction with the buttons

Let's now add interaction. There are many ways of doing this, but I want to showcase some additional features. In gooey, can add arbitrary user data to any widget. We will use this to assign a tool index to each button, that corresponds to the tools array in the obj_Player object. We can do this with .setUserData like so:

Game / Draw GUI
    var _button = new UIButton("Button_Toolbar_dig", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][shovel]", dt_box_9slice_c_selected, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 0);
    _grid.addToCell(_button, 0, 0);

    var _button = new UIButton("Button_Toolbar_watering", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][water]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 1);
    _grid.addToCell(_button, 0, 1);

    var _button = new UIButton("Button_Toolbar_axe", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][axe]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 2);
    _grid.addToCell(_button, 0, 2);

    var _button = new UIButton("Button_Toolbar_plant", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][plant]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 3);
    _grid.addToCell(_button, 0, 3);

Once we have this, to achieve our two objectives:

  1. To allow buttons from dynamically reflecting the used tool, we will use .setPreRenderCallback; and
  2. To allow the player to click to select, we will use the button's .setCallback method, using the UI_EVENT.LEFT_RELEASE event.

In order to simplify code, I will create two methods, one for each of those objectives:

  • The first one will update the button sprite with the yellow border sprite, if the selected tool index corresponds with the button index, and it will set the default sprite if it doesn't. Using setPreRenderCallback for this is convenient, since we know this will run every frame, so we can set it and forget it.

  • The second method will set the obj_Player's current_tool variable to the button's tool_idx variable. We can then use this method as the callback for our left mouse button release event.

Let's take a look at these (I'll add them both before our buttons code):

Game / Draw GUI
    self.mark_selected = function() {
        var _sprite = obj_Player.current_tool == _button.getUserData("tool_idx") ? dt_box_9slice_c_selected : dt_box_9slice_c;
        _button.setSprite(_sprite);
    };

    self.set_tool = function() {
        obj_Player.current_tool = _button.getUserData("tool_idx");
    };

Note that these methods seem to use a variable which is not declared inside the function, _button. This is because will use a trick to bind these to each of our local _button variables using a closure. Let's take a look at how to use them:

Game / Draw GUI
    var _button = new UIButton("Button_Toolbar_dig", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][shovel]", dt_box_9slice_c_selected, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 0);
    _button.setPreRenderCallback(method({_button}, self.mark_selected));
    _button.setCallback(UI_EVENT.LEFT_RELEASE, method({_button}, self.set_tool));
    _grid.addToCell(_button, 0, 0);

    var _button = new UIButton("Button_Toolbar_watering", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][water]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 1);
    _button.setPreRenderCallback(method({_button}, self.mark_selected));
    _button.setCallback(UI_EVENT.LEFT_RELEASE, method({_button}, self.set_tool));
    _grid.addToCell(_button, 0, 1);

    var _button = new UIButton("Button_Toolbar_axe", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][axe]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 2);
    _button.setPreRenderCallback(method({_button}, self.mark_selected));
    _button.setCallback(UI_EVENT.LEFT_RELEASE, method({_button}, self.set_tool));
    _grid.addToCell(_button, 0, 2);

    var _button = new UIButton("Button_Toolbar_plant", 0, 0, 0, 0, "[fa_center][fa_middle][scale,3][plant]", dt_box_9slice_c, UI_RELATIVE_TO.MIDDLE_CENTER);
    _button.setInheritHeight(true).setInheritWidth(true).setSpriteClick(lt_box_9slice_c).setSpriteMouseover(lt_box_9slice_c);
    _button.setUserData("tool_idx", 3);
    _button.setPreRenderCallback(method({_button}, self.mark_selected));
    _button.setCallback(UI_EVENT.LEFT_RELEASE, method({_button}, self.set_tool));
    _grid.addToCell(_button, 0, 3); 

We can see that the code remains the same for all four buttons - this is because we are using the button tool_idx user data under the hood to do it.

The final result

With this, we have achieved our two objectives and we now have a fully functional toolbar!

The final toolbar
Our final toolbar. We can see that it graphically shows the selected tool when using the mouse wheel to toggle, and we can also click on any button to set the current tool directly.