Need help creating a GUI with responsive purchase buttons

Hello! I am new to the Roblox Dev forum and getting my feet wet with some GUI scripting. I am looking to create a system with interactive purchase buttons.

The issue is that I want these buttons to go from being the purchase label to saying equip and unequip. For my game, you can only have one item in your inventory at a time (that part I have had no issue creating and it works great.) but I want the GUI to reflect that with what item you have equipped.

I’ve tried tactics such as returning a Boolean value in my remote function to alter the buttons and currently believe I have a system going where the already purchased buttons get filtered into their own table and then from that table I want to decide, “If X button is clicked, make it say equipped and make all the other ones says unequipped.”

Again, I may be biting off a bit more than I can chew as an newbie scripter, but it’s something I’ve been taking day by day to understand! Below I have listed the scripts.

This is the server script and what controls the items actually going into the inventory. I don’t believe there’s anything here that would contribute to the solution.

local replicatedStorage = game:GetService("ReplicatedStorage")
local buyEvent = replicatedStorage:WaitForChild("BuyEvent")
local itemFolder = replicatedStorage:WaitForChild("Items")

buyEvent.OnServerInvoke = function(player, buttonPress, buyValue) --Sends values from client button press to the server
	
	local character = player.Character
	local humanoid = character:FindFirstChildOfClass("Humanoid")
	local leaderstats = player.leaderstats
	local points = leaderstats.Points
	local clonedItem = itemFolder:WaitForChild(buttonPress.Name)
	local playerItemsFolder = player:WaitForChild("Player Items")
	
	if not player.Backpack:FindFirstChild(buttonPress.Name) then --If the item is not in the backpack or Player Items Folder, we will begin the purchase.
		if not playerItemsFolder:FindFirstChild(buttonPress.Name) then --If the item is not in the Player Items Folder, they don't own it!
			if points.Value >= buyValue then --If the player then has enough points to buy the item, lets give it to them!
				points.Value -= buyValue --Subtracts points based on the value of the item.
				humanoid:UnequipTools() --Avoids the annoying quirk that is equipped tools moving to the workspace.
				player.Backpack:ClearAllChildren()
				clonedItem:Clone().Parent = playerItemsFolder --Clones it into the Player Items Folder for data storage.
				clonedItem:Clone().Parent = player.Backpack --Clones it into the backpack for use!
			else
			end
		else
			humanoid:UnequipTools() --Avoids the annoying quirk that is equipped tools moving to the workspace.
			player.Backpack:ClearAllChildren()
			clonedItem:Clone().Parent = player.Backpack --If they already own the item but don't have it equipped, equip it!
		end
	else
		if clonedItem then --If the cloned item is found in the player's backpack, then remove it!
			player.Backpack[buttonPress.Name]:Destroy() --Item is destroyed or, "un-equipped"
		end
	end
end

Here is the local shop GUI script. What I am attempting to do is filter the purchased items into a separate table that can then be looped through and my idea is one item gets set to equipped while everything else being looped through the table gets set to unequipped.

local replicatedStorage = game:GetService("ReplicatedStorage")
local buyEvent = replicatedStorage:WaitForChild("BuyEvent")
local player = game.Players.LocalPlayer
local playerItemsFolder = player:FindFirstChild("Player Items")
local shopGui = script.Parent
local shopFrame = shopGui:WaitForChild("ShopFrame")
local itemFrames = shopFrame:GetDescendants()
local buttonTable = {}
local purchasedButtonsTable = {}

for _, buttons in pairs(itemFrames) do
	if buttons:IsA("IntValue") then
		table.insert(buttonTable, buttons.Parent)
	end
end

for i, buttonPress in pairs(buttonTable) do
	
	buttonPress.MouseButton1Click:Connect(function()
		
		local selectedButton = buttonPress.Name
		local purchasedTag = buttonPress.Bought.Value
		local buyValue = buttonPress.Price.Value
		local purchaseOutcome = buyEvent:InvokeServer(buttonPress, buyValue)
		
		--print(selectedButton)
		if purchasedTag == false then --If items has not been purchased yet run this
			if playerItemsFolder:FindFirstChild(buttonPress.Name) then --If item is in Player Items folder we know they own it already 
				purchasedTag = true --Set the ownership tag to true
				if not table.find(purchasedButtonsTable, buttonPress.Name) then --If this item is not in the purchased table yet, add it there.
					table.insert(purchasedButtonsTable, buttonPress.Name) --Item is added to list of purchased items.
				end
			end	
		end
		for i, itemCheck in pairs(purchasedButtonsTable) do
							--I think something has to happen here.
			print("Looped")
		end
		print(purchasedButtonsTable)
	end)
end

Again, imagine that after clicking a button and purchasing it, the prompt becomes equipped/unequipped and if I equip one tool it says equipped for it and says unequipped for all of the others.


I feel like I’m quite close to the solution but just need a little extra push, or I may need to completely rethink my approach I’m open any and all ideas!

You are pretty close to the answer, infact your super close

for i, itemCheck in pairs(purchasedButtonsTable) do
	itemcheck.textlabel.Text = "Unequipped"
	print("Looped")
end

if table.find(purchasedButtonsTable, buttonPress.Name) then
buttonPress.textlabel.Text = "Equipped"
end

Basically, what I’m doing is looping through all the owned purchased weapons and then set their text into unequipped, afterwards I just if the player owns the weapon he just attempted to equip

If he does own it, then the text will change into Equipped instead

Now you could also add more functionality like change the font, or text color

Hope this helped!

When I attempted to click the button to change the text to unequipped, this error showed up:


When I commented out the for loop and tried just table.find this showed up as well:

