Skip to content

Intro

Let us first create a basic HUD to show the time of day, money and quests.

Using gooey we will create non-resizable, non-movable panels that are positioned in the GUI layer, to display general stats about the game.

Re-importing gooey

Since the latest release had some modifications after the original inclusion in the base project file, we want to reimport gooey. Go ahead and follow the instructions to update it.

Showing the time of day

Our Draw GUI event in the Game controller currently includes this code that displays the hour of the day in the top right corner (and shows some arrows if the game time is currently being sped up, as described in the intro chapter of the game):

Game / Draw GUI
2
3
4
5
6
7
var _period = time_source_get_period(self.ts);

var _h = draw_get_halign();
draw_set_halign(fa_right);
draw_text_transformed(display_get_gui_width()-100, 20, string($"{_period == self.hour_length_frames_speedup ? ">>" : ""} {self.hour}"), 4, 4, 0);
draw_set_halign(_h);

Let's replace that with a gooey UIPanel. We will use ui_get to check if the panel exists before creating it (so it's only created once) and add a UIText element bound to the time of day variable. We will also use Flaticon's sensational day/night icon for displaying a nice graphical indicator. Finally, to lay it out easily, we will use a 1x3 UIGrid. For the moment, we will leave the middle cell (row 0 column 1) empty. Now, our Draw GUI event should look like so:

Game / Draw GUI
if (!ui_exists("Panel_TimeOfDay")) {
    var _panel = new UIPanel("Panel_TimeOfDay", -30, 30, 280, 150, glass_panel, UI_RELATIVE_TO.TOP_RIGHT);
    _panel.setResizable(false).setMovable(false).setDragBarHeight(0).setImageAlpha(0.6);

    var _grid = new UIGrid("Grid_TimeOfDay", 1, 3);
    _grid.setColumnProportions([0.5, 0.2, 0.3]);
    _panel.add(_grid);

    var _sprite = new UISprite("Sprite_TimeOfDay", 0, 0, day_and_night, 128, 128,,UI_RELATIVE_TO.MIDDLE_CENTER);
    _sprite.setUseNineSlice(false);
    _grid.addToCell(_sprite, 0, 0);

    var _txt = new UIText("Text_TimeOfDay", 0, 0, "", UI_RELATIVE_TO.MIDDLE_CENTER);
    var _fmt = "[scale,3][fnt_UI][fa_center]";
    _txt.setTextFormat(_fmt).setTextFormatMouseover(_fmt).setTextFormatClick(_fmt).setBinding(self, "hour");    
    _grid.addToCell(_txt, 0, 2);
}

Note that we could have also placed this in the Create (or similar) event, and avoid the ui_exists if check, which effectively creates the panel only once. In here, the if check will run every frame, but the underlying code will only run once (since the condition will only be true the first time), even though the Draw GUI event runs every frame.

Note also that there's no need to explicitly tell gooey to render the panels in the GUI event of any object (the included controller object does it by itself).

Since I'd like the icon to rotate depending on the time of day, I've set setUseNineSlice to false. I will add the following code to the time source update method advance_clock in the Create event of the Game controller:

Game / Create / spawn method
// Update GUI
if (ui_exists("Sprite_TimeOfDay")) {
    var _angle = self.hour/24 * 360 - 90;
    ui_get("Sprite_TimeOfDay").setAngle(_angle);
}

