创建图形用户界面

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

目前,游戏信息的大部分已位于输出窗口,对玩家隐形。因此,玩家可以知道游戏中发生了什么,你将创建一个图形用户界面 (GUI) 并编写代码。

使用图形GUI界面显示信息

对于这个游戏,文本标签将显示当前游戏状态以及剩余玩家数量和时间。

中场休息期间
>

在比赛期间
>

设置 GUI

首先,创建一个 屏幕 GUI 对象来容纳不同的文本元素。当玩家移动相镜头时,屏幕图形用户界面保持在屏幕上的同一位置。

为了确保所有玩家都看到相同的显示,请将 GUI 放置在 StarterGUI 文件夹中。在游戏启动时,此文件夹将复制到所有玩家。

  1. 在新手 GUI 文件夹中,创建一个新的屏幕 GUI。然后在屏幕 GUI 中添加一个新的文本标签,名为状态文本。

  2. 要移动标签,在 Explorer 中,选择状态文本。然后,在游戏视查看中,拖动你想要的标签。您的数字可能与视频不同。标签也可以使用角落上的锚点进行调整。

脚本用户界面

要反映游戏中的更改,脚本需要更新 GUI 元素。例实例,游戏状态,是中场休息还是激活回合,将被存储在 StringValue 中,使用本地脚本进行更新。

设置脚本

状态显示脚本将用于每次游戏状态更改时更新玩家的图形用户界面。

  1. 复制存储 中,创建一个名为 DisplayValues 的文件夹。在那个文件夹中,添加一个名为状态的 StringValue。为了稍后测试值,给它一个临时值,例如“欢迎来到战斗!”

  2. 在启动GUI > 屏幕GUI > 状态中,添加一个名为 StatusDisplay 的新本地脚本。影响GUI 的脚本往往会被父辈到该 GUI 元素。

  3. 打开状态显示,并为跟随定义以下变量:

    • 复制存储服务

    • 显示值文件夹

    • 状态字符串值

    • 文本标签 - 使用 script.Parent .


      local ReplicatedStorage = game:GetService("ReplicatedStorage")
      local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
      local status = displayValues:WaitForChild("Status")
      local textLabel = script.Parent

更改文本标签

要更改标签中的文本,使用更改事件,每当状态字符串由另一个脚本更改时,文本标签都会更新。

  1. 编写一个名为 updateText() 的新函数。在该函数中,将 textLabel 的 Text 属性设置为 status.Value


    local textLabel = script.Parent
    local function updateText()
    textLabel.Text = status.Value
    end
  2. 将函数连接到更改事件。


    local function updateText()
    textLabel.Text = status.Value
    end
    status.Changed:Connect(updateText)
  3. 因此,玩家在开始游戏时看到最新状态,在脚本结束时运行 updateText()


    local function updateText()
    textLabel.Text = status.Value
    end
    status.Changed:Connect(updateText)
    updateText()
  4. 运行游戏并确认您在显示中看到暂时值。

创建显示管理器

在游戏期间,文本标签需要从游戏管理器、匹配管理器和可能是其他脚本获取信息。因此,这些不同的脚本可以在需要时更新文本标签,创建一个名为 DisplayManager 的模块脚本。

设置脚本

因为显示管理器需要与其他脚本进行通信,它将是一个模块脚本。

  1. 服务器存储 > 模块脚本 中,创建一个名为 DisplayManager 的新模块脚本。重命名模块表以匹配脚本名称。

  2. 为以关注中/正在关注添加本地变量:复制存储、显示值文件夹、状态。


    local DisplayManager = {}
    -- 服务
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    -- 用于更新玩家图形GUI界面的显示值
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local status = displayValues:WaitForChild("Status")
    -- 本地函数
    -- 模块功能
    return DisplayManager
  3. 创建一个名为 updateStatus() 的新模块函数,用于更新状态值中的字符串。其他脚本将能够调用此函数。


    -- 本地函数
    -- 模块功能
    function DisplayManager.updateStatus(newStatus)
    status.Value = newStatus
    end

更新文本状态

