How do you create a badge index gui in-game?

I’m trying to make a badge index GUI in-game that shows the badges you achieved and the badges you still haven’t achieved too, where the badges you achieved will have a green background color indicating you already found them and the badges you haven’t achieved yet will just have a grey/no background color indicating that they still need to be found.

I also want to make it so that you can click on the badge image from the badge index and it views a hint on how to get it and what area of the map it can be found in.

The best example that has a badge index GUI is this game:

https://www.roblox.com/games/7768149183/238-Find-The-Trollfaces

or this game too: https://www.roblox.com/games/7896264844/Find-the-Markers-151

I’m trying to make a badge index GUI exactly or almost the same as the one in the games mentioned above or any other of the “Find The…” games.

Can anyone please walk me through step by step how to make this badge index GUI?

(I’m a beginner sorry if I ask a lot!)

Thank you very much!

5 Likes

badgechecker.rbxl (41.9 KB)

image

I made something like this recently.

There’s a lot of steps involved.

5 Likes

Do you have a view for the date/time of when someone got the badge on that gui?

1 Like

Not exactly what I had in mind, but this looks really cool! Do you mind explaining to me how I can work with it? (If you allow me to use it in the first place of course)

1 Like

Great idea, I decided to create an entirely new system & gui to achieve that.

badges.rbxl (43.5 KB)

image

This seldomly used API endpoint proved its usefulness.
https://badges.roblox.com/v1/users/{userId}/badges/awarded-dates/{badgeIds}

--SERVER

local players = game:GetService("Players")
local replicated = game:GetService("ReplicatedStorage")
local badgeRemote = replicated.BadgeRemote
local http = game:GetService("HttpService")
local getAsync = http.GetAsync
local jsonDecode = http.JSONDecode
local urlEncode = http.UrlEncode

local proxy = "roproxy.com"
local badgesUrl = "https://badges.%s/v1/universes/%s/badges?limit=100&sortOrder=Asc&cursor=%s"
local badgeTimestampsUrl = "https://badges.%s/v1/users/%s/badges/awarded-dates?badgeIds=%s"

local playerDebounces = {}
local badgeIds

local function getBadgesRecursive(cursor, badges, retries)
	cursor = cursor or ""
	badges = badges or {}
	retries = retries or 0
	if retries >= 10 then return {} end
	
	local requestUrl = badgesUrl:format(proxy, game.GameId, cursor)
	local success, result = pcall(getAsync, http, requestUrl)
	if success then
		if result then
			local success2, result2 = pcall(jsonDecode, http, result)
			if success2 then
				if result2 then
					for _, badgeItem in ipairs(result2.data) do
						table.insert(badges, badgeItem.id)
					end
					
					cursor = result2.nextPageCursor
					if cursor then
						return getBadgesRecursive(cursor, badges, retries)
					else
						return badges
					end
				end
			else
				task.wait()
				warn(result2)
				retries += 1
				return getBadgesRecursive(cursor, badges, retries)
			end
		end
	else
		task.wait()
		warn(result)
		retries += 1
		return getBadgesRecursive(cursor, badges, retries)
	end
end

