Roblox Studio · 第 18 课

远程事件:向服务器申请补充能量

用 RemoteEvent 连接按钮与服务器,练习请求、校验、限流和状态反馈。

10–15 岁 75 分钟 RemoteEvent 动手实践 测试与保存

Course overview

按钮可以申请能量,但数量由服务器说了算。

这一课把你的个人按钮连接到共享规则。玩家按下按钮,客户端发送“我要补充”,服务器检查冷却后决定是否增加能量。

我们不让客户端传“请给我一万点”。请求只表达动作,能量上限与增加量都写在服务器脚本里。

01 · BEFORE

开始之前

完成第 16–17 课。新建 Lesson18 Baseplate,练习两种脚本位置。

02 · MAKE

你的作品

一个补充能量按钮,服务器每两秒最多接受一次,每次加 10,上限 100。

03 · CHECK

完成标志

快速连点不会绕过冷却;两个玩家的能量分别记录;晚出现的界面能读到当前值。

Output 中区分 Client 与 Server 的官方截图
图 18-1:官方 Output 标签截图:Client 与 Server 能帮助你判断消息由哪一端发出。Roblox Creator Documentation · CC BY 4.0 · 原图未修改 · 许可说明

Learning route

先准备,再动手;看到结果后,记得保存。

每完成一小步,就测试一次。先说出你预计会看到什么,再用 Play 和 Output 检查,不用急着一次写完所有代码。

1

01 · 在双方都能看见的位置放事件

RemoteEvent 像一条消息通道。ReplicatedStorage 同时对服务器和客户端可见,因此适合放这条通道。

2

02 · 服务器只接受动作,不接受任意奖励

OnServerEvent 的第一个 player 由 Roblox 提供,不需要客户端自己传身份。服务端冷却按玩家分别记录,并在离开时清理。

3

03 · 发请求,再显示真实状态

FireServer() 只发送请求,不代表申请已经成功。按钮显示的值应来自服务器更新后的 Attribute。

4

04 · 哪些东西不能交给客户端决定

这是一台免费训练补给机,任何存活玩家都能申请,不需要距离限制。如果改成“靠近营地才能补充”,就必须在服务器再检查到营地的距离。

5

05 · 用连点和双人测试检查边界

安全检查也要有可重复的预期:十次快速点击不能获得 100 能量;慢慢等待并点击,最终能到 100,但不能超过。

Step by step

01 · 在双方都能看见的位置放事件

RemoteEvent 像一条消息通道。ReplicatedStorage 同时对服务器和客户端可见,因此适合放这条通道。

下面的 Energy 是 Player 的 Attribute(自定义属性),可以保存一个小数值并让客户端读取。第 19 课会进一步使用它制作任务。

  1. 在 ReplicatedStorage 创建 RemoteEvent,命名 RechargeRequest。
  2. 创建 ServerScriptService > EnergyServer(Script)。
  3. 创建 StarterPlayerScripts > EnergyButton(LocalScript)。

Step by step

02 · 服务器只接受动作,不接受任意奖励

OnServerEvent 的第一个 player 由 Roblox 提供,不需要客户端自己传身份。服务端冷却按玩家分别记录,并在离开时清理。

SetAttribute 更新状态;GetAttribute 读取状态。角色必须存活,且满足两秒间隔,服务器才会增加固定的 10 点。

  1. 把完整代码放入 EnergyServer。
  2. 检查上限、增加量与冷却都留在服务器。
ServerScriptService > EnergyServer(Script)Luau
local Players = game:GetService("Players")
local remote = game:GetService("ReplicatedStorage"):WaitForChild("RechargeRequest")
local lastRequest = {}
local function setup(player)
    player:SetAttribute("Energy", 0)
end
Players.PlayerAdded:Connect(setup)
for _, player in ipairs(Players:GetPlayers()) do setup(player) end

remote.OnServerEvent:Connect(function(player)
    local now = os.clock()
    if now - (lastRequest[player] or -math.huge) < 2 then return end
    lastRequest[player] = now
    local character = player.Character
    local humanoid = character and character:FindFirstChildOfClass("Humanoid")
    if not humanoid or humanoid.Health <= 0 then return end
    local energy = player:GetAttribute("Energy") or 0
    player:SetAttribute("Energy", math.min(100, energy + 10))
end)
Players.PlayerRemoving:Connect(function(player)
    lastRequest[player] = nil
end)
客户端向服务器发送事件的官方示意图
图 18-2:官方 RemoteEvent 流程图:客户端发送请求,服务器收到后验证并处理;请求不等于批准。Roblox Creator Documentation · CC BY 4.0 · 原图未修改 · 许可说明

