Roblox Studioでコイン数を保存する:Data Storeの使い方
Data StoreへプレイヤーのScoreを保存し、ゲームを退出して入り直したあとも、集めたコイン数を復元できるようにしよう。

ゲームを退出したあともコイン数を残し、次に参加したとき、拾う前から前回のScore = 3へ戻るようにする。完成までの目安は12分だ。Robuxは必要ないが、自分が所有するゲームをRobloxへPublishしておく必要がある。

この記事は、触れると増えるコインの記事の続きだ。Playするたびに3枚が戻り、Scoreが0から始まる状態を用意しよう。まだRobloxへ保存していない場合は、先にゲームを非公開で保存する記事を進める。
重要 — 公開中の本番ゲームでは試さない
Studioのテストと実際のゲームは同じData Storeを使う。Roblox公式も、公開中の本番ゲームではなく別のテスト版でStudio accessを有効にするよう案内している。この記事では、テスト用ゲームと
PlayerScore_v1という新しい保存箱を使おう。
1. StudioからData Storeを使えるようにする
Creator Hubで対象のテストゲームを開き、左側の環境設定 > 設定へ進む。APIまで下へスクロールし、API サービスへのStudio アクセスを有効にするへチェックを入れて、変更を保存を押そう。

StudioではFile > Experience Settings > Securityから同じ設定を開ける。Experience Settingsの公式一覧では、この項目をData Storeなどのテストに使う設定として説明している。
Tip — APIは保存箱へつなぐ窓口
Data Storeは端末内のファイルではなく、Roblox側へ置かれる保存箱だ。APIはStudioとその保存箱をつなぐ窓口になる。ローカルファイルのままではゲームを識別できないため、Publish済みゲームが必要だ。
この設定を有効にするのは、この記事の動作確認に使うテストゲームだけにしよう。チェックを入れると、Studioで実行したScriptもそのゲームのData Storeを読み書きできるようになる。公開中のゲームで試すと、遊んでいる人の保存値と混ざる可能性がある。テスト用ゲームなら、失敗しても実際の進み具合へ影響させずにやり直せる。
2. SaveScoreを追加する
Studioへ戻り、ExplorerのServerScriptServiceへScriptを追加する。名前をSaveScoreにしよう。LeaderboardとCoinCollectorは消さず、3本を並べる。