local function getBadgeTimestampsRecursive(userId, pageIndex, timestamps, retries)
	pageIndex = pageIndex or 1
	timestamps = timestamps or {}
	retries = retries or 0
	if retries >= 10 then return {} end
	
	local badgeList = ""
	for badgeIndex = ((pageIndex - 1) * 100) + 1, math.min(#badgeIds, pageIndex * 100) do
		badgeList..=badgeIds[badgeIndex]..","
	end
	badgeList = badgeList:gsub(",$", "")

	local success, result = pcall(urlEncode, http, badgeList)
	if success then
		if result then
			local requestUrl = badgeTimestampsUrl:format(proxy, userId, result)
			local success2, result2 = pcall(getAsync, http, requestUrl)
			if success2 then
				if result2 then
					local success3, result3 = pcall(jsonDecode, http, result2)
					if success3 then
						if result3 then
							for _, badgeTimestamp in ipairs(result3.data) do
								timestamps[badgeTimestamp.badgeId] = badgeTimestamp.awardedDate
							end

							if pageIndex <= #badgeIds/100 then
								pageIndex += 1
								return getBadgeTimestampsRecursive(userId, pageIndex, timestamps, retries)
							else
								return timestamps
							end
						end
					else
						task.wait()
						warn(result3)
						retries += 1
						return getBadgeTimestampsRecursive(userId, pageIndex, timestamps, retries)
					end
				end
			else
				task.wait()
				warn(result2)
				retries += 1
				return getBadgeTimestampsRecursive(userId, pageIndex, timestamps, retries)
			end
		end
	else
		task.wait()
		warn(result)
		retries += 1
		return getBadgeTimestampsRecursive(userId, pageIndex, timestamps, retries)
	end
end

local function onBadgeRemoteFired(player)
	repeat task.wait() until badgeIds
	if tick() - (playerDebounces[player] or 0) <= 20 then return end
	playerDebounces[player] = tick()
	local badgeTimestamps = getBadgeTimestampsRecursive(player.UserId)
	badgeRemote:FireClient(player, badgeTimestamps)
end

local function onPlayerAdded(player)
	repeat task.wait() until badgeIds
	local badgeTimestamps = getBadgeTimestampsRecursive(player.UserId)
	badgeRemote:FireClient(player, badgeTimestamps, badgeIds)
end

badgeRemote.OnServerEvent:Connect(onBadgeRemoteFired)
players.PlayerAdded:Connect(onPlayerAdded)
badgeIds = getBadgesRecursive()
--LOCAL

local tweens = game:GetService("TweenService")
local badges = game:GetService("BadgeService")
local getBadgeInfoAsync = badges.GetBadgeInfoAsync
local replicated = game:GetService("ReplicatedStorage")
local badgeRemote = replicated:WaitForChild("BadgeRemote")

local badgesGui = script.Parent
local badgesFrame = badgesGui:WaitForChild("BadgesFrame")
local reloadButton = badgesFrame:WaitForChild("ReloadButton")
local badgesList = badgesFrame:WaitForChild("BadgesList")
local badgeFrameTemplate = script:WaitForChild("BadgeFrame")
local toggleButton = badgesGui:WaitForChild("ToggleButton")

local guiToggle = true
local reloadToggle = true

local function onBadgeRemoteFired(badgeTimestamps, badgeIds)
	if badgeIds then
		for _, badgeId in ipairs(badgeIds) do
			local success, result = pcall(getBadgeInfoAsync, badges, badgeId)
			if success then
				if result then
					local badgeFrame = badgeFrameTemplate:Clone()
					badgeFrame.Name = badgeId.."Frame"
					badgeFrame.BadgeName.Text = result.Name
					badgeFrame.BadgeImage.Image = "rbxassetid://"..result.IconImageId
					local badgeTimestamp = badgeTimestamps[tostring(badgeId)]
					if badgeTimestamp then
						badgeFrame.LayoutOrder = 1
						badgeFrame.BadgeDate.Text = badgeTimestamp:match("^(%d+%-%d+%-%d+)T")
						badgeFrame.BadgeTime.Text = badgeTimestamp:match("T(%d+:%d+:%d+)%.")
						badgeFrame.BadgeCheckImage.Image = "rbxassetid://9038877993"
					else
						badgeFrame.BadgeCheckImage.Image = "rbxassetid://9038877823"
					end
					badgeFrame.Parent = badgesList
				end
			end
		end
		reloadButton.Image = "rbxassetid://9082930345"
		reloadToggle = false
	else
		for _, badgeFrame in ipairs(badgesList:GetChildren()) do
			if badgeFrame:IsA("Frame") then
				local badgeId = badgeFrame.Name:gsub("Frame", "")
				local badgeTimestamp = badgeTimestamps[badgeId]
				if badgeTimestamp then
					badgeFrame.LayoutOrder = 1
					badgeFrame.BadgeDate.Text = badgeTimestamp:match("^(%d+%-%d+%-%d+)T")
					badgeFrame.BadgeTime.Text = badgeTimestamp:match("T(%d+:%d+:%d+)%.")
					badgeFrame.BadgeCheckImage.Image = "rbxassetid://9038877993"
				else
					badgeFrame.LayoutOrder = 0
					badgeFrame.BadgeDate.Text = "Date: N/A"
					badgeFrame.BadgeTime.Text = "Time: N/A"
					badgeFrame.BadgeCheckImage.Image = "rbxassetid://9038877823"
				end
			end
		end
	end
end

local function onToggleButtonClicked()
	guiToggle = not guiToggle
	local guiPosition = if guiToggle then 0.025 else -0.2
	toggleButton.Text = if guiToggle then "<\n<\n<" else ">\n>\n>"
	local tween = tweens:Create(badgesFrame, TweenInfo.new(0.3, Enum.EasingStyle.Linear, Enum.EasingDirection.Out), {Position = UDim2.fromScale(guiPosition, 0.5)})
	tween:Play()
	tween.Completed:Wait()
end

local function onReloadButtonClicked()
	if reloadToggle then return end
	reloadToggle = not reloadToggle
	reloadButton.Image = "rbxassetid://9083079276"
	badgeRemote:FireServer()
	task.wait(20)
	reloadButton.Image = "rbxassetid://9082930345"
	reloadToggle = false
end

toggleButton.MouseButton1Click:Connect(onToggleButtonClicked)
reloadButton.MouseButton1Click:Connect(onReloadButtonClicked)
badgeRemote.OnClientEvent:Connect(onBadgeRemoteFired)
3 Likes

I don’t see a list to put the badge IDs to be checked.
This is what I see in-game, empty GUI?
(I haven’t made a badge for this place.
But is it possible to check badges for other people’s games with this?)
Tested in a place with badges, it does still show up empty like the image below.

1 Like

It automatically gets the current game’s badges. You likely have HTTP requests disabled or some other issue at hand. Working fine on my end, as you can see below.

image

Any way of getting another games badge list to check for all the badges there?
Also any way of adding a search for roblox user ID to the box, to see someones badges?