データストアは、異なるプレイヤーセッション間で永続的なプレイヤーデータを保存および読み込むために使用できるサービスです。これらはプレイヤーの進捗状況やインベントリなどの重要な情報を保存し、プレイヤーが次回ゲームに参加したときにそれを取得できるようにします。データストアがない場合、プレイヤーはゲームを離れるたびにすべての進捗を失ってしまいます。
データストアには標準と順序付きの2種類があります。このチュートリアルでは、データを数値的にランク付けおよびソートして、保存された数値に基づいて昇順または降順で取得できる順序付きデータストアを使用します。
ゴールドラッシュのリーダーボード作成チュートリアル - スタート の.rbxlファイルを出発点として、ゴールドラッシュのリーダーボード作成チュートリアル - 完成の.rbxlファイルを参照しながら、このチュートリアルではカスタムプレイヤーリーダーボードを作成するための基盤を提供します。その際のガイダンス内容は以下の通りです。
- 順序付きデータストアにゴールドのスコアを保存する。
- すべてのサーバーにおけるトップスコアを取得およびソートする。
- UIにカスタムリーダーボードにトップスコアを表示する。
- 数秒ごとにカスタムリーダーボードを自動的に更新する。
このチュートリアルの終わりまでには、以下の内容が得られます。
- ServerScriptServiceの下に:
- プレイヤーのスコアをリーダーボード用に順序付きデータストアに保存する更新されたGoldManagerスクリプト。
- リーダーボードからトップスコアのソートされたリストを取得して返す新しいLeaderboardRemoteHandlerモジュールスクリプト。
- クライアントからリーダーボードデータリクエストに応じてサーバーで機能する新しいLeaderboardManagerスクリプト。
- StarterGuiの下に、プレイヤーのためにリーダーボードUIをレンダリングする新しいLeaderboardGuiScriptローカルスクリプト。

APIサービスへのスタジオアクセスを有効化する
データストアはデバイスにローカルには保存されず、ゲームはそれらを使用するためにRobloxのバックエンドとのサーバー間通信に依存しています。デフォルトでは、スタジオはこの通信を制限して、悪用や誤用を防ぎます。APIサービスへのスタジオアクセスは、信頼できるゲームのみがRobloxのバックエンドサーバーの読み書き可能にするために、明示的に有効化されるまで無効になっています。
スタジオでAPIサービスへのアクセスを有効にして、データストアを使用できるようにするには:
- スタジオでゴールドラッシュのリーダーボード作成チュートリアル - スタートファイルを開きます。この出発地ファイルにはすでにプレイヤーデータの保存チュートリアルのコードとプレイヤーリーダーボードのUIスケルトンが含まれています。
- ゲームを公開します。
- スタジオに戻って、ファイル ⟩ エクスペリエンス設定 ⟩ セキュリティに進みます。
- APIサービスへのスタジオアクセスを有効にするをオンにします。
- 変更を保存します。
順序付きデータストアを作成する
データストアを作成するときは、常にサーバー側のScriptからDataStoreServiceを呼び出すべきです。これは重要です。
- Robloxは、クライアントからのすべてのデータストアアクセスをブロックして、永続的なプレイヤーデータにアクセスし、変更する権限がサーバーのみにあるようにしています。
- サーバー側のスクリプトは集中化された環境で実行されるため、データストアに読み書きされるデータが正確で有効であることが保証されます。
- クライアント側のスクリプトはプレイヤーのデバイス上で実行されるため、もしクライアントがデータストアにアクセスできる場合、どのプレイヤーでもゲームを悪用し、他のプレイヤーのデータを盗むか上書きする可能性があります。
また、データを整理して、異なるデータストアで重複したり衝突したりしないように、データストアに一意の名前を付けるべきです。このチュートリアルでは、リーダーボード用のデータストアをGlobalLeaderboardと呼びます。
GlobalLeaderboardの順序付きデータストアを作成するには:
ServerScriptServiceの下にある既存のGoldManagerスクリプトを開きます。