This method seems like it should work and that’s what is confusing me so much. I know the answer is right there.

I believe you’re storing names (as strings) in purchasedButtonsTable, so when you do itemCheck.TextLabel, you’re indexing a string instead of a GUI object, you wanna store the button instances not their names if you wanna do it this way

Interesting. I had a slight feeling something like that was happening. How would I go about indexing the actual GUI element itself instead of just a string with the same name?

Change:
table.insert(purchasedButtonsTable, buttonPress.Name)
to
table.insert(purchasedButtonsTable, buttonPress)

Index like this:

for _, btn in ipairs(purchasedButtonsTable) do
    -- btn is the gui element
    -- Example: btn.TextLabel.Text
end

Oh wow! The answer was right in front of me the whole time but since I was using the Name of the GUI and not the GUI itself it wasn’t going anywhere!

I have one last question and hopefully it’s a small fix. Whenever I’ve selected an item that I’ve bought but then click on a purchase and the purchase fails, it sets all of the tags to say, “unequipped.”

Here is the newly written script if you want to take a look at it.

local replicatedStorage = game:GetService("ReplicatedStorage")
local buyEvent = replicatedStorage:WaitForChild("BuyEvent")
local player = game.Players.LocalPlayer
local playerItemsFolder = player:FindFirstChild("Player Items")
local shopGui = script.Parent
local shopFrame = shopGui:WaitForChild("ShopFrame")
local itemFrames = shopFrame:GetDescendants()
local buttonTable = {}
local purchasedButtonsTable = {}

for _, buttons in pairs(itemFrames) do
	if buttons:IsA("IntValue") then
		table.insert(buttonTable, buttons.Parent)
	end
end

for i, buttonPress in pairs(buttonTable) do

	buttonPress.MouseButton1Click:Connect(function()

		local selectedButton = buttonPress.Name
		local purchasedTag = buttonPress.Bought.Value
		local buyValue = buttonPress.Price.Value
		local purchaseOutcome = buyEvent:InvokeServer(buttonPress, buyValue)

		--print(selectedButton)
		if purchasedTag == false then --If items has not been purchased yet run this
			if playerItemsFolder:FindFirstChild(buttonPress.Name) then --If item is in Player Items folder we know they own it already 
				purchasedTag = true --Set the ownership tag to true
				if not table.find(purchasedButtonsTable, buttonPress) then --If this item is not in the purchased table yet, add it there.
					table.insert(purchasedButtonsTable, buttonPress) --Item is added to list of purchased items.
				end
			end	
		end
		for _, btn in pairs(purchasedButtonsTable) do
			btn.Text = "Unequipped"
			btn.TextColor3 = Color3.fromRGB(255, 0, 0)
		end
		if table.find(purchasedButtonsTable, buttonPress) then
			buttonPress.Text = "Equipped"
			buttonPress.TextColor3 = Color3.fromRGB(0, 255, 0)
		end
		print(buttonPress)
	end)
end

Thanks again!

You’re updating all the buttons to say “Unequipped” even if the purchase fails. You’re doing that part before checking if purchaseOutcome actually succeeded. You should only run that block if the purchase was confirmed by the server.

Just wrap the tag-updating part in here:

if purchaseOutcome then
    for _, btn in pairs(purchasedButtonsTable) do
        btn.Text = "Unequipped"
        btn.TextColor3 = Color3.fromRGB(255, 0, 0)
    end

    if table.find(purchasedButtonsTable, buttonPress) then
        buttonPress.Text = "Equipped"
        buttonPress.TextColor3 = Color3.fromRGB(0, 255, 0)
    end
end

That way nothing visually changes unless the purchase actually goes through.

In fact, here you go. Your code should look like this:

local replicatedStorage = game:GetService("ReplicatedStorage")
local buyEvent = replicatedStorage:WaitForChild("BuyEvent")
local player = game.Players.LocalPlayer
local playerItemsFolder = player:FindFirstChild("Player Items")
local shopGui = script.Parent
local shopFrame = shopGui:WaitForChild("ShopFrame")
local itemFrames = shopFrame:GetDescendants()
local buttonTable = {}
local purchasedButtonsTable = {}

for _, buttons in pairs(itemFrames) do
	if buttons:IsA("IntValue") then
		table.insert(buttonTable, buttons.Parent)
	end
end

for _, buttonPress in pairs(buttonTable) do
	buttonPress.MouseButton1Click:Connect(function()
		local selectedButton = buttonPress.Name
		local purchasedTag = buttonPress.Bought.Value
		local buyValue = buttonPress.Price.Value

		local purchaseOutcome = buyEvent:InvokeServer(buttonPress, buyValue)

		-- If the player owns it already
		if not purchasedTag and playerItemsFolder:FindFirstChild(selectedButton) then
			purchasedTag = true
			if not table.find(purchasedButtonsTable, buttonPress) then
				table.insert(purchasedButtonsTable, buttonPress)
			end
		end

		-- Update UI only if purchase succeeded or item is already owned
		if purchaseOutcome or playerItemsFolder:FindFirstChild(selectedButton) then
			for _, btn in pairs(purchasedButtonsTable) do
				btn.Text = "Unequipped"
				btn.TextColor3 = Color3.fromRGB(255, 0, 0)
			end

			if table.find(purchasedButtonsTable, buttonPress) then
				buttonPress.Text = "Equipped"
				buttonPress.TextColor3 = Color3.fromRGB(0, 255, 0)
			end
		else
			warn("Purchase failed or was canceled")
		end
	end)
end

Didn’t test it so let me know if that works.

Yep! Those changes worked! Man if only I had known I was referencing the button name and not the button itself in the first place I would have been over with this much sooner ha.

Thanks!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.