保存数据

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

游戏经常需要在会话之间存储 持续数据 ,例如玩家的等级、经验积分、金币、库存物品、位置等。

本教程显示了如何创建基本 数据存储 、保存玩家数据并读回数据到游戏会话中。

启用工作室存取

默认情况下,工作室测试的游戏无法访问数据存储,因此您必须先启用它们:

  1. 发布经验。

  2. 选择 文件游戏设置

  3. 安全 部分,启用 启用 Studio 访问 API 服务 并单击 保存

创建数据存储库

数据存储需要一个独特的 名称 。这个例子创建了一个名为 PlayerGold 的数据存储,用于永久存储每个玩家的金币:

  1. Script 内创建一个名为 ServerScriptService 的 **** 。

  2. 数据库由 DataStoreService 管理,因此获取服务:


    local DataStoreService = game:GetService("DataStoreService")
  3. 调用 DataStoreService:GetDataStore() 使用字符串 "PlayerGold" .此方法访问已存在的 PlayerGold 数据存储,如果存在。如果它不存在,方法创建一个新的数据存储并将其命名为 PlayerGold


    local DataStoreService = game:GetService("DataStoreService")
    local goldStore = DataStoreService:GetDataStore("PlayerGold")

保存数据

数据存储是本质上像 Luau 表一样的词典。数据存储中的每个值由独特的 进行索引,可能是玩家独特的 UserId 或仅仅是游戏促销的命名字符串。

KeyValue
3125060850
35167597920
50530609278000

要将玩家数据保存到数据存储中:

  1. 创建一个名为 playerUserID 的变量为数据存储键。然后,使用 playerGold 来存储玩家的初始黄金数量。


    local DataStoreService = game:GetService("DataStoreService")
    local goldStore = DataStoreService:GetDataStore("PlayerGold")
    -- 数据存储键和值
    local playerUserID = 505306092
    local playerGold = 250
  2. 要将数据保存到 PlayerGold 数据存储中,在保护调用中调用 SetAsync ,传递之前创建的键和值变量。


    local DataStoreService = game:GetService("DataStoreService")
    local goldStore = DataStoreService:GetDataStore("PlayerGold")
    -- 数据存储键和值
    local playerUserID = 505306092
    local playerGold = 250
    -- 设置数据存储关键字
    local success, error = pcall(function()
    goldStore:SetAsync(playerUserID, playerGold)
    end)
    if not success then
    warn(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窗口的 。请注意,由于函数必须连接到数据存储服务器,可能需要几秒钟时间。

自动阅读并保存

以前的脚本工作了,但有一个根本问题:它包含 playerUserIDplayerGold 的硬编码值,因此它不支持多个拥有不同数量金币的玩家。更现实的解决方案在玩家连接到体验时读取金值,然后在玩家离开时保存它。这种方法意味着将数据存储调用连接到事件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 坐标存储为单个数字而不是单个 Vector3CFrame 值。当您测试您的体验时,移动您的角色。注意你的角色下次测试体验时是否返回到同一位置

示例项目

现在您已经理解了基本数据存储的使用,请在 黄金淘宝 示例游戏中进行测试。您还可以在工作室编辑游戏,并探索增强的 GoldManager 脚本,该脚本将金币显示为 UI 的一部分,并包含自动保存功能。