データストアは、異なるプレイヤーセッション間で永続的なプレイヤーデータを保存およびロードするために使用できるサービスです。データストアは、プレイヤーの進捗やインベントリーのような重要な情報を保存し、次回プレイヤーがゲームに参加した際にそれを取得できるようにします。データストアがなければ、プレイヤーはゲームを離れるたびにすべての進捗を失うことになります。
データストアには2種類あります: 標準データストアと順序付きデータストアです。このチュートリアルでは、ランキングやソートが不要な数字、文字列、テーブルなどのデータを保存する標準データストアを使用します。
Gold Rushデータストアチュートリアル - スタート .rbxlファイルを出発点とし、Gold Rushデータストアチュートリアル - 完成版 .rbxlファイルを参考にしながら、このチュートリアルではプレイヤーの進捗を保存し、一貫性のあるゲームを作成するための基盤を提供します。具体的には以下についてのガイダンスを行います:
- プレイヤーが集めた金の量を保存およびロードする
- プレイヤーの金インベントリーを表示するためにUIを更新する
- プレイヤーの金インベントリーを30秒ごとに自動的に保存する
- プレイヤーがゲームを離れたときにその位置を保存する
- 再びゲームに参加したときにプレイヤーの位置を復元する
このチュートリアルの終わりまでには、ServerScriptServiceの下にデータストアを持つ2つのスクリプトがある状態になるはずです:
- プレイヤーの金を追跡、ロード、自動保存する更新されたGoldManagerスクリプト
- ゲームを離れる際にプレイヤーの位置を保存し、再びゲームに戻ったときにその位置を復元する更新されたPositionManagerスクリプト

Studio APIサービスへのアクセスを有効にする
データストアはデバイスにローカルに保存されないため、ゲームはそれを使用するためにRobloxのバックエンドとサーバー間通信に依存します。デフォルトでは、Studioはこの通信を制限して、悪用や不注意な使用を防ぎます。信頼できるゲームのみがRobloxのバックエンドサーバーからデータを読み書きできるように、StudioでのAPIサービスへのアクセスは明示的に有効にされるまで無効です。
データストアを使用できるようにするためにStudioでAPIサービスへのアクセスを有効にする手順は次の通りです:
- StudioでGold Rushデータストアチュートリアル - スタート .rbxlファイルを開き、ローカルコピーを作成します。
- Studioに戻り、ファイル ⟩ エクスペリエンス設定 ⟩ セキュリティに移動します。
- APIサービスへのStudioアクセスを有効にするをオンにします。
- 変更を保存します。
標準データストアを作成する
データストアを作成する際は、常にサーバー側のScriptからDataStoreServiceを呼び出す必要があります。そうすることが重要な理由は以下の通りです:
- Robloxはクライアントからのすべてのデータストアアクセスをブロックし、サーバーのみが永続的なプレイヤーデータにアクセスして変更できるようにします。
- サーバー側スクリプトは中央集権的な環境で実行されるため、データストアに読み書きされるデータが正確で有効であることを保証します。
- クライアント側スクリプトはプレイヤーのデバイス上で実行されるため、クライアントがデータストアにアクセスできる場合、任意のプレイヤーがゲームを悪用して他のプレイヤーのデータを盗んだり上書きする可能性があります。
データストアには、データを整理し、異なるデータストアで重複や衝突を防ぐためにユニークな名前を付ける必要があります。このチュートリアルでは、プレイヤーの金インベントリーを保存およびストアするデータストアの名前をPlayerGoldとします。
PlayerGoldデータストアを作成する手順は以下の通りです:
ServerScriptService内の既存のGoldManagerスクリプトを開きます。

