使用 roblox 上的数据存储保存游戏数据而不是玩家数据
Save game data not player data with datastore on roblox
这是一个使用 lua 和 roblox studio 的一般问题。我在我的游戏中需要保存一些信息以便与加入的玩家分享。特别是,我正在编写一款平台游戏,玩家在平台上跳跃,当他们跳上平台时,平台会变成他们团队的颜色。我需要为所有玩家更新平台颜色,而且如果玩家加入游戏中期,已经 'conquered' 的平台需要已经是那种颜色。为此,我使用 getAsync 和 setAsync。据我所知,人们大多使用数据存储来保存游戏之间的数据,但就我而言,我希望在游戏过程中检索在游戏过程中保存的数据。一旦游戏结束,数据将被设置为零。我假设数据存储是可行的方法(...?)。我遇到的问题是,据我所知,roblox 中的数据存储只允许每个键保存一个值,并且它以播放器为键保存它。但我需要三个关键值。它们是:征服平台的行、列和颜色。我也不一定需要知道玩家的 ID。我希望每个玩家在加入或更新时都能访问这个数据存储。理想情况下,我想要这样的东西:
设置:
local dataStoreService = game:GetService("DataStoreService")
local PlatformsScored = dataStoreService:GetDataStore('PlatformsScored')
在玩家得分时的函数内:
PlatformsScored:SetAsync({col, row}, platformColor)
然后,当新玩家加入时,检索并触发所有客户端and/or:
local pScoredNow = PlatformsScored:GettAsync({col, row}, platformColor)
for k, platform in (myPlatforms) do
if platform.col == col and platform.row = row do
platform.BrickColor = BrickColor.new(platformColor)
end
想法是这个 for 循环遍历所有平台并设置颜色。我一直在网上看,但我不确定这是否可能。您可以将表保存到 Roblox studio 中的数据存储吗? datastore 是否可以是不一定与作为键的玩家 ID 相关联的“'impersonal'”?谢谢
你问了很多问题,所以我会尽力一一解答
Can you save tables to datastore in Roblox studio? ... I need three values by key. These are: the row, the column and the colour of the platform conquered.
表格无法保存,但如果您的数据可以序列化,您可以使用 HttpService:JSONEncode(), and back to a table using HttpService:JSONDecode().
将 table 转换为字符串
local HttpService = game:GetService("HttpService")
local dataString = HttpService:JSONEncode({
row = 5,
column = 10,
color = "Red",
})
print(dataString)
local reconstructedData = HttpService:JSONDecode(dataString)
print(reconstructedData.row, reconstructedData.column, reconstructedData.color)
Can datastore be ''impersonal'' that is not associated necessarily with a player ID as the key
当然,您可以将信息存储在您想要的任何密钥下。但是你应该非常小心地选择密钥,因为每个游戏服务器都会写入这些密钥。这就是为什么一直推荐playerID,因为它是一个保证唯一的key,玩家不能同时在两个服务器,所以不存在两个服务器不小心同时写入同一个key的风险。
如果您有多个游戏服务器写入同一个密钥,则很有可能两个服务器会覆盖彼此的数据,从而导致某人的东西丢失。
I want the data saved during the game to be retrieved during the game... I want then every player to access this datastore when they join or when it updates.
这不是数据存储的好用例。 DataStores 应该用于持久存储有关玩家或必须跨多个服务器的世界的数据。例如,想一想全球排行榜,或者玩家的游戏进度,或者多人挖的洞有多深(假设您希望该洞在下次游戏启动时持续存在)。
如果您正在尝试访问游戏状态信息并且您仍在进行游戏,您可以让新玩家根据当前状态构建他们的游戏板。无需通过 DataStores 进行通信。
处理活动游戏状态信息的一个好方法是在服务器脚本中创建一个 "GameManager" 对象,并使其对游戏中发生的变化具有权威。球员得分?告诉 GameManager,它将更新记分牌。有玩家加入?询问 GameManager platforms/game 棋盘的当前状态。
您可以使用简单的 lua tables、RemoteEvents 和 RemoteFunctions 完成所有这些。我喜欢使用 ModuleScript 来制作我的 GameManager class。我粗略的架构大概是这样的...
local PlayerService = game:GetService("Players")
-- keep a list of RemoteFunctions and RemoteEvents that are fired by players when they do something
local GetState = game.ReplicatedStorage.Functions.GetState
local PlayerAction = game.ReplicatedStorage.Events.PlayerAction
-- keep a list of RemoteEvents that are fired by the GameManager when something should be communicated to the players
local StartGame = game.ReplicatedStorage.Events.StartGame
local UpdateBoard = game.ReplicatedStorage.Events.UpdateBoard
local EndGame = game.ReplicatedStorage.Events.EndGame
-- make an authority over the game state
local GameManager = {}
GameManager.__index = GameManager
function GameManager.new()
local gm = {
-- keep a list of players
teams = { "red" = {}, "blue" = {} },
-- keep a list of scores per team
scores = { "red" = 0, "blue" = 0 },
-- keep track of the board colors
platforms = {},
-- keep track of the state of the game
currentGameState = "WaitingForPlayers", --InGame, PostGame
-- as good housecleaning, hold onto connection tokens
__tokens = {},
}
setmetatable(gm, GameManager)
-- if anyone ever asks what the current state of the game is, let them know!
GetState.OnServerInvoke = function()
return gm.scores, gm.platforms, gm.currentGameState, gm.teams
end
return gm
end
function GameManager:waitForPlayers()
-- wait for players to join to start the game
while #PlayerService:GetPlayers() < 1 do
wait(5)
end
wait(5)
-- tell everyone the round is starting!
self:startNewGame()
end
function GameManager:startNewGame()
-- start listening to game events
local playerActionToken = PlayerAction:OnServerEvent(function(player, ...)
-- the player has done something, update the game state!
local args = { ... }
print("PlayerAction : ", player.Name, unpack(args))
-- if a platform was taken, alert all players so they can update their stuff
UpdateBoard:FireAllClients(self.platforms)
end)
table.insert(self.__tokens, playerActionToken)
-- assign players to teams...
-- tell all the players that the game has begun
StartGame:FireAllClients()
-- rather than code a game loop, just kill the game for now
spawn(function()
wait(30)
-- tell everyone the game is over
self:endGame()
end)
end
function GameManager:endGame()
self.currentGameState = "PostGame"
-- communicate to all players that the game is over, and let them know the score
EndGame:FireAllClients(self.scores)
-- stop accepting actions from the game and clean up connections
for _, token in ipairs(self.__tokens) do
token:Disconnect()
end
-- start the game over again!
spawn(function()
wait(30)
self:waitForPlayers()
end)
end
return GameManager
然后在服务器脚本中,创建 GameManager...
local GameManager = require(script.Parent.GameManager) -- or wherever you've put it
local gm = GameManager.new()
gm:waitForPlayers()
然后在 LocalScript 中,让玩家在加入游戏时请求游戏状态...
-- connect to all the game signals that the server might send
game.ReplicatedStorage.Events.StartGame:Connect(function(args)
-- construct the local game board
print("Game has started!")
end)
game.ReplicatedStorage.Events.UpdateBoard:Connect(function(newBoardState)
print("Board state has changed!")
end)
game.ReplicatedStorage.Events.EndGame:Connect(function(scores)
print("Game has ended!")
end)
-- request the current game state with a RemoteFunction
local GetState = game.ReplicatedStorage.Functions.GetState
local scores, platforms, currentGameState, teams= GetState:InvokeServer()
-- parse the current game state and make the board...
for k, v in pairs(scores) do
print(k, v)
end
for k, v in pairs(platforms) do
print(k, v)
end
print(currentGameState)
for k, v in pairs(teams) do
print(k, v)
end
查看您的问题后,我看到您询问是否可以将 table 保存在数据存储中。是的你可以。我不确定你是否可以通过 SetAsync() 来完成,但我从个人经验中知道你可以通过 UpdateAsync() 来完成,我已经做过无数次了。如果您不知道该怎么做,请按以下方法操作:
PlatformsScored:UpdateAsync("Platforms",function()
local returningTable = {col,row}
return returningTable
end)
这也回答了您关于拥有不围绕玩家旋转的钥匙的问题。你可以。也只是做同样的事情使数据存储为零,只需将 table 中的所有内容替换为 nil.
这是一个使用 lua 和 roblox studio 的一般问题。我在我的游戏中需要保存一些信息以便与加入的玩家分享。特别是,我正在编写一款平台游戏,玩家在平台上跳跃,当他们跳上平台时,平台会变成他们团队的颜色。我需要为所有玩家更新平台颜色,而且如果玩家加入游戏中期,已经 'conquered' 的平台需要已经是那种颜色。为此,我使用 getAsync 和 setAsync。据我所知,人们大多使用数据存储来保存游戏之间的数据,但就我而言,我希望在游戏过程中检索在游戏过程中保存的数据。一旦游戏结束,数据将被设置为零。我假设数据存储是可行的方法(...?)。我遇到的问题是,据我所知,roblox 中的数据存储只允许每个键保存一个值,并且它以播放器为键保存它。但我需要三个关键值。它们是:征服平台的行、列和颜色。我也不一定需要知道玩家的 ID。我希望每个玩家在加入或更新时都能访问这个数据存储。理想情况下,我想要这样的东西:
设置:
local dataStoreService = game:GetService("DataStoreService")
local PlatformsScored = dataStoreService:GetDataStore('PlatformsScored')
在玩家得分时的函数内:
PlatformsScored:SetAsync({col, row}, platformColor)
然后,当新玩家加入时,检索并触发所有客户端and/or:
local pScoredNow = PlatformsScored:GettAsync({col, row}, platformColor)
for k, platform in (myPlatforms) do
if platform.col == col and platform.row = row do
platform.BrickColor = BrickColor.new(platformColor)
end
想法是这个 for 循环遍历所有平台并设置颜色。我一直在网上看,但我不确定这是否可能。您可以将表保存到 Roblox studio 中的数据存储吗? datastore 是否可以是不一定与作为键的玩家 ID 相关联的“'impersonal'”?谢谢
你问了很多问题,所以我会尽力一一解答
Can you save tables to datastore in Roblox studio? ... I need three values by key. These are: the row, the column and the colour of the platform conquered.
表格无法保存,但如果您的数据可以序列化,您可以使用 HttpService:JSONEncode(), and back to a table using HttpService:JSONDecode().
将 table 转换为字符串local HttpService = game:GetService("HttpService")
local dataString = HttpService:JSONEncode({
row = 5,
column = 10,
color = "Red",
})
print(dataString)
local reconstructedData = HttpService:JSONDecode(dataString)
print(reconstructedData.row, reconstructedData.column, reconstructedData.color)
Can datastore be ''impersonal'' that is not associated necessarily with a player ID as the key
当然,您可以将信息存储在您想要的任何密钥下。但是你应该非常小心地选择密钥,因为每个游戏服务器都会写入这些密钥。这就是为什么一直推荐playerID,因为它是一个保证唯一的key,玩家不能同时在两个服务器,所以不存在两个服务器不小心同时写入同一个key的风险。
如果您有多个游戏服务器写入同一个密钥,则很有可能两个服务器会覆盖彼此的数据,从而导致某人的东西丢失。
I want the data saved during the game to be retrieved during the game... I want then every player to access this datastore when they join or when it updates.
这不是数据存储的好用例。 DataStores 应该用于持久存储有关玩家或必须跨多个服务器的世界的数据。例如,想一想全球排行榜,或者玩家的游戏进度,或者多人挖的洞有多深(假设您希望该洞在下次游戏启动时持续存在)。
如果您正在尝试访问游戏状态信息并且您仍在进行游戏,您可以让新玩家根据当前状态构建他们的游戏板。无需通过 DataStores 进行通信。
处理活动游戏状态信息的一个好方法是在服务器脚本中创建一个 "GameManager" 对象,并使其对游戏中发生的变化具有权威。球员得分?告诉 GameManager,它将更新记分牌。有玩家加入?询问 GameManager platforms/game 棋盘的当前状态。
您可以使用简单的 lua tables、RemoteEvents 和 RemoteFunctions 完成所有这些。我喜欢使用 ModuleScript 来制作我的 GameManager class。我粗略的架构大概是这样的...
local PlayerService = game:GetService("Players")
-- keep a list of RemoteFunctions and RemoteEvents that are fired by players when they do something
local GetState = game.ReplicatedStorage.Functions.GetState
local PlayerAction = game.ReplicatedStorage.Events.PlayerAction
-- keep a list of RemoteEvents that are fired by the GameManager when something should be communicated to the players
local StartGame = game.ReplicatedStorage.Events.StartGame
local UpdateBoard = game.ReplicatedStorage.Events.UpdateBoard
local EndGame = game.ReplicatedStorage.Events.EndGame
-- make an authority over the game state
local GameManager = {}
GameManager.__index = GameManager
function GameManager.new()
local gm = {
-- keep a list of players
teams = { "red" = {}, "blue" = {} },
-- keep a list of scores per team
scores = { "red" = 0, "blue" = 0 },
-- keep track of the board colors
platforms = {},
-- keep track of the state of the game
currentGameState = "WaitingForPlayers", --InGame, PostGame
-- as good housecleaning, hold onto connection tokens
__tokens = {},
}
setmetatable(gm, GameManager)
-- if anyone ever asks what the current state of the game is, let them know!
GetState.OnServerInvoke = function()
return gm.scores, gm.platforms, gm.currentGameState, gm.teams
end
return gm
end
function GameManager:waitForPlayers()
-- wait for players to join to start the game
while #PlayerService:GetPlayers() < 1 do
wait(5)
end
wait(5)
-- tell everyone the round is starting!
self:startNewGame()
end
function GameManager:startNewGame()
-- start listening to game events
local playerActionToken = PlayerAction:OnServerEvent(function(player, ...)
-- the player has done something, update the game state!
local args = { ... }
print("PlayerAction : ", player.Name, unpack(args))
-- if a platform was taken, alert all players so they can update their stuff
UpdateBoard:FireAllClients(self.platforms)
end)
table.insert(self.__tokens, playerActionToken)
-- assign players to teams...
-- tell all the players that the game has begun
StartGame:FireAllClients()
-- rather than code a game loop, just kill the game for now
spawn(function()
wait(30)
-- tell everyone the game is over
self:endGame()
end)
end
function GameManager:endGame()
self.currentGameState = "PostGame"
-- communicate to all players that the game is over, and let them know the score
EndGame:FireAllClients(self.scores)
-- stop accepting actions from the game and clean up connections
for _, token in ipairs(self.__tokens) do
token:Disconnect()
end
-- start the game over again!
spawn(function()
wait(30)
self:waitForPlayers()
end)
end
return GameManager
然后在服务器脚本中,创建 GameManager...
local GameManager = require(script.Parent.GameManager) -- or wherever you've put it
local gm = GameManager.new()
gm:waitForPlayers()
然后在 LocalScript 中,让玩家在加入游戏时请求游戏状态...
-- connect to all the game signals that the server might send
game.ReplicatedStorage.Events.StartGame:Connect(function(args)
-- construct the local game board
print("Game has started!")
end)
game.ReplicatedStorage.Events.UpdateBoard:Connect(function(newBoardState)
print("Board state has changed!")
end)
game.ReplicatedStorage.Events.EndGame:Connect(function(scores)
print("Game has ended!")
end)
-- request the current game state with a RemoteFunction
local GetState = game.ReplicatedStorage.Functions.GetState
local scores, platforms, currentGameState, teams= GetState:InvokeServer()
-- parse the current game state and make the board...
for k, v in pairs(scores) do
print(k, v)
end
for k, v in pairs(platforms) do
print(k, v)
end
print(currentGameState)
for k, v in pairs(teams) do
print(k, v)
end
查看您的问题后,我看到您询问是否可以将 table 保存在数据存储中。是的你可以。我不确定你是否可以通过 SetAsync() 来完成,但我从个人经验中知道你可以通过 UpdateAsync() 来完成,我已经做过无数次了。如果您不知道该怎么做,请按以下方法操作:
PlatformsScored:UpdateAsync("Platforms",function()
local returningTable = {col,row}
return returningTable
end)
这也回答了您关于拥有不围绕玩家旋转的钥匙的问题。你可以。也只是做同样的事情使数据存储为零,只需将 table 中的所有内容替换为 nil.