SaveScoreのコードをすべて消し、次へ置き換えよう。
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local scoreStore = DataStoreService:GetDataStore("PlayerScore_v1")
local loadedPlayers = {}
local savedPlayers = {}
local function getScore(player)
local leaderstats = player:WaitForChild("leaderstats")
return leaderstats:WaitForChild("Score")
end
local function getKey(player)
return "player_" .. player.UserId
end
local function loadScore(player)
local score = getScore(player)
local success, savedScore = pcall(function()
return scoreStore:GetAsync(getKey(player))
end)
if not success then
warn("Score load failed:", savedScore)
return
end
if typeof(savedScore) == "number" then
score.Value += savedScore
end
loadedPlayers[player] = true
print("Score loaded:", player.Name, score.Value)
end
local function saveScore(player)
if not loadedPlayers[player] then
warn("Score save skipped because load failed:", player.Name)
return
end
if savedPlayers[player] then
return
end
local score = getScore(player)
local success, errorMessage = pcall(function()
scoreStore:UpdateAsync(getKey(player), function()
return score.Value
end)
end)
if success then
savedPlayers[player] = true
print("Score saved:", player.Name, score.Value)
else
warn("Score save failed:", errorMessage)
end
end
Players.PlayerAdded:Connect(loadScore)
Players.PlayerRemoving:Connect(saveScore)
game:BindToClose(function()
for _, player in Players:GetPlayers() do
saveScore(player)
end
end)
3. 読み込みの仕組みを確認する
GetDataStore("PlayerScore_v1")は、このゲーム内で使う保存箱の名前を決める。名前を変えると別の保存箱になるため、途中で書き換えないようにしよう。
その中では、参加者ごとにkeyとvalueを1組で保存する。
key: player_11328632018
value: 3
keyはロッカー番号、valueは中身のような関係だ。表示名ではなくUserIdを使うため、あとで名前を変えても同じ人のScoreを開ける。
PlayerScore_v1は全員で共通する保存箱の名前で、player_から始まるkeyは参加者ごとの引き出しだ。参加者が10人いても保存箱を10個作るのではなく、1つの保存箱の中で10個のkeyを使い分ける。v1は最初の保存形式だと分かる目印で、今後データの形を大きく変えるときに別名へ切り替えやすくなる。
GetAsync()は参加時に保存値を読む。公式のData Store解説にあるように、保存先への通信は失敗する場合がある。そのためpcall()で囲み、成功したかと結果を分けて受け取る。
Tip — pcallは失敗を受け止める囲い
pcall()の中でAPIが失敗しても、Script全体を赤いエラーで止めず、success = falseとして次の判断へ進める。今回は警告を出し、保存済みか分からない0をあとで上書きしない。
保存値が数字なら、現在のScoreへ加える。読み込みを待つ短い間に1枚取っても、その1点を消さずに保存値と合わせられる。初参加で保存値がない場合は0のままだ。
4. 退出時に現在のScoreを保存する
PlayerRemovingはプレイヤーがゲームを離れるときの合図だ。そこでUpdateAsync()を呼び、現在のScoreを返す。公式は、複数serverから同じkeyを更新する可能性がある場合にUpdateAsyncを使う方法を示している。
BindToClose()はserverを閉じる直前の最後の保存機会だ。StudioでStopしたときやserver終了時にも、残っている参加者を保存する。savedPlayersは同じセッションの成功書き込みを1回に制限する。
読み込みに失敗した参加者はloadedPlayersへ入らない。退出時の保存を見送るため、以前の値があるか分からない状態で0を上書きしない。失敗したセッションで取ったコインは保存されないが、以前の安全な値を守れる。
コインへ触れるたびには保存しない
この記事では、コインを取った瞬間はScoreだけを変更し、Data Storeへの書き込みは退出時にまとめる。Data Storeは画面内の数字を毎回変える場所ではなく、セッションをまたいで残したい値を預ける場所だ。
3枚なら触れるたびに保存しても少なく見えるが、コインが100枚になったり参加者が増えたりすると、短時間のAPI通信が多くなる。Play中はScoreを正本として素早く更新し、退出時に最後の値を保存する流れをまず身につけよう。
5. 2回のPlayで保存と復元を確かめる
まず1回目のPlayを始めよう。Outputに次のような行が出れば、読み込みは成功している。
Score loaded: robtsuku 0
3枚のコインを拾ってScore = 3にし、Stopを押す。Outputで保存成功を確認しよう。

Score saved: robtsuku 3
もう一度Playを押す。今回はコインへ触れる前に、右上のScoreが3へ戻り、Outputにも読み込み結果が出る。

Score loaded: robtsuku 3
次の4点が見えれば完成だ。
- 1回目に3枚を取るとScore 3
- Stop時に
Score savedと3 - 2回目は触れる前からScore 3
- 赤いData Storeエラーがない
2回目のPlayで確認するときは、キャラクターを動かす前に右上とOutputを見る。コインへ触れてからScore 3になった場合は、保存値が戻った証拠にならない。参加直後から3なら、GetAsync()で前のセッションの値を読めたと判断できる。
保存されないとき
StudioAccessToApisNotAllowed: Creator HubのAPI設定へチェックを入れ、変更を保存してからStudioでPlayし直す- API設定が見つからない: ゲームをローカルファイルではなくRobloxへPublishし、所有者のアカウントでCreator Hubを開く
- 毎回0になる:
PlayerScore_v1と"player_" .. player.UserIdを両方の処理で同じまま使う - LocalScriptでエラーになる: Data Storeへアクセスできるのはserver側だけなので、
SaveScoreをServerScriptServiceの通常のScriptへ置く Score load failed: 一時的な通信失敗の可能性がある。現在のセッションでは保存を試さず、少し待って新しいPlayで再確認する- 短時間に何度も警告が出る: PlayとStopの連打をやめ、1回の読み込み、取得、保存が終わってから次のテストを始める
完成
これで、コインを拾ったScoreがRoblox側へ保存され、退出と再参加をまたいで戻るようになった。leaderstatsは画面表示、Data Storeは長期保存という別の役割だ。
次は、この保存済みデータを使いながら、ゲームパス所有者だけが通れるVIPドアを作る。


