Create a Shop (UI)

In this lesson, we are making a User Interface (UI) that shows a button to buy a cool hat for your player. This lesson is focusing on the Client part, the next part is about the networking to remove the Coins and spawn the Hat in the Server Context.

The steps that we are going to take are:

  1. Create the UI Container and the basic UI of your shop
  2. Create a button with an image and a text
  3. Connect the button in a script to detect when the player clicks on it
  4. Send an event to show and hide the shop from the Seller script we made in the previous lesson

As this Shop is a system on its own that will have a script in the Server Context to remove the resources and spawn the object, it will also have a Client Context with the UI and a script to manage that. We are making a new group called Shop that will contain all this logic.

Create UI

To create a UI, you always need the same basic elements:

  1. Create a ClientContext (here, the ClientContext is added inside our Shop group to keep the Hierarchy organised).
  2. Create a UI Container inside the Client Context: this is mandatory to add a user interface in your game.
  3. Create a UI Panel that will be the panel containing the shop. A panel is an easy way to organize your UI with a basic element that has a size and a position.
  4. Change the Dock and the Anchor of this UI Panel to “Middle Center” to align and attach everything in the center of the screen.
  5. Create a UI Image and check the Inherit Parent Width and Height properties to have a background that follows the size of the Panel.
  6. Change the size of the panel and the background should be resized automatically.
Settings of the Background UI Image
Default UI with a panel and a background
Hierarchy

Add a UI Text next to the UI Image with the text Shop. Change the properties of the UI Text to match the following screenshot.

Note: Rename the component of your UI to find elements faster.
Shop Interface
Hierarchy after renaming the image and the text

Create a UI Button

If you press play, you will have the shop UI on your game but you can’t interact with it. The easiest way to interact with the UI is to add UI Button. An event is fired when the player clicks on a button. Before diving into the code, let’s create that button to buy a cool hat.

  1. Create a UI Button as a child of the UI Panel. rename it BuyHatButton so it is easier to find it.
  2. Add a UI Image of a hat and a UI Text with the text “Buy Hat (3 coins)”.
Hierarchy after creating the button
Place the BuyHatButton in the Shop UI
UI after placing the image and the text
Properties of the Hat UI Image
Hierarchy of the Shop UI

Connect the button

Your button is created but you still can’t interact with it when pressing Play because you need a script to explicitly say that you want to use your cursor to interact with the UI. You also want to detect when the player interacts with the button.

  1. Create a script called UIShop and place it just above your UI Container, in the Client Context.
  2. Select the script and drag & drop the BuyHatButton from the Hierarchy in the Custom Property.
  3. Double click on the script to open it and paste this code:
local BUYHAT_BUTTON = script:GetCustomProperty("BuyHatButton"):WaitForObject()

-- Show the cursor and set the UI interactable
UI.SetCursorVisible(true)
UI.SetCanCursorInteractWithUI(true)

function OnBuyHat(button)
    print("Clicked on Hat")
end
BUYHAT_BUTTON.clickedEvent:Connect(OnBuyHat)Code language: Lua (lua)

This script has two lines to show the cursor and to enable the cursor to interact with the UI at the top. There is also a variable BUYHAT_BUTTON that is a reference to the BuyHatButton of our Hierarchy. UI Buttons have an event called clickedEvent that is fired when the player clicks on a button. The script is writing in the Event Log window when the player clicks on the hat. Try it out by yourself!

Now that we can detect when the player clicks, we need to look at the current amount of resources using the GetResource function. To use this function, we need a reference to the player but as we are in a Client Context, we can use Game.GetLocalPlayer() to get that reference. If the value is lower than 3, the function prints an error and returns to stop the execution here. If the player has more than 3 Coins, then we print “Just bought a hat”. This is where we are going to add the Broadcast to the server in the next lesson.

local BUYHAT_BUTTON = script:GetCustomProperty("BuyHatButton"):WaitForObject()

-- Show the cursor and set the UI interactable
UI.SetCursorVisible(true)
UI.SetCanCursorInteractWithUI(true)


local PLAYER = Game.GetLocalPlayer()

