现在你可以检测玩家收集硬币的时刻了,你需要计算玩家收集了多少硬币并在排行榜上显示这一数量。
创建一个模块脚本以记录硬币收集
为了处理每个玩家的硬币收集数据的存储和管理,你需要创建一个 ModuleScript 对象,以包含一个数据结构和访问每个玩家硬币收集数据的函数。模块脚本是可以被其他脚本调用的可重用代码。在这种情况下,CoinService 需要这个模块脚本,以便在玩家触摸硬币时更新硬币收集数据。
创建 PlayerData在 ServerStorage 中创建一个名为 PlayerData 的 ModuleScript,并添加以下代码:```lualocal PlayerData = {}PlayerData.COIN_KEY_NAME = "Coins"local playerData = {--[[[userId: string] = {["Coins"] = coinAmount: number}]]}local function defaultPlayerData()return {[PlayerData.COIN_KEY_NAME] = 0}endlocal function getData(player)local data = playerData[tostring(player.UserId)] or defaultPlayerData()playerData[tostring(player.UserId)] = datareturn dataendfunction PlayerData.getValue(player, key)return getData(player)[key]endfunction PlayerData.updateValue(player, key, updateFunction)local data = getData(player)local oldValue = data[key]local newValue = updateFunction(oldValue)data[key] = newValuereturn newValueendreturn PlayerData```
模块脚本定义了一个 PlayerData 表,该表包含零个或多个 playerData 表,表示玩家的硬币收集数据。每个需要这个模块脚本的脚本都将接收相同的 PlayerData 表副本,允许多个脚本修改和共享硬币收集数据。
声明数据结构
模块脚本以声明一个空表 PlayerData 开始,该表在脚本结束时返回。它还包含访问器方法以获取和设置表中的值。
playerData 表包含描述表结构的注释,使代码更易于理解。在这种情况下,playerData 表包含一个 userId 和一个对应字段 Coins,表示该玩家收集的硬币数量。
local PlayerData = {}PlayerData.COIN_KEY_NAME = "Coins"local playerData = {--[[[userId: string] = {["Coins"] = coinAmount: number}]]}...return PlayerData
定义本地数据访问器
getData() 是一个本地函数,用于检索特定 playerData 表的数据。如果玩家还没有收集硬币,它将返回 defaultPlayerData() 函数中的一个表,以确保每个玩家都有某些相关的数据。一个常见的约定是创建简单的公共函数,将逻辑卸载到本地作用域的函数中来完成繁重的工作。
local function defaultPlayerData()
return {
[PlayerData.COIN_KEY_NAME] = 0
}
end
local function getData(player)
local data = playerData[tostring(player.UserId)] or defaultPlayerData()
playerData[tostring(player.UserId)] = data
return data
end
定义公共数据访问器
getValue() 和 updateValue() 是面向公共的函数,其他需要这个模块脚本的脚本可以调用。在我们的例子中,CoinService 使用这些函数在玩家触摸硬币时更新该玩家的硬币收集数据。
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
实现排行榜
你可以通过屏幕上的排行榜以可视化方式呈现硬币收集数据。Roblox 包含一个内置系统,自动生成一个使用默认 UI 的排行榜。
创建排行榜在 ServerStorage 中创建一个名为 Leaderboard 的 ModuleScript,并添加以下代码:```lualocal Leaderboard = {}-- 创建新的排行榜local function setupLeaderboard(player)local leaderstats = Instance.new("Folder")-- 'leaderstats' 是 Roblox 识别的一个保留名称,用于创建排行榜leaderstats.Name = "leaderstats"leaderstats.Parent = playerreturn leaderstatsend-- 创建一个新的排行榜统计值local function setupStat(leaderstats, statName)local stat = Instance.new("IntValue")stat.Name = statNamestat.Value = 0stat.Parent = leaderstatsreturn statend-- 更新玩家的统计值function Leaderboard.setStat(player, statName, value)local leaderstats = player:FindFirstChild("leaderstats")if not leaderstats thenleaderstats = setupLeaderboard(player)endlocal stat = leaderstats:FindFirstChild(statName)if not stat thenstat = setupStat(leaderstats, statName)endstat.Value = valueendreturn Leaderboard```
以下部分更详细地描述了排行榜的工作原理。
创建排行榜
setupLeaderboard() 函数创建一个名为 leaderstats 的新文件夹实例,并将其设置为指定玩家的子级。Roblox 自动识别名为 leaderstats 的文件夹作为统计数据的容器,并创建一个 UI 元素来显示统计数据。它要求 leaderstats 中的值必须存储为“值”对象(例如 StringValue、IntValue 或 NumberValue)。
-- 创建新的排行榜
local function setupLeaderboard(player)
local leaderstats = Instance.new("Folder")
-- 'leaderstats' 是 Roblox 识别的一个保留名称,用于创建排行榜
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
return leaderstats
end
-- 创建一个新的排行榜统计值
local function setupStat(leaderstats, statName)
local stat = Instance.new("IntValue")
stat.Name = statName
stat.Value = 0
stat.Parent = leaderstats
return stat
end
更新玩家统计数据
setStat() 是 Leaderboard 模块中唯一的公共函数。它为指定玩家或排行榜本身创建统计值(如果它尚不存在)。
FindFirstChild() 接受一个对象的名称,如果存在则返回该对象,如果不存在则返回 nil。这是一个常见的安全方法,可以在使用对象之前检查它是否存在。
-- 更新玩家的统计值
function Leaderboard.setStat(player, statName, value)
local leaderstats = player:FindFirstChild("leaderstats")
if not leaderstats then
leaderstats = setupLeaderboard(player)
end
local stat = leaderstats:FindFirstChild(statName)
if not stat then
stat = setupStat(leaderstats, statName)
end
stat.Value = value
end
集成模块脚本
在两个模块就位后,在 CoinService 脚本中导入它们,以管理和显示玩家硬币数据。
更新 CoinService在 ServerScriptService 中,用以下代码替换现有 CoinService 脚本的代码:```lua-- 初始化服务和变量local Workspace = game:GetService("Workspace")local Players = game:GetService("Players")local ServerStorage = game:GetService("ServerStorage")-- 模块local Leaderboard = require(ServerStorage.Leaderboard)local PlayerData = require(ServerStorage.PlayerData)local coinsFolder = Workspace.World.Coinslocal coins = coinsFolder:GetChildren()local COIN_KEY_NAME = PlayerData.COIN_KEY_NAMElocal COOLDOWN = 10local COIN_AMOUNT_TO_ADD = 1local function updatePlayerCoins(player, updateFunction)-- 更新硬币表local newCoinAmount = PlayerData.updateValue(player, COIN_KEY_NAME, updateFunction)-- 更新硬币排行榜Leaderboard.setStat(player, COIN_KEY_NAME, newCoinAmount)end-- 定义事件处理器local function onCoinTouched(otherPart, coin)if coin:GetAttribute("Enabled") thenlocal character = otherPart.Parentlocal player = Players:GetPlayerFromCharacter(character)if player then-- 玩家触碰了硬币coin.Transparency = 1coin:SetAttribute("Enabled", false)updatePlayerCoins(player, function(oldCoinAmount)oldCoinAmount = oldCoinAmount or 0return oldCoinAmount + COIN_AMOUNT_TO_ADDend)task.wait(COOLDOWN)coin.Transparency = 0coin:SetAttribute("Enabled", true)endendend-- 设置事件监听器for _, coin in coins docoin:SetAttribute("Enabled", true)coin.Touched:Connect(function(otherPart)onCoinTouched(otherPart, coin)end)end```
对原有 CoinService 脚本的更改包括:
- 声明 COIN_AMOUNT_TO_ADD 为玩家收集硬币时要增加的硬币数量,COIN_KEY_NAME 为 PlayerData 中定义的键名称。
- 创建助手函数 updatePlayerCoins() 来更新玩家的硬币数量和相关的排行榜统计数据。
- 在 onCoinTouched() 中用 updatePlayerCoins() 的调用替换占位符 print() 语句。
试玩
从下拉菜单中选择 测试 并点击 播放。走进一个硬币,确认排行榜在角落中出现,并且随着你收集更多硬币,硬币数量增加。