在 Roblox 中动态创建的 GUI

Posted

技术标签:

【中文标题】在 Roblox 中动态创建的 GUI【英文标题】:Dynamically created GUI in Roblox 【发布时间】:2020-05-07 00:20:06 【问题描述】:

我正在使用 lua 和 roblox studio 编写我的第一个游戏。我有几个关于 GUI 的问题。我编写了一个非常基本的 gui,它显示了可以加入游戏的四个团队的代码。这是 GUI 的代码。它位于 StarterGUI 内的本地脚本中:

local UpdateGUI = game.ReplicatedStorage:WaitForChild("UpdateGUI")
local StartGui = game.ReplicatedStorage:WaitForChild("StartGui")
local UpdateAllScoresLateArrival = game.ReplicatedStorage:WaitForChild("UpdateAllScoresLateArrival")

local function updateAllLabelsLateArrival(redPoints, bluePoints, yellowPoints, greenPoints)
    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeam.Text = redPoints
    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeam.Text = bluePoints
    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeam.Text = yellowPoints
    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeam.Text = greenPoints
end

local function UpdateLabel(plr, points)
    if plr.team.Name == "Really red Team" then
    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeam.Text = points
    elseif plr.team.Name == "Really blue Team" then
    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeam.Text = points
    elseif plr.team.Name == "New Yeller Team" then
    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeam.Text = points
    elseif plr.team.Name == "Lime green Team" then
    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeam.Text = points
    end
end

local localPlayer = game.Players.LocalPlayer


local function StartLabel(player)
    if player.Team.Name == "Really red Team" then

    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeam.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeamTag.TextTransparency = 0

    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeam.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeamTag.TextStrokeTransparency = 0

    game.Players.LocalPlayer.PlayerGui.ScreenGui.RedTeamTag.BackgroundTransparency = 0.5

    elseif player.Team.Name == "Really blue Team" then

    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeam.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeamTag.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeam.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeamTag.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.BlueTeamTag.BackgroundTransparency = 0.5

    elseif player.Team.Name == "New Yeller Team" then

    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeam.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeamTag.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeam.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeamTag.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.YellowTeamTag.BackgroundTransparency = 0.5

    elseif player.Team.Name == "Lime green Team" then

    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeam.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeamTag.TextTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeam.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeamTag.TextStrokeTransparency = 0
    game.Players.LocalPlayer.PlayerGui.ScreenGui.GreenTeamTag.BackgroundTransparency = 0.5
    end


end


UpdateGUI.OnClientEvent:Connect(UpdateLabel)

StartGui.OnClientEvent:Connect(StartLabel)

UpdateAllScoresLateArrival.OnClientEvent:Connect(updateAllLabelsLateArrival)

有一个函数可以在玩家加入游戏时启动在服务器端脚本中触发的标签。通过“开始标签”,我的意思是标签的透明度为 1,并且该功能使它们在玩家加入时可见。有一个功能可以在每次任何玩家得分时更新标签,还有一个功能会在玩家加入游戏较晚时触发,以确保它具有已经在游戏中的玩家的得分。就像我说的,这是我的第一场比赛,我专注于工作。现在我想正确编码。我的目标是动态分配标签。也就是说,当玩家加入游戏时,标签是在代码中创建的。特别是我希望动态设置标签之间的空间,以便无论有多少玩家,标签都居中。我尝试使标签成为“框架”的子标签,但标签改变了位置并且难以操作。所以我想要一些关于如何在代码中设置它的建议。

【问题讨论】:

【参考方案1】:

我的目标是动态分配标签。即当玩家加入游戏时,在代码中创建标签

您可以像在工作区中创建实例一样创建 UI 元素。

local lblTeam = Instance.new("TextLabel")
lblTeam.TextTransparency = 0
lblTeam.TextStrokeTransparency = 0
lblTeam.Name = teamName
lblTeam.Parent = game.Players.LocalPlayer.PlayerGui.ScreenGui

我希望动态设置标签之间的空间,以便无论有多少玩家,标签都居中。

UI 元素在 Roblox 中的布局方式是使用 UDim2 的 Size 和 Position 值。 UDim2 的构造函数如下所示:UDim2.new(xScale, xOffset, yScale, yOffset)。 Scale 是指该尺寸跨度时父容器的百分比,Offset 是要添加的额外像素数。所以一些例子:

local lbl = Instance.new("TextLabel")
lbl.Size = UDim2.new(0, 50, 0, 10) -- 50 pixel wide and 10 pixel tall
lbl.Size = UDim2.new(1, 0, 1, 0) -- 100% wide by 100% tall
lbl.Size = UDim2.new(1, -10, 1, -10) -- 100% wide and tall, minus 10 pixels on both bottom and right