既存のPlayerGoldデータストアの下で、文字列**"GlobalLeaderboard"**を使ってGetOrderedDataStoreを呼び出します。これにより、プレイヤーがゴールドを獲得したときにそのスコアを保存するための順序付きデータストアが作成されます。
local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")
データストアを作成した後は、異なるスクリプト間で同じデータストアを参照できます。たとえば、GoldManagerスクリプトと、後でこのチュートリアルで作成するLeaderboardManagerモジュールスクリプトの両方でGetOrderedDataStoreを呼び出すことができます。異なる場所で同じデータストアを参照するということは、データを重複させるのではなく、2つのスクリプトが同じ集中型ストレージにアクセスしていることを意味します。これは、2人のチームメイトが一つのフォルダーを使って情報を共有するのと同じです。
プレイヤーデータをリーダーボードに送信する
データストアは、データを特定するためのキーとデータを保存するための値で構成されています。標準データストアとは異なり、順序付きデータストアではデータを値でソートできるため、リーダーボードなどを作成するのに理想的です。
順序付きデータストア内の各エントリは、数値でランク付けおよびソートできる一意のキーの下に保存され、その後、保存された数値の値に基づいて昇順または降順で取得されます。これにより、たとえば、ゲーム内でプレイヤーが収集するゴールドに応じてリアルタイムで更新されるトップ3リストを表示するために順序付きデータストアを使用できます。
| キー | 値 | |
|---|---|---|
| 説明 | キーは、プレイヤーのユーザーIDなど、特定のデータにアクセスするために使用できる一意の文字列識別子です。 キーを使用すると、データを整理して簡単に管理およびデバッグできます。 | 値は、保存または読み込みたい実際の数値データです(例:プレイヤーのスコア)。 値を使用すると、セッション間での進捗を保存し、プレイヤーが次回ゲームに参加したときにデータを取得できます。 |
| 許可された形式 | 文字列のみ。ユーザーIDなどの数値を使用している場合は、tostring()を使用して文字列に変換してください。 | 数値のみ。 |
| 例 | "Player_A", "TopScore", "123456" (ユーザーIDを文字列として) | 100, 3.14, 0, -25 |
GlobalLeaderboardの順序付きデータストアを作成したので、GoldManagerスクリプト内の既存のsaveGold関数を更新して、プレイヤーのゴールドスコアをSetAsyncを使用してカスタムリーダーボードに送信します:
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
leaderboardStore:SetAsync(tostring(userId), value)
end)
if not success then
warn("ゴールドを保存できませんでした", player.Name, ":", err)
end
end
順序付きデータストアGlobalLeaderboardは、共有フォルダーのように考えることができます。SetAsyncはフォルダーにコンテンツを追加し、GetSortedAsync(後でLeaderboardManagerモジュールスクリプトで作成します)はフォルダーの内容を読み取り、スコアでソートします。
リーダーボードのスコアを取得する
リーダーボードのスコアを取得するには、ModuleScriptを使用します。モジュールスクリプトを使用すると、コードを複数のスクリプト間で整理および再利用できます。同じロジックを異なる場所にコピーするのではなく、モジュールスクリプトに一度書いて、どこからでも呼び出すことができます。
リーダーボードのロジックをモジュールに保存すると、UIハンドラーとサーバースクリプトの両方が同じ関数を使用してトッププレイヤースコアを取得できます。たとえば、ユーザー名の取得方法やスコアのソート方法を更新する必要がある場合、1ヶ所でコードを変更するだけで済みます。モジュールを更新すると、それを使用するすべてのスクリプトも自動的に更新された動作を得ます。
カスタムリーダーボードは、異なるサーバー間でデータを共有するために以下の順序付きデータストアメソッドを使用します。
- SetAsync (GoldManagerスクリプトから)を使用してプレイヤースコアをGlobalLeaderboardの順序付きデータストアに送信します。
- GetSortedAsync(モジュールスクリプト内)を使用して、同じデータストアからすべてのサーバーのトップスコアを取得します。GetSortedAsyncメソッドは順序付きデータストアに固有であり、特定のソート順、ページサイズ、最小値、最大値に基づいて複数のソートされたキーを取得できます。
リーダーボードのスコアを取得するには:
ServerScriptServiceの下にLeaderboardManagerという新しいModuleScriptを作成します。
モジュールスクリプトの先頭で、文字列**"GlobalLeaderboard"**を使ってGetOrderedDataStoreを呼び出します。GoldManagerスクリプトで作成した同じ順序付きデータストアを参照することで、後でリーダーボードUIがトッププレイヤースコアを取得してソートできるようになります。
local DataStoreService = game:GetService("DataStoreService")local Players = game:GetService("Players")local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")他のスクリプトに公開したいすべての関数とデータを保持するためのモジュールテーブルを準備します。
local leaderboardManager = {}トッププレイヤースコアを取得するためのGetTopScoresという関数を作成します。この関数は:
- GetSortedAsyncを呼び出して、降順でlimit数のトップスコアを取得します。呼び出しが失敗した場合、コードがクラッシュするのを防ぐために空のリストが返されます。
- リーダーボードをループして、GetCurrentPageでエントリのテーブルとGetNameFromUserIdAsyncでプレイヤーのユーザー名を取得します。
- 各結果を最終リストに追加し、プレイヤーのユーザー名とそのスコアを含むリーダーボードテーブルを構築します。
- プレイヤーの最終リストを返し、リーダーボードデータをこのleaderboardManager.GetTopScores関数を呼び出した任意のスクリプトに送信します。
function leaderboardManager.GetTopScores(limit)local success, pages = pcall(function()return leaderboardStore:GetSortedAsync(false, limit)end)if not success or not pages thenreturn {}endlocal results = {}for _, entry in ipairs(pages:GetCurrentPage()) dolocal userId = tonumber(entry.key)local score = entry.valuelocal username = "不明"local ok, name = pcall(function()return Players:GetNameFromUserIdAsync(userId)end)if ok thenusername = nameendtable.insert(results, {Username = username,Score = score})endreturn resultsend以前作成したモジュールテーブルを返して、モジュールを使用可能にします。モジュールスクリプトを作成する際は、他のスクリプトがそれにアクセスし、内部の関数を呼び出せるようにするため、必ずモジュールテーブルを返さなければなりません。
return leaderboardManager
サーバーからリーダーボードデータをリクエストする
クライアントUIがリーダーボードスコアを表示するためには、クライアントがデータを要求したときにサーバーが応答する必要があります。RemoteFunctionを使用すると、クライアントはサーバーから情報をリクエストし、返答を待つことができます。
サーバーからリーダーボードデータをリクエストするには:
- ReplicatedStorageの下に、LeaderboardRemoteという名前のRemoteFunctionを挿入します。このリモート関数は、クライアントのUIスクリプトとサーバーのリーダーボードロジックをつなぐ役割を果たします。
- ServerScriptServiceの下にLeaderboardRemoteHandlerというスクリプトを作成します。このスクリプトでは:
ReplicatedStorage(クライアントとサーバー間の共有スペース)、ServerScriptService(リーダーボードモジュールを保持)、およびleaderboardRemote(クライアントがリーダーボードデータを要求するために呼び出すリモート関数)を呼び出します。
local ReplicatedStorage = game:GetService("ReplicatedStorage")local ServerScriptService = game:GetService("ServerScriptService")local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")以前に作成したLeaderboardManagerモジュールを読み込みます。これには順序付きデータストアからトップスコアを取得する関数が含まれています。
local leaderboardManager = require(ServerScriptService:WaitForChild("LeaderboardManager"))クライアントがInvokeServerを呼び出したときの動作を設定します。サーバーはトップ3スコアを取得してその結果をクライアントに送信します。
leaderboardRemote.OnServerInvoke = function(player)return leaderboardManager.GetTopScores(3)end
カスタムリーダーボードUIにデータを表示する
サーバー側のスクリプトを設定した後、ローカルスクリプトを作成して、トップ3プレイヤーを3秒ごとに取得し、ゲーム内のグローバルUIリーダーボードに結果を表示します。
カスタムリーダーボードにデータを表示するには:
StarterGui ⟩ LeaderboardGuiの下に、LeaderboardGuiScriptというローカルスクリプトを作成します。
スクリプトの先頭でリモート関数に接続します。クライアントとサーバー間の共有オブジェクトにアクセスするためにReplicatedStorageを呼び出し、その後leaderboardRemoteを呼び出して、クライアントがサーバーからリーダーボードデータをリクエストできるようにします。
local ReplicatedStorage = game:GetService("ReplicatedStorage")local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")LeaderboardGuiの下にある既存のリーダーボードUI要素を参照します。
local gui = script.Parentlocal leaderboardFrame = gui:WaitForChild("LeaderboardFrame")local entriesFrame = leaderboardFrame:WaitForChild("EntriesFrame")local template = entriesFrame:WaitForChild("LeaderboardEntry")古いリーダーボードエントリをクリアするためのclearEntriesという関数を作成します。この関数は、リーダーボード行を含むentriesFrameのすべての子をループし、新しいデータを表示する前にリーダーボードを完全に更新します。
local function clearEntries()for _, child in ipairs(entriesFrame:GetChildren()) doif child:IsA("TextLabel") and child.Name:match("^Row%d+$") thenchild:Destroy()endendendプレイヤーデータをリーダーボード行に挿入して表示するためのrenderLeaderboardという関数を作成します。dataオブジェクトは、サーバーから返されるプレイヤーのユーザー名とスコアを含むテーブルです。
local function renderLeaderboard(data)clearEntries()for i, entry in ipairs(data) dolocal row = template:Clone()row.Name = "Row" .. irow.Visible = truerow.LayoutOrder = irow.Text = string.format("%d%s位: %s - %d",i, i == 1 and "位" or i == 2 and "位" or i == 3 and "位" or "位",entry.Username, entry.Score)row.Parent = entriesFrameendend定期的にリーダーボードデータを取得するループを作成します。3秒ごとに、ループが実行され、以前にLeaderboardRemoteHandlerスクリプトで作成したInvokeServer関数を使用してサーバーを呼び出します。呼び出しが成功した場合、UIは更新されたスコアでリフレッシュされます。
while true dolocal success, data = pcall(function()return leaderboardRemote:InvokeServer()end)if success and data thenrenderLeaderboard(data)endtask.wait(3)end
最終コード
以下のコードスニペットに完全なGoldManager、LeaderboardManager、LeaderboardRemoteHandler、LeaderboardGuiScriptスクリプトのコードを示します。これらをゴールドラッシュのリーダーボード作成チュートリアル - スタートの.rbxlファイル内に直接貼り付けて実行できます。
GoldManager
GoldManagerスクリプトは、リーダーボードの更新を管理するために順序付きデータストアを作成します。
-- サービスを取得
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local DataStoreService = game:GetService("DataStoreService")
-- UIを更新するためのリモートイベント
local uiEvent = ReplicatedStorage:WaitForChild("UIEvent")
-- プレイヤーのゴールドチャンクを保存するためのデータストア
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- リーダーボード用のゴールドを保存するための順序付きデータストア
local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")
-- ゴールドチャンクの位置を決めるためのランダム数生成器を作成
local random = Random.new()
-- 単一セッションのプレイヤーのゴールドチャンクを保存するためのテーブル
local playerGold = {}
-- 定数
local GOLD_VALUE = 10 -- 各ゴールドチャンクの価値
local GOLD_REGENERATION_BOUNDS = { -- ゴールドチャンクが無作為に再配置されるエリアの境界
minX = -72,
maxX = 72,
minZ = -72,
maxZ = 72
}
local GOLD_REGEN_DELAY = 2 -- チャンクが再生成されるまでの遅延(秒)
local AUTOSAVE_INTERVAL = 30 -- プレイヤーのチャンクが保存される頻度(秒)
-- プレイヤーがゴールドチャンクを収集するのを処理する関数
local function processGoldTouch(chunk, player)
-- プレイヤーが収集したときにチャンクを隠す
chunk.Parent = nil
-- プレイヤーのセッションゴールドスコアにチャンクを追加
local userId = player.UserId
playerGold[userId] = (playerGold[userId] or 0) + GOLD_VALUE
print(player.Name, "は現在", playerGold[userId], "ゴールドを持っています")
-- このセッションの新しいゴールドスコアが反映されるようにUIスコアバーを更新する
uiEvent:FireClient(player, {
gold = playerGold[userId],
doTween = true,
showAlert = false
})
-- 少し待ってから、収集されたばかりのゴールドチャンクを無作為な場所に再生成する
task.delay(GOLD_REGEN_DELAY, function()
-- ゴールドチャンクを新しい無作為な位置に再生成する
local nextPositionX = random:NextInteger(GOLD_REGENERATION_BOUNDS.minX, GOLD_REGENERATION_BOUNDS.maxX)
local nextPositionZ = random:NextInteger(GOLD_REGENERATION_BOUNDS.minZ, GOLD_REGENERATION_BOUNDS.maxZ)
chunk.CFrame = CFrame.new(nextPositionX, 50, nextPositionZ) -- チャンクを新しい位置に移動
chunk:SetAttribute("DropCollided", false) -- 衝突フラグをリセット
chunk.Parent = workspace.GoldChunks
end)
end
-- "Gold"タグが付けられたすべてのパーツをループして、接触検知に接続する
for _, chunk in ipairs(CollectionService:GetTagged("Gold")) do
chunk.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
processGoldTouch(chunk, player)
end
end)
end
-- プレイヤーのゴールドを標準および順序付きデータストアに保存するための関数
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
leaderboardStore:SetAsync(tostring(userId), value)
end)
if not success then
warn("ゴールドを保存できませんでした", player.Name, ":", err)
end
end
-- プレイヤーがゲームに参加したときに処理する関数
local function onPlayerAdded(player)
local userId = player.UserId
print(player.Name, "がゲームに参加しました")
-- データストアからプレイヤーのゴールドを読み込もうとします
local success, storedGold = pcall(function()
return goldStore:GetAsync(userId)
end)
-- プレイヤーのデータストア値を使用して現在のセッションのゴールドスコアを設定する
local currentGold = if success and storedGold then storedGold else 0
playerGold[userId] = currentGold
-- プレイヤーのデータストア値でUIを更新する
uiEvent:FireClient(player, {
gold = currentGold,
doTween = false,
showAlert = not success
})
if success then
print(player.Name, "のために", currentGold, "ゴールドをロードしました")
else
-- プレイヤーにゴールドをロードできなかったことを通知
uiEvent:FireClient(player, { showAlert = true })
warn(player.Name, "のゴールドをロードできませんでした")
end
-- プレイヤーのゴールドを30秒ごとに自動保存するコルーチンを開始
coroutine.wrap(function()
while player.Parent do
task.wait(AUTOSAVE_INTERVAL)
if playerGold[userId] then
saveGold(player, playerGold[userId])
print(player.Name, "のために", playerGold[userId], "ゴールドを自動保存中")
end
end
end)()
end
-- プレイヤーがゲームから離れたときに処理する関数
local function onPlayerRemoving(player)
local userId = player.UserId
print(player.Name, "がゲームから退出しました")
-- プレイヤーのゴールドが追跡されていたか確認
if playerGold[userId] then
-- プレイヤーが退出する前にデータストアにゴールドを保存する
saveGold(player, playerGold[userId])
end
end
-- 参加および退出イベントを接続
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
LeaderboardManager
LeaderboardManagerモジュールスクリプト:
- GlobalLeaderboardの順序付きデータストアでGetSortedAsync()を呼び出す。
- GetNameFromUserIdAsyncを使用してユーザーIDをユーザー名に変換する。
- トップランクのプレイヤーのリストを{Username, Score}テーブルとして返す。
- クライアントがリーダーボードデータをリクエストするときにLeaderboardRemoteHandlerによって呼び出されます。
-- サービスを取得
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- リーダーボードスコアを保存するための順序付きデータストア
local leaderboardStore = DataStoreService:GetOrderedDataStore("GlobalLeaderboard")
-- リーダーボードスコアを保存するためのテーブル
local leaderboardManager = {}
-- トップスコアを返す関数
function leaderboardManager.GetTopScores(limit)
-- データストアからリーダーボードエントリのソートされたページを取得しようとする
local success, pages = pcall(function()
-- false = 降順(最高スコアが最初)
return leaderboardStore:GetSortedAsync(false, limit)
end)
-- 呼び出しが失敗した場合や何も返さない場合、警告を記録し空のテーブルを返す
if not success or not pages then
warn("リーダーボードデータの取得に失敗しました")
return {}
end
-- トッププレイヤーデータを格納するテーブルを作成
local topPlayers = {}
-- リーダーボード結果の現在のページ内の各エントリをループ
for _, entry in ipairs(pages:GetCurrentPage()) do
local userId = tonumber(entry.key) -- エントリキーを数値に変換(ユーザーIDは文字列として保存されました)
local score = entry.value -- 値はプレイヤーのスコア(ゴールドの量)
local username = "不明" -- ルックアップが失敗した場合のデフォルト名
-- プレイヤーのユーザー名をユーザーIDから取得しようとする
local ok, name = pcall(function()
return Players:GetNameFromUserIdAsync(userId)
end)
-- ルックアップが成功した場合は、実際のユーザー名を保存
if ok then
username = name
end
-- このプレイヤーとそのスコアをリストに追加
table.insert(topPlayers, {
Username = username,
Score = score
})
end
-- ユーザー名とスコアのあるトッププレイヤーの完全なリストを返す
return topPlayers
end
-- 他のスクリプトがこれを使用できるようにLeaderboardManagerモジュールを返す
return leaderboardManager
LeaderboardRemoteHandler
LeaderboardRemoteHandlerスクリプトは、クライアントにトップ3スコアを取得して返します。
-- サービスを取得
local ServerScriptService = game:GetService("ServerScriptService") -- サーバー側モジュールにアクセスする
local ReplicatedStorage = game:GetService("ReplicatedStorage") -- クライアントとサーバー間の通信オブジェクトを共有する
-- クライアントがリーダーボードデータを要求するために使用するRemoteFunctionを待つ
local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")
-- トップスコアを取得する関数を含むLeaderboardManagerモジュールを読み込む
local leaderboardManager = require(ServerScriptService:WaitForChild("LeaderboardManager"))
-- クライアントがリーダーボードのRemoteFunctionを呼び出したときのハンドラーを設定
leaderboardRemote.OnServerInvoke = function(player)
-- リーダーボードモジュールを呼び出してトップ3スコアを取得し、それをクライアントに返す
return leaderboardManager.GetTopScores(3)
end
LeaderboardGuiScript
LeaderboardGuiScriptローカルスクリプト:
- Class.RemoteHandler.InvokeServer|InvokeServerを使用して、3秒ごとにサーバーからリーダーボードデータをリクエストします。
- 隠しLeaderboardEntryテンプレートを使用して各リーダーボード行を表示します。
- 各行を「1位: ユーザー名 - スコア」という形式でフォーマットします。
- UIListLayoutを使用してリーダーボード行の作成、表示、およびレイアウトを管理します。
-- リモート関数アクセス用の共有ストレージを取得
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- サーバーからリーダーボードデータを要求するために使用されるRemoteFunctionを取得
local leaderboardRemote = ReplicatedStorage:WaitForChild("LeaderboardRemote")
-- UI参照
local gui = script.Parent -- ScreenGuiの下のLocalScript
local leaderboardFrame = gui:WaitForChild("LeaderboardFrame") -- リーダーボードのメインコンテナ
local entriesFrame = leaderboardFrame:WaitForChild("EntriesFrame") -- リーダーボードエントリが表示されるフレーム
local template = entriesFrame:WaitForChild("LeaderboardEntry") -- 行を作成するために使用される隠しテンプレートTextLabel
-- 古いリーダーボード行を削除する関数(テンプレートは除外)
local function clearEntries()
for _, child in ipairs(entriesFrame:GetChildren()) do
-- "Row1"、"Row2" などの名前が付いているラベルだけを破棄し、テンプレートをそのままにしておく
if child:IsA("TextLabel") and child.Name:match("^Row%d+$") then
child:Destroy()
end
end
end
-- UIでリーダーボードデータを表示する関数
local function renderLeaderboard(data)
-- まず古い行を削除
clearEntries()
for i, entry in ipairs(data) do
local row = template:Clone() -- 隠しテンプレートを複製
row.Name = "Row" .. i -- 一意の名前を付ける
row.Visible = true -- 可視にする
row.LayoutOrder = i -- UIListLayoutによる適切な順序を設定する
-- リーダーボード形式: "1位: ユーザー名 - 123"
row.Text = string.format("%d%s位: %s - %d",
i,
i == 1 and "位" or i == 2 and "位" or i == 3 and "位" or "位",
entry.Username,
entry.Score
)
-- UIにデータを追加
row.Parent = entriesFrame
end
end
-- メインループ:3秒ごとにリーダーボードを更新
while true do
-- サーバーにリーダーボードデータを要求
local success, data = pcall(function()
return leaderboardRemote:InvokeServer()
end)
if success and data then
-- リーダーボードに結果を表示
renderLeaderboard(data)
else
warn("リーダーボードデータの取得に失敗しました")
end
-- 再度更新するまで3秒待つ
task.wait(3)
end