玩家现在可以收集金币并在死亡时失去它们,但这些金币没有任何作用,而且没有能力跳得很高,3D 世界的大部分区域无法访问。本教程的这一部分教你如何通过添加一个在屏幕上花费金币以增加跳跃能力的按钮来完成游戏的逻辑。
创建升级按钮
Roblox 中的 2D 界面通常由一组 GUI 组件组成,这些组件位于一个 GUI 容器内。在这种情况下,你只需要一个 TextButton 组件,里面写着“升级跳跃(5 个金币)”,放在一个 ScreenGui 容器内。
在 ReplicatedStorage 中,创建一个名为 Instances 的文件夹。
在 Instances 文件夹内,创建一个名为 JumpPurchaseGui 的 ScreenGui,并禁用 ResetOnSpawn。
在 JumpPurchaseGui 内,创建一个名为 JumpButton 的 TextButton,具有以下属性:
- Text: "升级跳跃(5 个金币)"
- TextSize: 25
- AnchorPoint: 1, 1
- Position: {1, 0}, {1, 0}
在 Instances 文件夹内,还创建一个名为 IncreaseJumpPowerFunction 的 RemoteFunction。
最后,在 StarterPlayer 服务上,启用 CharacterUseJumpPower 属性。定义跳跃能力数据
目前,只有金币数量存储在 PlayerData 模块脚本中。你还需要以相同的方式存储和更新跳跃能力。由于 PlayerData 中的函数与正在更改的数据无关,因此只需添加一个 Jump 键并在 defaultPlayerData() 中初始化其初始值即可。
在 ServerStorage 中,用以下代码替换现有的 PlayerData ModuleScript 的代码:
```lua
local PlayerData = {}
PlayerData.COIN_KEY_NAME = "Coins"
PlayerData.JUMP_KEY_NAME = "Jump"
local playerData = {
--[[
[userId: string] = {
["Coins"] = coinAmount: number,
["Jump"] = jumpPower: number
}
--]]
}
local function defaultPlayerData()
return {
[PlayerData.COIN_KEY_NAME] = 0,
[PlayerData.JUMP_KEY_NAME] = 0,
}
end
local function getData(player)
local data = playerData[tostring(player.UserId)] or defaultPlayerData()
playerData[tostring(player.UserId)] = data
return data
end
function PlayerData.getValue(player, key)
return getData(player)[key]
end
function PlayerData.updateValue(player, key, updateFunction)
local data = getData(player)
local oldValue = data[key]
local newValue = updateFunction(oldValue)
data[key] = newValue
return newValue
end
return PlayerData
```更新跳跃能力数据
现在 PlayerData 能够跟踪跳跃能力,你需要在服务器上实现逻辑,以根据玩家的客户端请求升级跳跃能力。
服务器和客户端可以通过 RemoteEvents 或 RemoteFunctions 进行通信。远程事件在触发时不会阻塞,可以用于单向通信。另一方面,远程函数在收到回复之前会阻塞,这允许双向通信。
对于本教程,客户端需要知道服务器是否成功升级了玩家的跳跃能力,因此你应该使用远程函数。
在 ServerScriptService 中,创建一个名为 JumpService 的脚本,代码如下:
```lua
-- 服务
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- 模块
local Leaderboard = require(ServerStorage.Leaderboard)
local PlayerData = require(ServerStorage.PlayerData)
-- 事件
local IncreaseJumpPowerFunction = ReplicatedStorage.Instances.IncreaseJumpPowerFunction
local JUMP_KEY_NAME = PlayerData.JUMP_KEY_NAME
local COIN_KEY_NAME = PlayerData.COIN_KEY_NAME
local JUMP_POWER_INCREMENT = 30
local JUMP_COIN_COST = 5
local function updateJumpPower(player, updateFunction)
-- 更新跳跃能力表
local newJumpPower = PlayerData.updateValue(player, JUMP_KEY_NAME, updateFunction)
-- 更新玩家的跳跃能力
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
humanoid.JumpPower = newJumpPower
-- 更新跳跃排行榜
Leaderboard.setStat(player, JUMP_KEY_NAME, newJumpPower)
end
end
local function onPurchaseJumpIncrease(player)
local coinAmount = PlayerData.getValue(player, COIN_KEY_NAME)
if coinAmount < JUMP_COIN_COST then
return false
end
-- 增加玩家的跳跃能力
updateJumpPower(player, function(oldJumpPower)
oldJumpPower = oldJumpPower or 0
return oldJumpPower + JUMP_POWER_INCREMENT
end)
-- 更新金币表
local newCoinAmount = PlayerData.updateValue(player, COIN_KEY_NAME, function(oldCoinAmount)
return oldCoinAmount - JUMP_COIN_COST
end)
-- 更新金币排行榜
Leaderboard.setStat(player, COIN_KEY_NAME, newCoinAmount)
return true
end
local function onCharacterAdded(player)
-- 当角色被添加时重置玩家的跳跃能力
updateJumpPower(player, function(_)
return 0
end)
end
-- 初始化在连接到 PlayerAdded 事件之前添加的任何玩家
for _, player in Players:GetPlayers() do
onCharacterAdded(player)
end
-- 从 PlayerAdded 事件正常初始化玩家
local function onPlayerAdded(player)
player.CharacterAdded:Connect(function()
onCharacterAdded(player)
end)
end
local function onPlayerRemoved(player)
updateJumpPower(player, function(_)
return nil
end)
end
IncreaseJumpPowerFunction.OnServerInvoke = onPurchaseJumpIncrease
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoved)
```将按钮添加到玩家 GUI
ScreenGui 对象只有在其被父级设置为玩家的 PlayerGui 对象时才会在屏幕上显示。默认情况下,这包含系统 GUI,例如聊天窗口。你现在需要在 ReplicatedStorage 中创建一个脚本,将升级按钮复制到每个玩家的 GUI 中,并实现按钮被按下时的行为。
在 ReplicatedStorage 中,创建一个名为 JumpButtonClickHandler 的脚本,RunContext 设置为 Client,代码如下:
```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local playerGui = player.PlayerGui
local IncreaseJumpPowerFunction = ReplicatedStorage.Instances.IncreaseJumpPowerFunction
local jumpPurchaseGui = ReplicatedStorage.Instances.JumpPurchaseGui
local jumpButton = jumpPurchaseGui.JumpButton
local function onButtonClicked()
local success, purchased = pcall(IncreaseJumpPowerFunction.InvokeServer, IncreaseJumpPowerFunction)
if not success then
-- purchased 将是错误消息,如果成功为 false
error(purchased)
elseif success and not purchased then
warn("金币不足!")
end
end
jumpButton.Activated:Connect(onButtonClicked)
-- 将 JumpPurchaseGui 添加到玩家的 Gui
jumpPurchaseGui.Parent = playerGui
```以下部分更详细地描述代码。
- 获取对 GUI 和服务器函数的引用 - 变量 IncreaseJumpPowerFunction、jumpPurchaseGui 和 jumpButton 包含对调用函数的函数和 GUI 的引用,这些引用稍后会用到。
- 定义事件处理程序 - onButtonClicked() 定义了用户点击升级按钮时的逻辑。它使用 pcall()(保护调用)来调用 RemoteFunction。任何这样的客户端-服务器通信都需要 pcall() 来处理错误或连接问题。
进行游戏测试
从下拉菜单中选择 测试 并点击 播放。升级跳跃 按钮会出现在右下角。
尝试在收集任何金币之前点击按钮,以检查它是否不会奖励你额外的跳跃能力,然后尝试收集一些金币,看看再次点击时升级是否有效。
代码完成后,尝试调整难度:如果节奏感觉缓慢,可以增加金币,或者如果升级过于容易,可以减少一些并将其放在更棘手的位置。