编写游戏循环

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

创建了地图后,是时候开始构建脚本了。本课程剩余部分将重点关注编写游戏循环的所有不同元素的脚本。

设置脚本

战斗皇家将使用模块脚本和普通脚本的组合。以下是脚本和其功能。

游戏管理器脚本。使用游戏设置中的变量从匹配管理器运行函数
匹配管理器模块脚本。运行功能,例如将玩家送入竞技场或跟踪匹配赛中的时间。
游戏设置模块脚本。存储常用变量,由其他脚本使用。

游戏设置脚本

创建一个名为 GameSettings 的模块脚本来存储其他脚本使用的变量,例如比赛和中场休息时间。这些变量将在稍后由游戏管理器脚本使用。

  1. 服务器存储 中,创建一个名为 ModuleScripts 的文件夹。在那个文件夹中,创建一个名为 GameSettings 的新模块脚本。

  2. 打开游戏设置并将模块表重命名为与脚本名称匹配的名称。


    local GameSettings = {}
    return GameSettings
  3. 在模块表中,添加变量以进行以下使用。对每个值进行最佳猜测,您随时都可以在测试时更改它。

    • 中场休息时间 - 秒玩家在匹配赛前等待。
    • 匹配时长 - 匹配的时长(秒)。
    • 最小玩家 - 需要启开始的最小数量玩家。
    • 过渡时间 - 秒内的比赛前后时间。使游戏循环的部分之间的过渡变得更平缓。

    local GameSettings = {}
    -- 游戏变量
    GameSettings.intermissionDuration = 5
    GameSettings.matchDuration = 10
    GameSettings.minimumPlayers = 2
    GameSettings.transitionTime = 5
    return GameSettings

匹配管理器脚本

连接到 GameManager 的第二个脚本是 MatchManager 。该脚本管理任务,例如启动计时器或在比赛结束后重置玩家。

在 MatchManager 中,一个名为 prepareGame() 的函数开始游戏,通过将玩家转换为比匹配来实现。

  1. 在服务器存储 > 模块脚本 > 添加一个名为 MatchManager 的模块脚本。重命名模块表。


    local MatchManager = {}
    return MatchManager
  2. 将新模块函数添加到 MatchManager 名为 prepareGame() 的模块中。包含打印声明以在稍后测试脚本。


    local MatchManager = {}
    function MatchManager.prepareGame()
    print("Game starting!")
    end
    return MatchManager

编写游戏循环

主游戏循环将使用刚刚创建的变量在游戏管理器脚本中编写。请记住,游戏循环中有三个阶段:中场休息、竞赛和清理和重置。

游戏管理器脚本

该脚本是普通的服务器脚本,因此将其放置在 ServerScriptService 中,而不是模块脚本文件夹中。实际游戏循环将在 while true do 循环中。

  1. 在 ServerScriptService 中,创建一个名为 GameManager 的新脚本。

  2. 为服务“ServerStorage”添加变量,这是模块脚本存在的地方。然后为服务“玩家”添加变量,该变量将在中场休息期间检查玩家数量所需。


    -- 服务
    local ServerStorage = game:GetService("ServerStorage")
    local Players = game:GetService("Players")
  3. 要使用之前创建的模块:

    • 将变量名为 moduleScripts 的变量设置到模块脚本文件夹的位置。
    • 添加名为 matchManagergameSettings 的变量。将每个变量设置为需要其各自的脚本。

    -- 服务
    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"))
  4. 在变量之后,添加一个 while true do 循环。游戏循环的所有阶段都会进入重复无限期。


    -- 模块脚本
    local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
    local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
    local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
    -- 主游戏循环
    while true do
    end

编写中场休息

虽然游戏循环无限循环,但中场休息应暂停循环,只有当比匹配有足够的玩家时才继续。要编写这个暂停,包括在 while 循环中的嵌套重复循环以及中场休息。这个嵌套循环将继续重复,直到有足够的玩家,暂停主循环。一旦有足够的玩家,它就会退出并将玩家转换为比匹配。

