Roblox · Дополнительное

Таблица рекордов на стене

Щит на стене со списком лучших игроков по монетам (или любой колонке leaderstats). Режим Global — лучшие со всех серверов, Server — только те, кто сейчас в игре.

Структура

Синим — что нужно создать.

Workspace
└─ Leaderboard (Model)
   ├─ Board (Part) — щит
   │  └─ SurfaceGui (SurfaceGui) — PixelsPerStud 40
   │     ├─ Title (TextLabel)
   │     └─ List (Frame) — UIListLayout, SortOrder = LayoutOrder
   ├─ Configuration (Configuration) — Stat, Mode, Top
   └─ LeaderboardServer (Script)

Шаги

  1. Щит «Board» с SurfaceGui (SizingMode PixelsPerStud, 40) → TextLabel «Title» и Frame «List» с UIListLayout.
  2. Configuration: Stat — имя колонки leaderstats (Coins), Mode — Global или Server, Top — сколько строк.
  3. Global: результаты пишутся в OrderedDataStore — он сразу отдаёт лучших по убыванию (GetSortedAsync). Обновление раз в минуту — у хранилищ есть лимиты запросов. Нужны публикация и API Services; без них таблица сама показывает лучших на сервере.
  4. Имена игроков по номеру (GetNameFromUserIdAsync) запоминаются — не спрашиваем Roblox каждую минуту.

Скрипты

LeaderboardServer

Где: Workspace → Leaderboard · Script
Зачем: Собирает лучших и рисует таблицу.

-- все игроки
local Players = game:GetService("Players")
-- общие рекорды всех серверов
local DSS = game:GetService("DataStoreService")
-- таблица рекордов
local model = script.Parent
-- экран на стене
local gui = model:WaitForChild("Board"):WaitForChild("SurfaceGui")
-- заголовок
local title = gui:WaitForChild("Title")
-- строки
local list = gui:WaitForChild("List")
-- Stat, Mode, Top
local config = model:WaitForChild("Configuration")
-- какой показатель (колонка leaderstats, например Coins)
local STAT = config.Stat.Value
-- упорядоченное хранилище — сразу отдаёт лучших
local store = DSS:GetOrderedDataStore("Top_" .. STAT)
-- имена по номеру игрока (чтобы не спрашивать каждый раз)
local names = {}

-- нарисовать строки
local function Show(rows)
    -- старые строки
    for _, child in ipairs(list:GetChildren()) do
        -- убираем
        if child:IsA("TextLabel") then child:Destroy() end
    -- конец перебора
    end
    -- каждый игрок
    for i, row in ipairs(rows) do
        -- строка
        local label = Instance.new("TextLabel")
        -- высота строки
        label.Size = UDim2.fromScale(1, 0.085)
        -- без фона
        label.BackgroundTransparency = 1
        -- по размеру
        label.TextScaled = true
        -- жирный
        label.Font = Enum.Font.GothamBold
        -- первое место — золото
        label.TextColor3 = i == 1 and Color3.fromRGB(255, 210, 60) or i <= 3 and Color3.fromRGB(220, 220, 230) or Color3.new(1, 1, 1)
        -- «1. Илья — 350»
        label.Text = i .. ". " .. row[1] .. " — " .. row[2]
        -- порядок
        label.LayoutOrder = i
        -- в таблицу
        label.Parent = list
    -- конец перебора
    end
-- конец функции
end

-- показатель игрока
local function Stat(player)
    -- его таблица
    local stats = player:FindFirstChild("leaderstats")
    -- колонка
    local value = stats and stats:FindFirstChild(STAT)
    -- число или nil
    return value and value.Value
-- конец функции
end

-- лучшие на этом сервере
local function ServerTop()
    -- строки
    local rows = {}
    -- каждый игрок
    for _, player in ipairs(Players:GetPlayers()) do
        -- его показатель
        local value = Stat(player)
        -- в список
        if value then table.insert(rows, {player.DisplayName, value}) end
    -- конец перебора
    end
    -- по убыванию
    table.sort(rows, function(a, b) return a[2] > b[2] end)
    -- только Top лучших
    while #rows > config.Top.Value do table.remove(rows) end
    -- готово
    return rows
-- конец функции
end

-- лучшие на всех серверах (нужны API Services)
local function GlobalTop()
    -- записываем результаты тех, кто здесь
    for _, player in ipairs(Players:GetPlayers()) do
        -- показатель
        local value = Stat(player)
        -- есть
        if value then
            -- в хранилище (целое число)
            pcall(function() store:SetAsync(tostring(player.UserId), math.floor(value)) end)
        -- конец проверки
        end
    -- конец перебора
    end
    -- лучшие по убыванию
    local ok, pages = pcall(function() return store:GetSortedAsync(false, config.Top.Value) end)
    -- хранилище недоступно
    if not ok then return nil end
    -- строки
    local rows = {}
    -- каждая запись
    for _, entry in ipairs(pages:GetCurrentPage()) do
        -- номер игрока
        local id = tonumber(entry.key)
        -- имени ещё не знаем
        if not names[id] then
            -- спрашиваем Roblox
            local okName, name = pcall(function() return Players:GetNameFromUserIdAsync(id) end)
            -- запоминаем
            names[id] = okName and name or entry.key
        -- конец проверки
        end
        -- строка
        table.insert(rows, {names[id], entry.value})
    -- конец перебора
    end
    -- готово
    return rows
-- конец функции
end

-- постоянно
while true do
    -- общие рекорды, если включены
    local rows = config.Mode.Value == "Global" and GlobalTop() or nil
    -- получилось
    if rows then
        -- заголовок
        title.Text = "Лучшие игроки: " .. STAT
    -- режим Server или хранилище недоступно
    else
        -- лучшие на сервере
        rows = ServerTop()
        -- заголовок
        title.Text = "Лучшие на сервере: " .. STAT
    -- конец проверки
    end
    -- рисуем
    Show(rows)
    -- общие — раз в минуту (лимиты хранилища), серверные — раз в 3 секунды
    task.wait(config.Mode.Value == "Global" and 60 or 3)
-- конец цикла
end

Проверка

Запусти Play (или Run) и убедись:

Собрать таблицу рекордов одной командой