スクリプトの上部で他のサービスの下にDataStoreServiceを初期化し、文字列**"PlayerGold"を使ってGetDataStore**を呼び出します。
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")
プレイヤーデータを保存およびロードする
データストアは、データを識別するためのキーとデータを保存するための値で構成されています。
| キー | 値 | |
|---|---|---|
| 説明 | キーは、特定のデータにアクセスするために使用できるユニークな識別子です。 キーを使用することでデータを整理し、簡単に管理やデバッグを行うことができます。 | 値は、保存またはロードしたい実際のデータで、プレイヤーのインベントリーや設定のようなものです。 値を使用することでセッション間での進捗を保存し、次回プレイヤーがゲームに参加する際にデータを取得できます。 |
| 許可される形式 | 文字列のみ。 | 数字、文字列、ブーリアン、またはテーブルである必要があります。 |
| 例 | "Player_A", "TopScore", "GameSetting" | 100, "Level_5", true, {gold = 100, level = 5} |
このチュートリアルでは、キーはプレイヤーのuserIdで、値は集めた金の量になります。このキーと値を使用してプレイヤーデータを保存およびロードする手順は以下の通りです:
GoldManagerスクリプトに、プレイヤーの金をPlayerGoldデータストアに保存するためのヘルパー関数saveGoldを追加します。
local function saveGold(userId, value)local success, err = pcall(function()-- `userId`はプレイヤーのユニークIDです-- `value`はそのプレイヤーのために保存する金の量ですgoldStore:SetAsync(userId, value)end)end- OPTIONALsaveGoldにプレイヤーのIDとエラーメッセージを印刷する警告を追加します。このステップは必須ではありませんが、関数が失敗した場合のデバッグが容易になるため、良いプラクティスです。local function saveGold(userId, value)local success, err = pcall(function()-- `userId`はプレイヤーのユニークIDです-- `value`はそのプレイヤーのために保存する金の量ですgoldStore:SetAsync(userId, value)end)if not success thenwarn("[SAVE ERROR] ", userId, "の金を保存できませんでした:", err)endend
onPlayerAddedイベントを変更し、プレイヤーがゲームに最初に参加した際にその金をロードするようにします。更新されたonPlayerAdded関数は以下のようになります:
- PlayerGoldデータストア内の内容をロードしようとします。プレイヤーの保存された金、またはプレイヤーが金を持っていない場合や以前にゲームをプレイしていない場合は0を返します。
- デバッグログを提供し、あなたのコードをより簡単にデバッグできるようにします。このデバッグログには、参加しているプレイヤーの保存された金、またはonPlayerAddedがデータストアにアクセスできない場合はエラーメッセージが含まれます。
- UIを更新し、プレイヤーの保存された金を画面に表示します。
local function onPlayerAdded(player)local userId = player.UserIdlocal success, storedGold = pcall(function()return goldStore:GetAsync(userId)end)if success thenlocal currentGold = storedGold or 0playerGold[userId] = currentGolduiEvent:FireClient(player, {gold = currentGold,doTween = false,showAlert = not success})elseuiEvent:FireClient(player, { showAlert = true })warn(player.Name, "の金をロードできませんでした")endendonPlayerRemovingイベントを変更し、以前に作成したsaveGold関数を呼び出して、プレイヤーの金をゲームを離れる際に保存します。
local function onPlayerRemoving(player)local userId = player.UserIdif playerGold[userId] thensaveGold(userId, playerGold[userId])endend
プレイヤーデータを自動保存する
プレイヤーのデータを自動的に保存することは良いプラクティスです。これにより、プレイヤーがデータを失うことを防ぎます。onPlayerRemovingでプレイヤーのデータを保存する場合、サーバーから予期せず切断されると、最新の進捗を失う可能性があります。
プレイヤーデータを自動保存する手順は以下の通りです:
ゲームがプレイヤーデータを自動保存する頻度を決定する新しい定数を作成します。定数は、ゲームが実行されている間、値が変わらない変数です。この定数を使用してスクリプト内で自動保存間隔を参照しやすくし、自動保存の頻度を簡単に調整できます。
-- この数は秒単位ですlocal AUTOSAVE_INTERVAL = 30既存のonPlayerAdded関数に自動保存のコルーチンを追加し、プレイヤーがゲーム内にいる間に実行されるバックグラウンドループを作成します。コルーチンは非同期で実行される関数であり、特定のポイントで一時停止し、元の位置から再開し、ブロックすることなくスクリプトの他の部分と並行して実行できます。
このスクリプトでは、自動保存コルーチンのバックグラウンドループがAUTOSAVE_INTERVAL定数の秒数を待機し、その後に以前に作成したsaveGold関数を呼び出します。
coroutine.wrap(function()while player.Parent dotask.wait(AUTOSAVE_INTERVAL)if playerGold[userId] thenprint("[AUTOSAVE] ", player.Name, "の", playerGold[userId], "金を保存しています")saveGold(userId, playerGold[userId])endendend)()
プレイヤーの位置を保存およびロードする
プレイヤーの位置を保存するには、Characterを使用します。プレイヤーのCharacterは3D世界におけるその物理モデルを表し、現在の位置や方向の座標を持ちますが、Playerオブジェクトはユーザーアカウントのみを表します。
データストアは数字、文字列、テーブルなどの基本的なデータ型しか保存できないため、Vector3やCFrameのような複雑なオブジェクトを直接保存することはできません。プレイヤーの位置を保存するには、それをX、Y、Zの3つの別々の数字に分割し、個別に保存する必要があります。後で位置をロードする際には、保存された座標を使用してVector3を再構築できます。
キャラクターの位置を保存およびロードする手順は以下の通りです:
ServerScriptService内の既存のPositionManagerスクリプトを開きます。
スクリプトの上部でDataStoreServiceを初期化し、文字列**"PlayerPosition"を使ってGetDataStore**を呼び出します。
local DataStoreService = game:GetService("DataStoreService")local positionStore = DataStoreService:GetDataStore("PlayerPosition")プレイヤーのuserIdとVector3位置を受け取るヘルパー関数savePositionを追加します。Vector3値を直接保存することはできないため、位置をX、Y、Zの数値のテーブルに変換します。
local function savePosition(player, position)local userId = player.UserIdlocal success, err = pcall(function()positionStore:SetAsync(userId, {position.X, position.Y, position.Z})end)end- OPTIONALsavePositionに、位置を保存できなかったプレイヤーの名前とエラーメッセージを印刷する警告を追加します。このステップは必須ではありませんが、関数が失敗した場合のデバッグを容易にするために良いプラクティスです。local function savePosition(player, position)local userId = player.UserIdlocal success, err = pcall(function()positionStore:SetAsync(userId, {position.X, position.Y, position.Z})end)if not success thenwarn("位置を保存できませんでした:", player.Name, ":", err)endend
保存された座標をPlayerPositionデータストアからロードするためのloadPositionという別のヘルパー関数を追加します。PivotToを使用して、キャラクターの位置を世界に復元します。プレイヤーの保存された位置はテーブルとして返されるため、Vector3を再構築し、キャラクターを移動させるためにCFrameに変換する必要があります。
local function loadPosition(userId, character)local userId = player.UserIdlocal success, savedCoords = pcall(function()return positionStore:GetAsync(userId)end)if success and savedCoords thenlocal pos = Vector3.new(savedCoords[1], savedCoords[2], savedCoords[3])print(player.Name, "の位置を復元しました")character:PivotTo(CFrame.new(pos))elseif not success thenwarn("位置をロードできませんでした:", player.Name)endendonPlayerAddedイベントを変更し、ゲームに参加するすべてのプレイヤーの位置ロジックを設定します。更新されたonPlayerAdded関数内では:
- CharacterAddedが呼び出され、プレイヤーのキャラクターがスポーンしたときにloadPositionが呼び出されて最後に知られている位置を復元します。
- CharacterRemovingが呼び出され、ゲームから削除される場合にプレイヤーのキャラクターの現在の位置を保存するためにsavePositionが呼び出されます。
- **GetPivot**が呼び出され、削除される際のキャラクターの世界内の正確な位置を取得します。
local function onPlayerAdded(player)local userId = player.UserIdplayer.CharacterAdded:Connect(function(character)loadPosition(player, character)end)player.CharacterRemoving:Connect(function(character)local pos = character:GetPivot().PositionsavePosition(player, pos)end)endPlayer.PlayerAdded:Connect(onPlayerAdded)
最終コード
以下に、完全なGoldManagerおよびPositionManagerスクリプトのコードスニペットを示します。これらをGold Rushデータ保存チュートリアル - スタート .rbxlファイル内に直接貼り付けて実行できます。
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 playerGold = {}
-- 定数
local GOLD_VALUE = 10 -- 各金のチャンクの価値
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()
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)
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)
if success then
-- データストアの値を使用して現在のセッションの金スコアを設定します
local currentGold = storedGold or 0
playerGold[userId] = currentGold
-- プレイヤーのデータストア値を使用してUIを更新します
uiEvent:FireClient(player, {
gold = currentGold,
doTween = false,
showAlert = false
})
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)
PositionManager
-- サービスを取得
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- プレイヤーの位置を保存するためのデータストア
local positionStore = DataStoreService:GetDataStore("PlayerPosition")
-- プレイヤーの位置を{X, Y, Z}のテーブルとして保存する関数
local function savePosition(player, position)
local userId = player.UserId
local success, err = pcall(function()
positionStore:SetAsync(userId, {position.X, position.Y, position.Z})
end)
if not success then
warn("位置を保存できませんでした:", player.Name, ":", err)
end
end
-- プレイヤーの最後の保存位置をロードし、キャラクターを移動させる関数
local function loadPosition(player, character)
local userId = player.UserId
local success, savedCoords = pcall(function()
return positionStore:GetAsync(userId)
end)
if success and savedCoords then
local pos = Vector3.new(savedCoords[1], savedCoords[2], savedCoords[3])
print("の位置を復元しました", player.Name)
character:PivotTo(CFrame.new(pos))
elseif not success then
warn("位置をロードできませんでした:", player.Name)
end
end
-- プレイヤーがゲームに参加する際の処理を行う関数
local function onPlayerAdded(player)
local userId = player.UserId
-- プレイヤーのキャラクターがスポーンしたときにその位置をロードしようとします
player.CharacterAdded:Connect(function(character)
loadPosition(player, character)
end)
-- プレイヤーのキャラクターが削除されたときにその位置を保存します
player.CharacterRemoving:Connect(function(character)
local pos = character:GetPivot().Position
savePosition(player, pos)
end)
end
Players.PlayerAdded:Connect(onPlayerAdded)