使用 重复循环 ,循环中的代码至少会运行一次。与 while 循环不同,它不会在循环结束之前检查条件。这保证玩家始终在比匹配前去大厅。

  1. while true do 循环中,输入 repeat 并按 Enter 以自动完成关键字 until


    while true do
    repeat
    until
    end
  2. 检查当前玩家数量 (#Players:GetPlayers()) 是否大于或等于游戏设置模块中先前创建的 minimumPlayers 变量。


    while true do
    repeat
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    end
  3. 在重复循环中,添加一个打印声明,说明中场休息正在开始。使用 task.wait() 从游戏设置中暂停使用 intermissionDuration 来进行中场休息。


    while true do
    repeat
    print("Starting intermission")
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    end
  4. 播放测试,检查打印声明 "Starting intermission" 至少显示两次。看到消息两次证明重复循环没有找到足够的玩家并再次运行。你必须等待一段中场休息时间才能第二次看到消息。

排除问题的提示

在这一点上,如果你没有按预期生成,请尝试以下方法之一。

  • task.wait() 应该在重复循环内。没有等待,脚本在一秒内运行太多次,会超载 Roblox Studio 并导致错误。
  • 在游戏设置模块中,变量 intermissionDuration 应大于 1。如果低于,脚本可能会重复太频繁,导致速度问题。

结束中场休息

一旦有足够的玩家,让他们等待短暂的过渡时间。然后,通过在匹配管理器中调用 prepareGame() 函数将它们发送到匹配中请记住,这个函数只打印一行,但你稍后会添加更多代码。

  1. 在重复循环结束时,添加一个打印声明,说中断已结束以测试您的代验证码。然后,使用游戏设置的 变量跟随它。


    while true do
    repeat
    print("Starting intermission")
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    print("Intermission over")
    task.wait(gameSettings.transitionTime)
    end
  2. 等待后,从匹配管理器模块中调用 prepareGame()。当代码运行时,这将只打印文本到输出窗口。等到下一节测试这段验证码。


    while true do
    repeat
    print("Starting intermission")
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    print("Intermission over")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    end

测试多人游戏

现在,要使代码运行 prepareGame() ,它需要退出重复循环。但是,要做到这一点,需要至少有一个玩家。这意味着如果你使用播放测试按钮,函数永远不会运行,因为你是游戏中唯一的玩家(除非你的最低玩家数是一个)。要测试这一点,你需要模拟多人游戏。

启动本地服务器

要测试需要多个玩家的代码,创建一个本地服务器。虽然发布的游戏通常在 Roblox 服务器上,但 本地服务器 可以模拟在您的计算机上使用模拟玩家的多人游戏。

  1. 要启动本地服务器,请在 测试 选项卡 > 客户端和服务器 部分 >将玩家下拉列表设置为游戏设置变量 minimumPlayers 的玩家数量。这一课程使用 2 名玩家。

  2. 单击启动开始启动服务器。

  3. 等待服务器设置几秒钟。除了您的原始 Studio 窗口外,将打开多个窗口。您可能需要允许从防火墙或其他在线安全软件中访问 Roblox Studio。

排除问题的提示

在这一点上,您无法看到测试服务器,请尝试以下其中一个。

  • 如果您有服务器启动时的任何问题,请检查防火墙和路由器问题文章。
  • 将玩家数设置为小数量,例如 2 或 3
  • 如果问题没有解决,请尝试重新启动 Studio 或重新启动您的计算机。

在本地服务器上进行测试

当服务器启动时,你会看到多个窗口。每个窗口都代表服务器/客户端关系的不同部分。

  • 服务器 (绿色边框) 运行游戏。
  • 客户端 (蓝色边框)模拟玩家的体验。

绿色边界服务器
>

拥有蓝色边框的客户端
>

当服务器运行时,您可以检查代码是否工作。

  1. 找到具有绿色边框的 服务器 窗口。检查从匹配管理器脚本中调用的打印声明。因为存在重复循环,你会看到相同的打印声明重复。

  2. 一旦您完成测试,在任何窗口中,通过清理按钮关闭服务器。这将关闭所有服务器和客户端窗口,并将你带回到你的正常 Studio 窗口。

排除问题的提示

在这一点上,如果预期的打印声明未出现,请尝试以下方法之一。

  • 检查功能如 prepareGame() 是否属于 while 真实循环的范围。
  • 如果从匹配管理器打印没有工作,请检查一些常见的排除问题方法,例如确保匹配管理器脚本在游戏管理器中需要或添加 prepareGame() 到该模块的表中。

已完成的脚本

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

游戏管理器脚本


-- 服务
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"))
-- 主游戏循环
while true do
repeat
print("Starting intermission")
task.wait(gameSettings.intermissionDuration)
until #Players:GetPlayers() >= gameSettings.minimumPlayers
print("Intermission over")
task.wait(gameSettings.transitionTime)
matchManager.prepareGame()
end

匹配管理器脚本


local MatchManager = {}
function MatchManager.prepareGame()
print("Game starting!")
end
return MatchManager

游戏设置脚本


local GameSettings = {}
-- 游戏变量
GameSettings.intermissionDuration = 5
GameSettings.roundDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.transitionTime = 5
return GameSettings