How to make a badge list

Please look at this post: How to make a badge list - #22 by TheH0meLands

Hello! So recently i’ve seen a tonn of badge list type posts in #help-and-feedback:scripting-support . So today, i’m going to show u how to make it!

First, we need to create our UI.

So inside starter gui, create a screen gui, then create a frame inside the screen ui. Make the frame nice and big, something like this will do:

Once you make the frame, name it “Holder” and add a Ui grid instance into it. This will allow us to create a grid ui for our badges.

Next, create a new frame and name it the badge’s name. For this i’ll name it “Welcome Badge”

Inside that frame, create a text label and set it’s size to “{1, 0},{0.2, 0}”. This will be the badge name. Change the name of the textlabel to “BadgeName” and set the text to “???”. That’s what will display to the people who dont own the badge

Once you make the name text, create a new image label and set it to a random image.

The size of this will be {1, 0},{0.8, 0} and the position will be {0, 0},{0.2, 0}. Set the image color to 0,0,0. This is so our image has a silhouette effect.


This is my UI if you want to copy it:

Now that we’ve gotten our ui, we can start scripting!

scripting

Create a local script inside of StarterPlayerScripts and name it “BadgelistScript”.

First, lets make an array which will store our badges.

Since i’ll only have 1 badge, i’ll have one badge data table. You can add as many as you want.

local badgeService = game:GetService("BadgeService")
local badges = {
	[1] = {
		["name"] = "Badge1", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "SBS welcome badge", -- change to the name of the badge
		['id'] = 174605507 -- change to badge id
	}
}

Next, we’ll need to check if the player owns the badge:

local badgeService = game:GetService("BadgeService")
local players = game:GetService("Players")

local player = players.LocalPlayer

local badges = {
	[1] = {
		["name"] = "Badge1", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "SBS welcome badge", -- change to the name of the badge
		['id'] = 174605507 -- change to badge id
	}
}

for _, data in ipairs(badges) do
	local badgeId = data.id
	local badgeName = data.displayName
	local frameName = data.name
	if badgeService:UserHasBadgeAsync(player.UserId, badgeId) then
		-- TODO: display that user owns badge
	else
		-- TODO: display that user DOESN't owns badge
	end
end

Now that we check this, we need to display that the user owns/doesn’t own the badge. To do this, we can add the following code:

local badgeService = game:GetService("BadgeService")
local players = game:GetService("Players")

local player = players.LocalPlayer

local badgesHolder = player.PlayerGui:WaitForChild("BadgeUi"):WaitForChild("Holder")

local badges = {
	[1] = {
		["name"] = "Badge1", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "SBS welcome badge", -- change to the name of the badge
		['id'] = 174605507 -- change to badge id
	}
}

for _, data in ipairs(badges) do
	local badgeId = data.id
	local badgeName = data.displayName
	local frameName = data.name
	
	local frameInstance = badgesHolder:FindFirstChild(frameName)
	if not frameInstance then warn(string.format("Could not find badge frame with name of %s", frameName)) continue end
	local badgeNameInstance = frameInstance:WaitForChild("BadgeName")
	local badgeIconInstance = frameInstance:WaitForChild("BadgeIcon")
	local success, ownsBadge = pcall(function()
		return badgeService:UserHasBadgeAsync(player.UserId, badgeId)
	end)
	if success and ownsBadge  then
		
		badgeIconInstance.ImageColor3 = Color3.fromRGB(255, 255, 255)
		badgeNameInstance.Text = badgeName
	else
		badgeIconInstance.ImageColor3 = Color3.fromRGB(0, 0, 0)
		badgeNameInstance.Text = "???"
	end
end

Since I own the badge, it’ll display like this:

If i didn’t own the badge it would’ve been like this:

there you go! Now we have a simple badge todo list script. Now there’s an issue with this script, it’ll only check if the player owns the badge after the join. Not if they get the badge during the session. So to fix this, we can wrap the code in a while true do. Paste the following code:

local badgeService = game:GetService("BadgeService")
local runService = game:GetService("RunService")
local players = game:GetService("Players")

local player = players.LocalPlayer

local badgesHolder = player.PlayerGui:WaitForChild("BadgeUi"):WaitForChild("Holder")

local badges = {
	[1] = {
		["name"] = "Badge1", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "SBS welcome badge", -- change to the name of the badge
		['id'] = 174605507 -- change to badge id
	}
}

local function getUserOwnedBadges()
	for _, data in ipairs(badges) do
		local badgeId = data.id
		local badgeName = data.displayName
		local frameName = data.name

		local frameInstance = badgesHolder:FindFirstChild(frameName)
		if not frameInstance then warn(string.format("Could not find badge frame with name of %s", frameName)) continue end
		local badgeNameInstance = frameInstance:WaitForChild("BadgeName")
		local badgeIconInstance = frameInstance:WaitForChild("BadgeIcon")
		local success, ownsBadge = pcall(function()
			return badgeService:UserHasBadgeAsync(player.UserId, badgeId) 
		end)
		if ownsBadge and success then

			badgeIconInstance.ImageColor3 = Color3.fromRGB(255, 255, 255)
			badgeNameInstance.Text = badgeName
		elseif typeof(ownsBadge):lower() == "string" then
			warn(string.format("failed to get badge data for reason of: %s", ownsBadge))
		else
			badgeIconInstance.ImageColor3 = Color3.fromRGB(0, 0, 0)
			badgeNameInstance.Text = "???"
		end
		
	end
