If you're creating a game, there's going to be one point where you want to dynamically create text on the screen. One way to approach this is by creating a TextLabel and parenting it to a ScreenGui. Set it's text, size, and make TextScaled true and you're done.
local label = Instance.new("TextLabel")
label.Text = "quick and simple"
label.TextScaled = true
label.Size = UDim2.fromOffset(300, 50) -- let's ignore that
label.Parent = screenGui
Not very appealing, but if you add a little style it's going to look good, right? Right? 😡
label.BorderSizePixel = 0
label.BackgroundColor3 = Color3.new(0, 0, .1)
label.BackgroundTransparency = .4
label.AnchorPoint = Vector2.new(.5, 0)
label.Position = UDim2.new(.5, 0, .04, 0)
label.Font = Enum.Font.GothamSemibold
label.TextColor3 = Color3.fromRGB(255, 255, 255)
Ok, that looks nice. But the text isn't always going to be the same in a game (presumably). So what if you make the text something else?
label.Text = enemyTeam .. " has captured the flag!" -- assuming enemyTeam is blue
or maybe
label.Text = "bought '" .. itemName .. "'" -- assuming itemName is sword
Individually they look nice, but together they're a little ugly. That's because of the inconsistent sizing. The paddings don't match and the text from the label below is almost two times bigger than the one above. It's not the end of the world, but you can do better. So how do you fix this? You can't really control the text size since it's TextScaled, and even if you disable TextScaled, the inconsistent padding is still going to be there.
TextService has two useful functions: FilterStringAsync and GetTextSize. The one that's going to be used for this is GetTextSize. Like its name says, GetTextSize gives you the dimensions of some text as a Vector2 in offset. It accepts the arguments:
TextService:GetTextSize(text: string, textSize: number, font: Enum.Font, boundary: Vector2)
duh, it's the text you want to find the dimensions of.
Size of the text you want to find the dimensions of. Make sure it's an integer.
Font of the text you want to find the dimensions of. Like Enum.Font.GothamSemibold
The boundaries of the text you want to find the dimensions of. Used to see how the text will wrap. Really only the X component of it matters.
There are two obvious ways of approaching the problem of text size. The first one is to scale the text to the background (TextScaled), and the second is to scale the background to the text. Using GetTextSize, you can scale the background to the text. So first you have to find the size of the text (the TextSize!!!!! hey that's an argument of gettextsize).
If you're concerned about scaling to different screen sizes, you're not just going to put some random number as the TextSize. You're going to have a text size that corresponds to the screen size. The most obvious way is to have the TextSize be some percentage of the screen size, and that's what you're going to do. Since TextSize is proportional to text height you'll want to scale based on the Y-axis (height). For this example you'll make the text size 5% of the screen height.
function getTextSize()
return workspace.CurrentCamera.ViewportSize.Y * (5/100)
end
this works well, but if the player is on their phone and is in portrait mode, the text is going to be way to bloated. The solution is to scale based on the shortest axis, which in most cases is going to be the Y-axis as intended.
function getTextSize()
return math.min(workspace.CurrentCamera.ViewportSize.X, workspace.CurrentCamera.ViewportSize.Y) * (5/100)
end
If you have a lot of text it's going to go off the screen, so you need to set a boundary. All the boundary does is specify how long the text is going to be before it wraps. The boundary is going to be proportional to the X-axis because English is written from left to right. For this it's going to be 70% of the screen.
function getBoundary()
return Vector2.new(workspace.CurrentCamera.ViewportSize.X * (70/100), math.huge) -- y-axis is math.huge so the text never gets cut-off
end
Now that you have all the ingredients you need for GetTextSize, just plug in the values and you'll get the dimensions for your text. Once you do that, adjust the size of your TextLabel to the dimensions of the text.
local textService = game:GetService("TextService")
local textSize = getTextSize()
local boundary = getBoundary()
local text = enemyTeam .. " has captured the flag!"
local font = Enum.Font.GothamSemibold
local textDimensions = text:GetTextSize(text, textSize, font, boundary)
label.Size = UDim2.fromOffset(textDimensions.X, textDimensions.Y)
label.TextWrapped = true
label.TextSize = textSize
label.Font = font
label.Text = text
Unfortunately there's no padding anymore. To add padding, all you have to do is change:
label.Size = UDim2.fromOffset(textDimension.X, textDimensions.Y)
to:
local paddingX = 5
local paddingY = 5
label.Size = UDim2.fromOffset(textDimensions.X + paddingX*2, textDimensions.Y + paddingY*2) -- multiply by 2 so padding is applied on both sides
and done. That's how you size your text nicely.
GetTextSize gives you the dimensions of some text, so it's really useful for anything related to text. Maybe you want to make something like Lua Learning. Use GetTextSize. Dynamically styled text? GetTextSize. It's really useful.
tl;dr: there's a secret function called danceMonkey that automatically scales your TextLabels