function OnBuyHat(button)
    if PLAYER:GetResource("Coins") < 3 then
        print("Not enough coins")
        return
    end
    print("Just bought a hat")
    -- Here we need to send the information to the server
    -- Only the server can remove resources and spawn the equipment
end
BUYHAT_BUTTON.clickedEvent:Connect(OnBuyHat)Code language: Lua (lua)

Toggle UI with an event

Using the previous script, the shop is always visible. When starting the game, we want the UI Container to be hidden, and to be displayed only when the player is next to the NPC. Let’s update our script:

  1. To show and hide the UI Container, we need to have a reference to it so we need to create a new Custom Property called UIContainer. Once we have this reference to the UI Container, we are using the visibility property to hide it.
  2. Under the button logic, we add a new function ToggleUI that takes a boolean as parameter (true or false). This function is also changing the visibility of the cursor and the fact that the cursor can interact with the UI. We removed those two lines from the beginning of the script as it is off by default, and the UI is not visible.
  3. Add the Events.Connect function to call the ToggleUI function when the ToggleShop event is triggered in the game. This event can be triggered from any other script of the Client Context using Events.Broadcast(“ToggleShop”, true) or Events.Broadcast(“ToggleShop”, false)
local BUYHAT_BUTTON = script:GetCustomProperty("BuyHatButton"):WaitForObject()
local UI_CONTAINER = script:GetCustomProperty("UIContainer"):WaitForObject()

-- Hide the container when starting the game
UI_CONTAINER.visibility = Visibility.FORCE_OFF

local HAT_PRICE = 3

local PLAYER = Game.GetLocalPlayer()

function OnBuyHat(button)
    if PLAYER:GetResource("Coins") < HAT_PRICE then
        print("Not enough coins")
        return
    end
    print("Just bought a hat")
    -- Here we need to send the information to the server
    -- Only the server can remove resources and spawn the equipment
end
BUYHAT_BUTTON.clickedEvent:Connect(OnBuyHat)

-- This function show and hide the UI
-- Triggered when another script send the "ToggleShop" event
function ToggleUI(show)
    if show then
        UI_CONTAINER.visibility = Visibility.INHERIT
    else
        UI_CONTAINER.visibility = Visibility.FORCE_OFF
    end
	
    -- Here, we are using show as this value equals true or false
    UI.SetCursorVisible(show)
    UI.SetCanCursorInteractWithUI(show)
end
Events.Connect("ToggleShop", ToggleUI)Code language: Lua (lua)

AnimateSeller Script

This is the new version of the AnimateSeller script with the broadcast of the event “ToggleShop”. This event is fired:

  • In the OnBeginOverlap with the parameter “true” to show the UI when the player enters the Trigger
  • At the end of the code inside the endOverlapEvent to hide the shop when the player leaves the Trigger.

This event is broadcasted using the Broadcast function, so it will stay in the current context (the Client Context in this example). All the scripts that are in the Client Context and that are listening to this event are going to receive it.

local TRIGGER = script.parent
local NPC = script:GetCustomProperty("NPC"):WaitForObject()

function OnBeginOverlap(trigger, other)
    if not other:IsA("Player") then return end
	
    if other ~= Game.GetLocalPlayer() then return end
	
    NPC:LookAt(other:GetWorldPosition())
    NPC:PlayAnimation("unarmed_wave")
	
    -- Line added here to send an event to the UIShop script, asking to show the UI
    Events.Broadcast("ToggleShop", true)
end
TRIGGER.beginOverlapEvent:Connect(OnBeginOverlap)

-- When the player leaves  the trigger, send an event to hide the UI
TRIGGER.endOverlapEvent:Connect(function(trigger, other)
    Events.Broadcast("ToggleShop", false)
end)Code language: Lua (lua)
The UI is displayed when the NPC waves at the player

Note: If you want to work on the rest of your game, your UI is currently always in the center of your screen. To hide it, you can click on the eye on the right of the Client Context to hide it only in the editor.
4 Comments
Collapse Comments

the code provided gives us an “attempt to index a nil value error. Is there a fix for this?

I can’t see the text while typing so please excuse the errors.

We (mostly my students) found an answer. “UIContainer” needs a space. UI Container fixed the error.

I had the same problem, thanks.

Leave a Comment

Scroll to Top