【问题标题】:Save game data not player data with datastore on roblox使用 roblox 上的数据存储保存游戏数据而不是玩家数据
【发布时间】:2020-05-01 17:00:18
【问题描述】:

这是一个使用 lua 和 roblox studio 的一般问题。我在我的游戏中需要保存一些信息,以便与加入的玩家分享。特别是,我正在编写一个平台游戏,玩家在平台上跳跃,当他们跳上时,平台会变成他们团队的颜色。我需要为所有玩家更新平台颜色,但如果玩家加入游戏中期,已经“征服”的平台需要已经是该颜色。为此,我使用 getAsync 和 setAsync。据我所见,人们大多使用数据存储来保存游戏之间的数据,但就我而言,我希望在游戏期间检索保存的数据。游戏结束后,数据将设置为零。我假设数据存储是要走的路(...?)。我遇到的问题是,据我所知,roblox 中的数据存储只允许为每个键保存一个值,并且它以播放器作为键来保存它。但我需要三个键值。它们是:被征服的平台的行、列和颜色。我也不一定需要知道玩家的 id。然后,我希望每个玩家在加入或更新时都能访问此数据存储。理想情况下,我想要这样的东西:

设置:

local dataStoreService = game:GetService("DataStoreService")
local PlatformsScored = dataStoreService:GetDataStore('PlatformsScored')

玩家得分时的函数内部:

PlatformsScored:SetAsync({col, row}, platformColor)

然后,检索并触发所有客户端和/或当新玩家加入时:

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 中的数据存储区吗?数据存储可以是“非个人的”,不一定与作为键的玩家 ID 相关联吗?谢谢。

【问题讨论】:

    标签: arrays lua datastore roblox


    【解决方案1】:

    你问了很多问题,所以我会尽力解决所有问题

    您可以将表保存到 Roblox Studio 中的数据存储区吗? ...我需要三个键值。它们是:被征服平台的行、列和颜色。

    无法保存表格,但如果您的数据可以序列化,则可以使用HttpService:JSONEncode() 将表格转换为字符串,然后使用HttpService:JSONDecode() 将表格转换回表格。

    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)
    

    数据存储是否可以是“非个人的”,不一定与作为键的玩家 ID 相关联

    当然,您可以在任何您想要的键下存储信息。但是您应该非常小心地选择密钥,因为每个游戏服务器都会写入这些密钥。这就是为什么总是推荐 playerID,因为它是一个保证唯一的密钥,玩家不能同时在两个服务器中,所以不会有两个服务器意外同时写入同一个密钥的风险。

    如果您有多个游戏服务器写入同一个密钥,则两台服务器很有可能会覆盖对方的数据,从而导致某人的资料丢失。

    我希望在游戏过程中检索在游戏过程中保存的数据...我希望每个玩家在加入或更新时都能访问此数据存储。

    这不是数据存储的好用例。数据存储应该用于持久存储有关玩家或世界的数据,这些数据必须跨越多个服务器。例如,想想全球排行榜、玩家的游戏进度,或者多人挖的坑有多深(假设您希望该坑在下次游戏启动时继续存在)。

    如果您尝试访问游戏状态信息并且您仍处于活动游戏中,您可以让新玩家根据当前状态构建他们的游戏板。无需通过 DataStore 进行通信。

    处理活动游戏状态信息的一个好方法是在服务器脚本中创建一个“GameManager”对象,并使其对游戏中发生的更改具有权威性。球员得分?告诉 GameManager,它将更新记分牌。有玩家加入?询问 GameManager 平台/游戏板的当前状态。

    您可以使用简单的 lua 表、RemoteEvents 和 RemoteFunctions 来完成所有这些工作。我喜欢使用 ModuleScript 来制作我的 GameManager 类。我粗略的架构轮廓会是这样的......

    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
    

    【讨论】:

      【解决方案2】:

      通过您的问题,我看到您问是否可以将表保存在数据存储中。是的你可以。我不确定你是否可以通过 SetAsync() 来做到这一点,但我从个人经验中知道你可以通过 UpdateAsync() 来做到这一点,我已经做过无数次了。如果您不知道如何操作,请按以下步骤操作:

      PlatformsScored:UpdateAsync("Platforms",function()
           local returningTable = {col,row}
           return returningTable
      end)
      

      这也回答了您的问题,即拥有不围绕玩家旋转的钥匙。你可以。也只需执行相同的操作以使数据存储为零,只需将表中的所有内容替换为 nil。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-29
        • 2015-05-10
        • 2019-06-29
        • 1970-01-01
        • 1970-01-01
        • 2016-09-10
        • 1970-01-01
        • 2023-01-15
        相关资源
        最近更新 更多