Step by step

03 · 发请求,再显示真实状态

FireServer() 只发送请求,不代表申请已经成功。按钮显示的值应来自服务器更新后的 Attribute。

先连接变化事件,再调用一次 render:既能接住以后发生的改变,也能读到界面打开前已有的当前状态。暂时没有值时显示等待,而不是假装加载完成。

  1. 把完整代码放入 EnergyButton。
  2. Play 后点击按钮,观察能量每次增加 10。
  3. 连点时按钮可以被点击,但两秒内不会反复加能量。
StarterPlayer > StarterPlayerScripts > EnergyButton(LocalScript)Luau
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local remote = game:GetService("ReplicatedStorage"):WaitForChild("RechargeRequest")
local gui = Instance.new("ScreenGui")
gui.Name = "EnergyGui"
gui.ResetOnSpawn = false
local button = Instance.new("TextButton")
button.Size = UDim2.fromOffset(280, 64)
button.Position = UDim2.fromOffset(16, 16)
button.TextSize = 20
button.Parent = gui
gui.Parent = player:WaitForChild("PlayerGui")

local function render()
    local energy = player:GetAttribute("Energy")
    button.Text = energy == nil and "等待能量数据…" or ("能量 " .. energy .. "/100 · 补充")
end
player:GetAttributeChangedSignal("Energy"):Connect(render)
button.Activated:Connect(function()
    remote:FireServer()
end)
render()

Step by step

04 · 哪些东西不能交给客户端决定

这是一台免费训练补给机,任何存活玩家都能申请,不需要距离限制。如果改成“靠近营地才能补充”,就必须在服务器再检查到营地的距离。

如果以后允许客户端传入物品名,要检查类型、允许列表、价格与玩家是否有资格。不要信任客户端传来的金币数或“我已经完成任务”。

  1. 在纸上写出本课允许的请求:只申请补充,无奖励数值。
  2. 找出服务器拒绝请求的两个理由:冷却未结束、角色无效或未存活。
  3. 不要为了界面更灵敏,把真正的加分移回 LocalScript。

Step by step

05 · 用连点和双人测试检查边界

安全检查也要有可重复的预期:十次快速点击不能获得 100 能量;慢慢等待并点击,最终能到 100,但不能超过。

本课只做课堂规模的限流实验,不代表完整线上反作弊系统。它展示的核心习惯是把规则放在可信的执行位置。

  1. 短时间连点十次,能量应只增加一次。
  2. 间隔两秒再点,能量再次增加。
  3. 双人测试中,A 申请不会改变 B 的 Energy。
  4. 达到 100 后再点,仍然保持 100。

Homework

轮到你来改一改,做出自己的版本。

1 改变补给规则

在服务器把增量改为 20,保持上限 100,并更新测试预期。

2 解释一次请求

用三句话说明按钮、RemoteEvent、服务器各做什么。

3 选做:显示冷却说明

在按钮旁写明“每两秒可补充一次”,让玩家知道为什么连点没有效果。

完成标准:先在 Playtest 中验证作品,再点击 Stop,保存为“姓名缩写_Lesson18”或对应 Homework 副本;不要覆盖上一课的可运行版本。

Exit questions

先自己回答,再展开看看。

OnServerEvent 的 player 需要客户端传吗?

不需要,Roblox 自动提供调用客户端对应的 Player。

FireServer 后能立刻显示成功吗?

不能把发出请求当作成功,应显示服务器确认后的状态。

为什么先连接变化事件再 render?

避免错过后续变化,同时读取已经存在的当前状态。

界面限制按钮就足够安全吗?

不够,客户端界面可以被绕过,规则和限流必须在服务器执行。

Explore further

需要查资料时,从这里出发。

正文代码可以直接复制。先确认脚本类型、放置位置,以及这段代码是完整版本还是小实验;不要把同一脚本的多个版本叠加运行。界面参考图已标注来源,图中的对象名可能与本课不同,请以操作步骤为准。