-- assuming no changes to AnchorPoint...
lbl.Position = UDim2.new(0, 0, 0, 0) -- upper left corner is upper left corner of parent
lbl.Position = UDim2.new(0.5, 0, 0.5, 0) -- upper left corner is dead center
lbl.Position = UDim2.new(1, 0, 0, 0) -- upper left corner is offscreen on the right

现在,如果您希望动态放置内容,可以使用 Positions 手动放置这些对象,但我建议使用 UIListLayout 对象并使用 LayoutIndex 属性自动放置对象为你。它会自动为您处理 Position 属性。

local function createTeamUI(name, parent, teamName, index)
    -- make a small frame to hold each team UI
    -- looks like : [[  Team Tag Label  ][ Team Points Label ]]
    local teamFrm = Instance.new("Frame")
    teamFrm.BackgroundTransparency = 1
    teamFrm.Size = UDim2.new(1, 0, 0, 30) -- relative to parent : 100% wide, 30px tall
    teamFrm.Name = name
    teamFrm.LayoutIndex = index

    local lblTeamTag = Instance.new("TextLabel", teamFrm)
    lblTeamTag.TextTransparency = 0
    lblTeamTag.TextStrokeTransparency = 0
    lblTeamTag.Name = "TeamTag"
    lblTeamTag.Text = teamName
    lblTeamTag.Size = UDim2.new(0.5, 0, 1, 0) -- relative to teamFrm : 50% wide, 100% tall
    lblTeam.Position = UDim2.new(0, 0, 0, 0)

    local lblPoints = Instance.new("TextLabel", teamFrm)
    lblPoints.TextStrokeTransparency = 0
    lblPoints.BackgroundTransparency = 0.5
    lblPoints.Name = "Points"
    lblPoints.Text = "0"
    lblPoints.Size = UDim2.new(0.5, 0, 1, 0) -- relative to teamFrm
    lblPoints.Position = UDim2.new(0.5, 0, 0, 0)

    -- optimization : set the parent last
    teamFrm.Parent = parent
    return teamFrm
end

local function createAllTeamLabels()
    -- creates a list of UI
    local frm = Instance.new("Frame")
    frm.Name = "Teams"
    frm.Size = UDim2.new(0.3, 0, 1, 0)
    frm.BackgroundTransparency = 1.0

    local layout = Instance.new("UIListLayout")
    layout.LayoutOrder = Enum.SortOrder.LayoutIndex
    layout.FillDirection = Enum.FillDirection.Vertical
    layout.Padding = UDim.new(0, 10) -- 10 pixels between each element in the list

    local frmTeamA = createTeamLabel("RedTeam", frm, "Really Red Team", 0)
    local frmTeamB = createTeamLabel("BlueTeam", frm, "Blue Team", 1)
    local frmTeamC = createTeamLabel("GreenTeam", frm, "Green Team", 2)

    frm.Parent = game.Players.LocalPlayer.PlayerGui.ScreenGui
end

local function updatePoints(teamName, points)
    game.Players.LocalPlayer.PlayerGui.ScreenGui.Teams[teamName].Points.Text = tostring(points)
end

我注意到当玩家死亡时,GUI 会在重生时消失

ScreenGuis 上有一个名为 ResetOnSpawn 的属性,您可以将其更改为 false。即使在玩家重置后,这也会保留 UI。

由于您是在代码中动态创建 UI,因此您应该小心不要意外地多次创建 UI。这就是 StarterPlayer > StarterPlayerScriptsStarterPlayer > StarterCharacterScripts 之间的区别变得重要的地方。 StarterPlayerScripts 中的 LocalScript 将在玩家首次加入时运行,而 StarterCharacterScripts 中的 LocalScript 将在每次玩家角色重新加载时运行。所以要小心你在哪里触发代码来创建 UI。

希望这会有所帮助!

【讨论】:

嗨,这很有用。非常感谢凯拉。唯一的问题是索引不是动态创建的吗?因此,例如:几个玩家加入游戏并玩了一段时间,此时我们应该有两个标签。然后第三个玩家稍后加入。然后我们有三个标签。所以也许我可以通过远程事件使用您在 OnPlayerAdded 函数中编写的 CreateTeamUI 函数?所以当玩家加入时,我可以通过计算数组来获得索引:#Players:GetPlayers() 这有意义吗? 是的,这行得通。另一种选择是保留一个局部变量“teamCount”,并在您调用 CreateTeamUI() 时添加 +1。然后使用它而不是传入索引。

以上是关于在 Roblox 中动态创建的 GUI的主要内容,如果未能解决你的问题,请参考以下文章

Jenkinsfile Pipeline DSL:如何在作业仪表板 GUI 中显示多列 - 对于所有动态创建的阶段 - 在 PIPELINE 部分中时

如何使用 lua 检查 Roblox 中是不是存在对象?

当它应该出现时框架没有出现......(ROBLOX GUI)

Qt Ruby:动态创建表并从文本文件输入数据

tkinter:动态创建和删除条目

如何在 Roblox 中打开和关闭 gui?