I want to also substitute the crappy > indicator with a proper icon. I only want to show the icon if the time is being sped up (remember you can press spacebar to toggle time speedup. There's a couple of ways of doing this: one would be to draw a sprite and then dynamically set its visibility property to true or false depending on the value of the time source that handles the time of day; the other is to draw a text and bind it to a method that returns an inline icon or empty string depending on said variable. Let's do the second one, adding a method to the Game controller:

Game / Create
self.progress_indicator = function() {
    var _period = time_source_get_period(self.ts);
    return (_period == self.hour_length_frames_speedup) ? "[arrow_right]" : "";
}

(note that arrow_right is the name of the sprite and that we're using Scribble syntax to show the icon inline). Now that we have this method, we can add the UIText element to our gooey grid in the (0,1) position:

Game / Draw GUI
    var _txt = new UIText("Text_AcceleratedTime", 0, 0, "", UI_RELATIVE_TO.MIDDLE_CENTER);
    var _fmt = "[scale,2][fnt_UI][fa_center]";
    _txt.setTextFormat(_fmt).setTextFormatMouseover(_fmt).setTextFormatClick(_fmt).setBinding(self, "progress_indicator");  
    _grid.addToCell(_txt, 0, 1);

Now we can see that the HUD shows the time of day, the day/night icon rotates, and if we're accelerating time we can see a right arrow icon being displayed next to the hour!

Displaying money

Currently, the game does not reward the player with anything when completing a quest. For added sense of progression, let's also make it so the NPC quest giver rewards the player with 10 coins whenever they complete a quest. For this, we will hastly create a money variable in the player object and update it each time the player completes a quest by delivering the goods to the NPC:

obj_Player / Create
self.money = 0;
obj_NPC / Create
obj_Player.money += 10;

Now that we have this, we can add another panel to our HUD to show how much money do we have. Let's use the same idea than the other panel, but bind the text variable to the obj_Player's money variable:

Game / Draw GUI
    if (!ui_exists("Panel_Money")) {
        var _panel = new UIPanel("Panel_Money", 30, 30, 280, 150, glass_panel);
        _panel.setResizable(false).setMovable(false).setDragBarHeight(0).setImageAlpha(0.6);

        var _grid = new UIGrid("Grid_Money", 1, 2);
        _grid.setColumnProportions([0.6,0.4]);
        _panel.add(_grid);

        var _txt = new UIText("Text_Money", 0, 0, "", UI_RELATIVE_TO.MIDDLE_CENTER);
        var _fmt = "[scale,3][fnt_UI][fa_right]";
        _txt.setTextFormat(_fmt).setTextFormatMouseover(_fmt).setTextFormatClick(_fmt).setBinding(obj_Player, "money");

        _grid.addToCell(_txt, 0, 1);

        var _sprite = new UISprite("Sprite_Money", 0, 0, itemdisc_01, sprite_get_width(itemdisc_01)*2, sprite_get_height(itemdisc_01)*2,,UI_RELATIVE_TO.MIDDLE_CENTER);
        _grid.addToCell(_sprite, 0, 0);
    }

Fantastic! If we complete one of the quests of the NPC, we can see that the money indicator increases as expected.

Displaying the current quest

When we interact with the NPC, they give us a quest. However, this is displayed in horrendous plain text on screen, and disappears after a couple of seconds. Let's instead add a HUD element that can appear whenever a quest is assigned, disappears whenever we complete the quest, and can quickly remind us of what the quest is about.

Let's do this with a panel, that we can name Panel_Quest, and do the following:

  • We can set its title to "Current Quest"
  • For each item, we can use Scribble inline sprites to display the icon and then the quantity needed
  • If there is no active quest, we can clear these and hide the panel with setVisible

Let's work through that. First, let's create the panel below the time of day one and set a placeholder text. We can also directly set a pre-render callback to set its visibility depending on whether there is an active quest:

Game / Draw GUI
    if (!ui_exists("Panel_Quest")) {
        var _dim = ui_get("Panel_TimeOfDay").getDimensions();
        var _y = _dim.y + _dim.height + 30;
        var _panel = new UIPanel("Panel_Quest", -30, _y, 280, 200, glass_panel, UI_RELATIVE_TO.TOP_RIGHT);
        _panel.setResizable(false).setMovable(false).setDragBarHeight(0).setImageAlpha(0.9).setTitle("Current Quest").setTitleFormat("[fnt_UI][scale,2][fa_top]");

        var _txt = new UIText("Text_Quest", 50, 50, "");
        var _fmt = "[fnt_UI][fa_left][fa_top]";
        _txt.setTextFormat(_fmt).setTextFormatMouseover(_fmt).setTextFormatClick(_fmt);
        _panel.add(_txt);

        _panel.setPreRenderCallback(function() {
            ui_get("Panel_Quest").setVisible(obj_NPC.quest != undefined);
        })
    }

After that, we can just set the text whenever the NPC assigns the quest, constructing a Scribble string with inline sprites. We can also comment the two lines that currently display the ugly text on screen:

obj_NPC / Create / process_quest method
    var _txt = "";
    repeat (_num_things) {
        // NOTE: not showing the lines that actually generate the quest
        _txt += string($"[scale,3][c_white][{_sprite}][scale,2][#eeeeee] x{_qty}\n");
    }

    //self.quest_message = string($"Here's a quest, can you bring me:\n{self.quest}");
    //self.alarm[0] = _msg_time;

    ui_get("Text_Quest").setText(_txt, true);

The final result

We're done! Our final HUD should look like this:

Our HUD made with gooey
The game HUD after creating it with gooey.