Сохранить данные игры, а не данные игрока с хранилищем данных на roblox - PullRequest
0 голосов
/ 15 января 2020

это общий вопрос с использованием lua и roblox studio. Я нахожусь в той точке моей игры, в которой мне нужно сохранить некоторую информацию, чтобы поделиться ею с игроками, которые присоединяются. В частности, я кодирую платформенную игру, в которой игроки прыгают на платформы, а когда они это делают, платформы переходят в цвет своей команды. Мне нужно обновить цвета платформ для всех игроков, но также, если игрок присоединяется к середине игры, платформы, которые уже «завоеваны», должны быть уже такого цвета. Для этого я использую getAsyn c и setAsyn c. Из того, что я видел, люди в основном используют хранилища данных для сохранения данных между играми, но в моем случае я хочу, чтобы данные, сохраненные во время игры, были извлечены во время игры. Как только игра закончится, данные будут установлены в ноль. Я предполагаю, что хранилища данных - это путь к go (...?). Проблема, с которой я столкнулся, заключается в том, что, насколько я могу судить, хранилища данных в roblox позволяют сохранять только одно значение на ключ, и оно сохраняется с ключом, являющимся игроком. Но мне нужно три значения по ключу. Это: строка, столбец и цвет платформы завоеваны. Мне не обязательно знать идентификатор игрока. Я хочу, чтобы каждый игрок имел доступ к этому хранилищу данных, когда он присоединяется или когда он обновляется. В идеале я хотел бы что-то вроде этого:

Настройка:

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

Идея состоит в том, что это для l oop проходит через все платформы и устанавливает цвета. Я искал на inte rnet, и я не уверен, как будто это даже возможно. Можете ли вы сохранить таблицы в хранилище данных в студии Roblox? Может ли хранилище данных быть «безличным», которое не обязательно связано с идентификатором игрока в качестве ключа? Спасибо.

Ответы [ 2 ]

0 голосов
/ 27 января 2020

Просматривая ваши вопросы, я видел, как вы спрашивали, можете ли вы сохранять таблицы в хранилищах данных. Да, ты можешь. Я не уверен, что вы можете сделать это через SetAsyn c (), но я знаю из личного опыта, что вы можете сделать это через UpdateAsyn c (), я делал это бесчисленное количество раз. Если вы не знаете, как это сделать, вот как:

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

Это также отвечает на ваш вопрос о наличии ключей, которые не вращаются вокруг игроков. Вы можете. Также просто сделайте то же самое, чтобы сделать datastore nil, просто замените все внутри таблицы на nil.

0 голосов
/ 15 января 2020

Вы задали много вопросов, поэтому я постараюсь ответить на них все

Можете ли вы сохранить таблицы в хранилище данных в студии Roblox? ... мне нужно три значения по ключу. Это: строка, столбец и цвет завоеванной платформы.

Таблицы не могут быть сохранены, но если ваши данные могут быть сериализованы, вы можете преобразовать таблицу в строку, используя 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, поскольку он является гарантированным уникальным ключом, и игроки не могут одновременно находиться на двух серверах, поэтому нет риска случайной записи двух серверов на один и тот же ключ одновременно.

Если у вас есть несколько игровых серверов, пишущих на один и тот же ключ, очень велика вероятность того, что два сервера перезапишут данные друг друга и чьи-то вещи будут потеряны.

Я хочу, чтобы данные, сохраненные во время игры, были извлечены во время игры ... Я хочу, чтобы каждый игрок имел доступ к этому хранилищу данных, когда он присоединяется или когда он обновляется.

Это не хороший вариант использования для хранилищ данных. Хранилища данных должны использоваться для постоянного хранения данных об игроках или мире, которые должны переноситься на несколько серверов. Например, подумайте о глобальной таблице лидеров, о прогрессе игры игрока или о том, насколько глубока яма, вырытая несколькими людьми (если вы хотите, чтобы эта дыра сохранялась при следующем запуске игры).

Если вы пытаетесь получить доступ к информации о состоянии игры и все еще находитесь в активной игре, вы можете просто заставить нового игрока построить свою игровую доску на основе текущего состояния. Нет необходимости сообщать об этом через DataStores.

Хороший способ обработки информации о состоянии активной игры - создать объект «GameManager» в сценарии сервера и предоставить ему полномочия в отношении изменений, происходящих в игре. А игрок забивает? Скажите GameManager, он обновит табло. Игрок присоединяется? Спросите GameManager, каково текущее состояние платформ / игрового поля.

Вы можете выполнить sh всего этого с помощью простых 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...