配备显示管理器后,它可以在其他脚本中使用来更新 GUI 文本标签。作为 GUI 的第一条消息,通过 GameManager 脚本显示中场休息的开始和结束。

  1. 服务器脚本服务 > 游戏管理器中,创建一个名为 displayManager 的变量,并要求服务器存储中的显示管理模块。


    -- 服务
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    local ServerStorage = game:GetService("ServerStorage")
    local Players = game:GetService("Players")
    -- 模块脚本
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local roundManager = require(moduleScripts:WaitForChild("RoundManager"))
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))
  2. 作为 while true do 语句之后的第一行,调用显示管理器 > 并传递关于等待玩家的消息


    -- 事件
    local events = ServerStorage:WaitForChild("Events")
    local matchEnd = events:WaitForChild("MatchEnd")
    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    print("Starting intermission")
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    matchEnd.Event:Wait()
    end
  3. 在中场休息的重复循环结束后,调用 updateStatus() 并传递一个宣布匹配开始的字符串。因为你将使用图形用GUI面进行测试,所以删除两个打印声明以记录中场休息的开始和结束。


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    matchEnd.Event:Wait()
    end
  4. 测试游戏 以及 没有 你的最低玩家。消息应该阅读以关注中/正在关注内容:

    • 没有最低玩家:"Waiting for Players"
    • 与最低玩家:"Get ready"

排除问题的提示

在这一点上,如果文本标签没有显示第一条消信息,或仍显示“标签”,请尝试以下方法之一。

  • 确保在状态显示本地脚本中,updateText() 被调用在脚本底部。这确保玩家得到最新的消信息。
  • 检查状态字符串值是否在复制存储中。由于客户端服务器关系的独特性,如果它在 ServerStorage 中,本地脚本无法找到它。

显示匹配状态

在比匹配期间,图形用户界面会显示两个数字:剩余玩家数量和时间。随着这些数字的变化,文本标签也会更改。

设置值和函数

IntValues将用于存储剩余玩家数量和时间。

  1. 在复制存储 > 显示值中,创建两个名为 PlayersLeft 和 TimeLeft 的 IntValues 值。

  2. 在 DisplayManager 中,添加变量以存储玩家剩余和剩余时间值。


    local DisplayManager = {}
    -- 服务
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    -- 用于更新玩家图形GUI界面的显示值
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local status = displayValues:WaitForChild("Status")
    local playersLeft = displayValues:WaitForChild("PlayersLeft")
    local timeLeft = displayValues:WaitForChild("TimeLeft")
  3. 创建一个名为 updateMatchStatus() 的本地函数。然后,将状态值设置为显示剩余的玩家数量和剩余时间。


    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local status = displayValues:WaitForChild("Status")
    local playersLeft = displayValues:WaitForChild("PlayersLeft")
    local timeLeft = displayValues:WaitForChild("TimeLeft")
    -- 本地函数
    local function updateRoundStatus()
    status.Value = "Players Left: " .. playersLeft.Value .. " / Time Left: " .. timeLeft.Value
    end
  4. 对于 两个 IntValue 变量,连接 updateRoundStatus() 到更改事件。


    -- 模块功能
    function DisplayManager.updateStatus(newStatus)
    status.Value = newStatus
    end
    playersLeft.Changed:Connect(updateRoundStatus)
    timeLeft.Changed:Connect(updateRoundStatus)
    return DisplayManager

显示玩家

接下来,添加显示游戏开始时玩家数量的代码。之后的课程将更新玩家左值,因为玩家被淘汰出游戏。

  1. 在 PlayerManager 中,为复制存储服务、显示值文件夹和玩家左侧的 IntValue 添加本地变量。


    local PlayerManager = {}
    -- 服务
    local Players = game:GetService("Players")
    local ServerStorage = game:GetService("ServerStorage")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    -- 地图变量
    local lobbySpawn = workspace.Lobby.StartSpawn
    local arenaMap = workspace.Arena
    local spawnLocations = arenaMap.SpawnLocations
    -- 值
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local playersLeft = displayValues:WaitForChild("PlayersLeft")
  2. 通过设置 playersLeft 值到激活玩家阵数组的大小来显示初始玩家数量。

    然后,在 sendPlayersToMatch() 下,在 for 循环下,输入: playersLeft.Value = #activePlayers


    function PlayerManager.sendPlayersToMatch()
    local availableSpawnPoints = spawnLocations:GetChildren()
    for playerKey, whichPlayer in Players:GetPlayers() do
    table.insert(activePlayers, whichPlayer)
    local spawnLocation = table.remove(availableSpawnPoints, 1)
    preparePlayer(whichPlayer, spawnLocation)
    end
    playersLeft.Value = #activePlayers
    end

