游戏经常需要在会话之间存储 持续数据 ,例如玩家的等级、经验积分、金币、库存物品、位置等。
本教程显示了如何创建基本 数据存储 、保存玩家数据并读回数据到游戏会话中。
启用工作室存取
默认情况下,工作室测试的游戏无法访问数据存储,因此您必须先启用它们:
发布经验。
选择 文件 和 游戏设置 。
在 安全 部分,启用 启用 Studio 访问 API 服务 并单击 保存 。
创建数据存储库
数据存储需要一个独特的 名称 。这个例子创建了一个名为 PlayerGold 的数据存储,用于永久存储每个玩家的金币:
在 Script 内创建一个名为 ServerScriptService 的 **** 。
数据库由 DataStoreService 管理,因此获取服务:
local DataStoreService = game:GetService("DataStoreService")调用 DataStoreService:GetDataStore() 使用字符串 "PlayerGold" .此方法访问已存在的 PlayerGold 数据存储,如果存在。如果它不存在,方法创建一个新的数据存储并将其命名为 PlayerGold 。
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")
保存数据
数据存储是本质上像 Luau 表一样的词典。数据存储中的每个值由独特的 键 进行索引,可能是玩家独特的 UserId 或仅仅是游戏促销的命名字符串。
Key | Value |
---|---|
31250608 | 50 |
351675979 | 20 |
505306092 | 78000 |
要将玩家数据保存到数据存储中:
创建一个名为 playerUserID 的变量为数据存储键。然后,使用 playerGold 来存储玩家的初始黄金数量。
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")-- 数据存储键和值local playerUserID = 505306092local playerGold = 250要将数据保存到 PlayerGold 数据存储中,在保护调用中调用 SetAsync ,传递之前创建的键和值变量。
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")-- 数据存储键和值local playerUserID = 505306092local playerGold = 250-- 设置数据存储关键字local success, error = pcall(function()goldStore:SetAsync(playerUserID, playerGold)end)if not success thenwarn(error)end
像 SetAsync() 这样的函数是可能会时不时失败的网络调用。如上所示,pcall() 用于检测并处理发生这类故障时。
在最基本的形式下, pcall() 接受一个函数并返回两个值:
- 状态,如果函数没有错误地执行,则为 true;否则为 false。
- 函数的返回值或错误消息。
上面的示例在第 13 行检查状态。如果 SetAsync() 因任何原因失败,示例将在 输出 窗口中显示错误。
读取数据
要从数据存储中读取数据,请调用 GetAsync() 并输入所需的键名。
local DataStoreService = game:GetService("DataStoreService")
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- 数据存储键和值
local playerUserID = 505306092
local playerGold = 250
-- 设置数据存储关键字
local setSuccess, errorMessage = pcall(function()
goldStore:SetAsync(playerUserID, playerGold)
end)
if not setSuccess then
warn(errorMessage)
end
-- 阅读数据存储关键
local getSuccess, currentGold = pcall(function()
return goldStore:GetAsync(playerUserID)
end)
if getSuccess then
print(currentGold)
end
要测试脚本,请单击 运行 并注意打印到currentGold窗口的 值 。请注意,由于函数必须连接到数据存储服务器,可能需要几秒钟时间。
自动阅读并保存
以前的脚本工作了,但有一个根本问题:它包含 playerUserID 和 playerGold 的硬编码值,因此它不支持多个拥有不同数量金币的玩家。更现实的解决方案在玩家连接到体验时读取金值,然后在玩家离开时保存它。这种方法意味着将数据存储调用连接到事件从Players中。
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- 将每个玩家的金币值添加到本地表以避免击中数据
-- 重复存储。
local playerGold = {}
local function incrementGold(player, amount)
playerGold[player.UserId] += amount
end
local function onPlayerAdded(player)
-- 阅读数据存储关键
local success, storedGold = pcall(function()
return goldStore:GetAsync(player.UserId)
end)
if success then
local currentGold
if storedGold then
currentGold = storedGold
else
currentGold = 0
end
playerGold[player.UserId] = currentGold
print(currentGold)
end
-- 测试增量黄金
incrementGold(player, 5)
end
local function onPlayerRemoving(player)
-- 设置数据存储关键字
local success, err = pcall(function()
goldStore:SetAsync(player.UserId, playerGold[player.UserId])
end)
if not success then
warn(err)
end
-- 清理入口,使表在服务器的生命周期内不会增长
playerGold[player.UserId] = nil
end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
阅读并保存字符位置
为了保存玩家位置,你与 Character 而不是 Player 工作,但原则相同。这次,在 Script 内创建一个 ServerScriptService 被称为 位置管理器 的:
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local Workspace = game:GetService("Workspace")
local playerPositionStore = DataStoreService:GetDataStore("PlayerPositionStore")
local function positionHandler(player)
-- 在角色添加时加载位置
player.CharacterAdded:Connect(function(character)
local success, coords = pcall(function()
return playerPositionStore:GetAsync(player.UserId)
end)
local position = Vector3.new(coords[1], coords[2], coords[3])
if success and position then
character:PivotTo(CFrame.new(position))
print("Loaded player position!")
else
warn("Failed to load position for player " .. player.Name .. ". Placing in default position.")
end
-- 处理玩家在死亡时重生
local humanoid = character:FindFirstChildOfClass("Humanoid")
humanoid.Died:Connect(function()
local spawnLocation = Workspace:FindFirstChild("SpawnLocation")
character:PivotTo(spawnLocation.CFrame)
end)
end)
-- 在角色移除时保存位置
player.CharacterRemoving:Connect(function(character)
local position = character:GetPivot().Position
local success, err = pcall(function()
playerPositionStore:SetAsync(player.UserId, {position.X, position.Y, position.Z})
print("Saved player position!")
end)
if not success then
warn("Failed to save position for player " .. player.Name .. ": " .. err)
end
end)
end
Players.PlayerAdded:Connect(positionHandler)
这段脚本添加了一个新的数据存储,playerPositionStore。因为数据存储只存储基本类型而不是对象,所以您必须将 X、Y 和 Z 坐标存储为单个数字而不是单个 Vector3 或 CFrame 值。当您测试您的体验时,移动您的角色。注意你的角色下次测试体验时是否返回到同一位置
示例项目
现在您已经理解了基本数据存储的使用,请在 黄金淘宝 示例游戏中进行测试。您还可以在工作室编辑游戏,并探索增强的 GoldManager 脚本,该脚本将金币显示为 UI 的一部分,并包含自动保存功能。