end

while true do
	getUserOwnedBadges()	
	task.wait(1)
end

There you go, now you have a simple badge list :slight_smile: hope this could help you out! If you have any questions feel free to ask.

place file:
badge list tutorial v2.rbxl (46.1 KB)
(43.7 KB)

62 Likes

Sweet! I always wondered how to do this!

Bookmarking it for later

ty, glad I could help u out!

1 Like

https://badges.roblox.com/docs#!/v1

It would be cool if you made an auto list of an badge thing. I gave an api which should help out

it’s pretty simple to do. I could make a tutorial if anyone wants.

3 Likes

Awesome tutorial. I learned a-lot here!

wow cool! Glad I could help u out!!

1 Like

You can change this:

[1] = {
		["name"] = "Badge1", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "SBS welcome badge", -- change to the name of the badge
		['id'] = 174605507 -- change to badge id
	}

To something like this:

[174605507] = {
		["name"] = "Badge1", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "SBS welcome badge", -- change to the name of the badge
	}

[1], formerly a never-used value, is changed to [BADGE ID].

It’s probably just for preference, but this way you don’t have a useless index value. (Probably saves a negligible amount of memory too depending on where you store this)

this sounds interesting.

But how would you access the badge id like this?

1 Like
for i,v in pairs(badges) do
print('badge ID: ' .. i)
print('badge name: ' .. v.name
end
3 Likes

This is something I’ve actually been looking for so this helped a lot! If you were to add more information such as the badge description and the badge icon, how would you go about doing that?

['displayDescription'] =  "Whatever my badge description says"

local badgeDescription = data.displayDescription

Would I need to do something like that? (Sorry I’m a new scripter so I am still trying to learn and grasp concepts.)

It’s really simple to do.

Yes you would do something like this.

Sorry I’m quite new to scripting, but when I test the badge list tutorial.rblx, it displays the Badge Ownership as if I owned it, but I don’t, and I noticed that it changes it after exactly 100 heartbeats

1 Like

hmm I’ll look into it, thanks for the report.

thanks, i’ve gone ahead and fixed the placefile + fixed the tutorial code.

I’d recommend anyone who’s used this to update their code in order to fix these bugs. Thanks @RoombaRobot.

1 Like

Would this work for a game with more than 50+ badges. Since im calling with UserHasBadgeAsync, and sometimes it doesnt return any sort of value. (Pcalls)

The badge frame would have to be offset size and the scrollingframe’s Y canvas size would have to be huge. @TheH0meLands you might wanna say this in the tutorial since this is a common confusion.

1 Like

Great tutorial, however I saw a post about having large amounts of badges and though I haven’t tested it yet, it might be more efficient to do something like this:

local badgeService = game:GetService("BadgeService")
local players = game:GetService("Players")

local player = players.LocalPlayer

local badgesHolder = script.parent.Badges
--Frame of badges

local function GetInfoName(badgeid)
	local asset = game:GetService("BadgeService"):GetBadgeInfoAsync(badgeid)
	return asset.Name
end
local function GetInfoDescription(badgeid)
	local asset = game:GetService("BadgeService"):GetBadgeInfoAsync(badgeid)
	return asset.Description
end
local function GetInfoImage(badgeid)
	local asset = game:GetService("BadgeService"):GetBadgeInfoAsync(badgeid)
	return asset.IconImageId
end

local badges = {
	[1] = {
		["icon"] = "i", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "i", -- change to the name of the badge
		["description"] = "i",
		["id"] = 2580515292,
	},
	[2] = {
		["icon"] = "i", -- change to the name of the frame that holds the badge's ui
		["displayName"] = "i", -- change to the name of the badge
		["description"] = "i",-- change to badge id
		["id"] = 2125905166,
	},
}

for _, data in ipairs(badges) do
	local badgeId = data.id
	
	data.displayName = GetInfoName(badgeId)
	data.description = GetInfoDescription(badgeId)
	data.icon = GetInfoImage(badgeId)
	
	

	local frameInstance = badgesHolder.Sample:Clone() --Cloning a object inside the frame will be more efficient for players who have lots of badges

        frameInstance.Icon.Image = ("rbxassetid://"..data.icon) 
	frameInstance:WaitForChild("Name").Text = data.displayName  --using frameinstance.Name would return a error as it would reference the actual name of the instance instead of the child
	frameInstance.Description.Text = data.description
	
        
	local success, ownsBadge = pcall(function()
		return badgeService:UserHasBadgeAsync(player.UserId, badgeId)
	end)
	if success and ownsBadge  then
                --Do stuff if they own it, I have a lock icon thats set to be invisible
		frameInstance.Icon.Lock.Visible = false
	else
                 --Do stuff if they don't own it, I have a lock icon thats set to be visible
		frameInstance.Icon.Lock.Visible = true
	end
end

If anyone wants to use this then they should add some pcall functions around the BadgeService calls.

Screenshot 2022-07-27 230744
This is the setup I used which might be used in the code example I posted. It uses a list layout to automatically place everything inside the scrollingframe.

It justs makes the process of adding badges a bit easier and uses the badge service which is helpful for new developers to get introduced to.

Edit: I updated fixed some errors I has while testing this morning and now I have an image attached of how it looks below:


Since my badges are dark themed ill set the lock to be cyan with a black outline however anyone using this should update it accordingly.

4 Likes

@Va13Official why do you need to update it accordingly?

1 Like

You’d need to change the UI style and colors so that it fits your game is what I meant