显示计时器

请记住,模块脚本用于中央化相同的代验证码。由于计时器在匹配管理器中跟踪,因此使用计时器脚本中的函数更新 TimeLeft 值。显示管理器会听到 TimeLeft 的更改,并更新以匹配新值。

  1. 在匹配管理器中,创建变量来存储 复制存储 服务、显示值文件夹和时间值。


    local MatchManager = {}
    -- 服务
    local ServerStorage = game:GetService("ServerStorage")
    local ReplicatedStorage = game:GetService("ReplicatedStorage")
    -- 模块脚本
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    local timer = require(moduleScripts:WaitForChild("Timer"))
    -- 事件
    local events = ServerStorage:WaitForChild("Events")
    local matchStart = events:WaitForChild("MatchStart")
    -- 值
    local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
    local timeLeft = displayValues:WaitForChild("TimeLeft")
    local myTimer = timer.new()
  2. 找到 startTimer() 函数。 在计时器的 Finished结束后,复制并粘贴以下整体、突出显示的循环。代码会循环更新 timeLeft 值,直到计时器仍然活跃。


    while myTimer:isRunning() do
    -- 添加 +1 可确保计时器显示结束为 1 而不是 0。
    timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
    -- 通过不设置等待时间,它提供了更准确的循环
    task.wait()
    end

    添加时,代码应该看起来像下面的示例。


    local function startTimer()
    print("Timer started")
    myTimer:start(gameSettings.matchDuration)
    myTimer.finished:Connect(timeUp)
    while myTimer:isRunning() do
    -- 添加 +1 可确保计时器显示结束为 1 而不是 0。
    timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
    -- 通过不设置等待时间,它提供了更准确的循环
    task.wait()
    end
    end
  3. 以最少玩家运行游戏。检查状态文本是否显示:

    • 正确的起始玩家数量。请记住,此数字在未来的一堂课中添加额外代码之前不会更改。
    • 时间每秒减少,直到它停止在 1 为止。

已完成的脚本

以下是完成的脚本来检查您的工作。

游戏管理器脚本


-- 服务
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- 模块脚本
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
while true do
displayManager.updateStatus("Waiting for Players")
repeat
task.wait(gameSettings.intermissionDuration)
until #Players:GetPlayers() >= gameSettings.minimumPlayers
displayManager.updateStatus("Get ready!")
task.wait(gameSettings.transitionTime)
matchManager.prepareGame()
matchEnd.Event:Wait()
end

显示管理器脚本


local DisplayManager = {}
-- 服务
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 用于更新玩家图形GUI界面的显示值
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local status = displayValues:WaitForChild("Status")
local playersLeft = displayValues:WaitForChild("PlayersLeft")
local timeLeft = displayValues:WaitForChild("TimeLeft")
-- 本地函数
local function updateRoundStatus()
status.Value = "Players Left: " .. playersLeft.Value .. " / Time Left: " .. timeLeft.Value
end
-- 模块功能
function DisplayManager.updateStatus(newStatus)
status.Value = newStatus
end
playersLeft.Changed:Connect(updateRoundStatus)
timeLeft.Changed:Connect(updateRoundStatus)
return DisplayManager

匹配管理器脚本


local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 模块脚本
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- 事件
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- 值
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local timeLeft = displayValues:WaitForChild("TimeLeft")
local myTimer = timer.new()
-- 本地函数
local function timeUp()
print("Time is up!")
end
local function startTimer()
print("Timer started")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
while myTimer:isRunning() do
-- 添加 +1 可确保计时器显示结束为 1 而不是 0。
timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
-- 通过不设置等待时间,它提供了更准确的循环
task.wait()
end
end
-- 模块功能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
return MatchManager

状态显示脚本


local ReplicatedStorage = game:GetService("ReplicatedStorage")
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local status = displayValues:WaitForChild("Status")
local textLabel = script.Parent
local function updateText()
textLabel.Text = status.Value
end
status.Changed:Connect(updateText)
updateText()