「ゲームの中にお店を作って、集めたコインで買い物できるようにしたい」「商品を増やすたびにボタンを作り直すのが大変」
ロブロックス(Roblox)スタジオでショップ(お店の画面)を作る方法を、実際の画像付きで誰でも簡単に分かるように解説します。この記事では、商品の一覧を1つのModuleScriptにまとめて、1行足すだけでお店のボタンが増える作りにします。お金を減らして商品を渡すのは、サーバーで動くScriptだけにします。
上級ステップ3/40 前の記事:ロブロックス(Roblox)のドアの作り方 全体の順番を見る
使うもの:Roblox Studioが起動するパソコン、マウス、キーボード。右上にお金を出す仕組み(leaderstats)はコイン集めゲームの作り方、ボタンからサーバーへ知らせるRemoteEventはRemoteEventの使い方で使ったものと同じです。
今回の完成状態:下の画像のように、左のお店で「キラキラ」を買うと、ボタンが「キラキラ(買った)」に変わり(画像の1)、右上のCoinsが100から20に減って(画像の2)、体のまわりにキラキラが付けば成功です(画像の3)。

ショップの部品
| 名前 | 置く場所 | 役目 |
|---|---|---|
| ShopItems(ModuleScript) | ReplicatedStorage | 売る物の一覧。名前・値段・効き目をここに書く |
| BuyItem(RemoteEvent) | ReplicatedStorage | ボタンが押されたことを、サーバーに知らせる |
| ShopService(Script) | ServerScriptService | コインを確かめて、減らして、効き目を渡す |
| ShopGui・ShopFrame | StarterGui | お店の画面と、ボタンを並べる枠 |
| UIListLayout | ShopFrame | 枠の中のボタンを、上から順に並べる |
| ShopClient(LocalScript) | ShopGui | 一覧を読んで、商品ごとにボタンを作る |
ModuleScriptは、ほかのスクリプトから require で読み込んで使うスクリプトです。お店の画面を作るShopClientも、お金を確かめるShopServiceも、同じShopItemsを読みます。一覧が1か所にあるので、値段を変えるときも1か所を直すだけで済みます。
1. 売る物の一覧(ModuleScript)を作る
新しいBaseplateを開き、エクスプローラの「Workspace」の左の「▼」を押して閉じます。「ReplicatedStorage」にマウスを乗せて、右に出る「+」を押します(赤い枠)。

一覧の検索欄に「ModuleScript」と入れ、一覧の「ModuleScript」を押します(赤い枠)。

ModuleScriptが入り、中身の画面が開きます。エクスプローラで「ModuleScript」を押して選び、F2キーを押して名前を「ShopItems」に変えます(赤い枠)。

開いているShopItemsの画面で、中身を全部消して、次のコードを貼り付けます。
-- お店で売る物の一覧。ここに1行足すと、お店のボタンも1つ増える
local ShopItems = {
{ id = "SpeedBoots", name = "はやい靴", price = 50, kind = "speed", value = 24 },
{ id = "Sparkles", name = "キラキラ", price = 80, kind = "sparkles" },
}
return ShopItems

1行が1つの商品です。
| 項目 | 意味 |
|---|---|
| id | 商品を見分ける名前。半角の英字で、ほかの商品と重ならないようにする |
| name | お店のボタンに出る名前 |
| price | 値段(コイン) |
| kind | 効き目の種類。speed(速く走れる)か sparkles(キラキラが付く) |
| value | speed のときの歩く速さ。プレイヤーの歩く速さの初期値は16 |
2. ボタンとサーバーをつなぐRemoteEventを入れる
もう一度、エクスプローラの「ReplicatedStorage」にマウスを乗せて「+」を押します(赤い枠)。

一覧の検索欄に「RemoteEvent」と入れ、一覧の「RemoteEvent」を押します(赤い枠)。

エクスプローラで選んだままF2キーを押し、名前を「BuyItem」に変えます(赤い枠)。

3. コインを確かめて渡すスクリプトを入れる
エクスプローラの「ServerScriptService」にマウスを乗せて、右に出る「+」を押します(赤い枠)。

一覧の検索欄に「Script」と入れ、一覧の「Script」を押します(赤い枠)。

Scriptが入り、中身の画面が開きます。エクスプローラで「Script」を押して選び、F2キーを押して名前を「ShopService」に変えます(赤い枠)。

プロパティの検索欄に「RunContext」と入れて、「▼動作」の欄にあるRunContextの一覧から「Server」を選びます(赤い枠)。

開いているShopServiceの画面で、中身を全部消して、次のコードを貼り付けます。
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ShopItems = require(ReplicatedStorage:WaitForChild("ShopItems"))
local buyItem = ReplicatedStorage:WaitForChild("BuyItem")
local START_COINS = 100 -- 試しやすいように、最初から持っているコイン
-- 一覧から、id が同じ物を探す
local function findItem(id)
for _, item in ShopItems do
if item.id == id then
return item
end
end
return nil
end
-- 買った物の効き目を、今のキャラクターに付ける
local function applyItem(character, item)
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then return end
if item.kind == "speed" then
humanoid.WalkSpeed = item.value
elseif item.kind == "sparkles" then
local root = character:FindFirstChild("HumanoidRootPart")
if root and not root:FindFirstChild("ShopSparkles") then
local sparkles = Instance.new("Sparkles")
sparkles.Name = "ShopSparkles"
sparkles.Parent = root
end
end
end
Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = START_COINS
coins.Parent = leaderstats
-- 生き返ったときも、買った物の効き目を付け直す
player.CharacterAppearanceLoaded:Connect(function(character)
for _, item in ShopItems do
if player:GetAttribute("Owned_" .. item.id) then
applyItem(character, item)
end
end
end)
end)
-- 買うボタンが押されたら、サーバーでコインを確かめてから渡す
buyItem.OnServerEvent:Connect(function(player, id)
local item = findItem(id)
if not item then return end
if player:GetAttribute("Owned_" .. item.id) then return end
local coins = player.leaderstats.Coins
if coins.Value < item.price then return end
coins.Value -= item.price
player:SetAttribute("Owned_" .. item.id, true)
if player.Character then
applyItem(player.Character, item)
end
end)
貼り付けたら、エクスプローラのServerScriptServiceの中に「ShopService」があるかを確かめます(赤い枠)。

| コードの部分 | していること |
|---|---|
| leaderstats と Coins | 参加した人ごとに、右上に出るコインを用意する。試しやすいように、START_COINSで最初から100にしている |
| buyItem.OnServerEvent | ボタンが押されたら、その商品が一覧にあるか、もう買っていないか、コインが足りるかを確かめる |
| SetAttribute("Owned_…") | 買った物の印を、その人に付ける |
| applyItem | 印の付いた物の効き目を、キャラクターに付ける |
| CharacterAppearanceLoaded | 倒れて生き返ったときも、効き目を付け直す |
値段は、ボタンから送られた数ではなく、サーバーの一覧の数で決めます。ボタンから届くのは、どの商品かを表すidだけです。こうしておくと、遊ぶ人のパソコンで値段を書きかえられても、一覧の値段でしか買えません。
4. お店の画面の枠を作る
エクスプローラの「StarterGui」にマウスを乗せて、右に出る「+」を押します(赤い枠)。

一覧の検索欄に「ScreenGui」と入れ、一覧の「ScreenGui」を押します(赤い枠)。

エクスプローラで選んだままF2キーを押し、名前を「ShopGui」に変えます(赤い枠)。

エクスプローラの「ShopGui」にマウスを乗せて、右に出る「+」を押します(赤い枠)。エクスプローラが下まで見えないときは、マウスのホイールで下へずらします。

一覧の検索欄に「Frame」と入れ、一覧の「Frame」を押します(赤い枠)。

エクスプローラで選んだままF2キーを押し、名前を「ShopFrame」に変えます(赤い枠)。

3D画面の上の作品のタブ「Place6」を押して3D画面に戻ります(タブの名前はパソコンによって違います)。エクスプローラでShopFrameを選んだまま、プロパティの検索欄に「Size」と入力し、Sizeを「{0, 240},{0, 150}」にします(画像の1)。画面の左上に、白い四角が出ます(画像の2)。

プロパティの検索欄に「Position」と入力し、Positionを「{0, 20},{0.5, -75}」にします(画像の1)。白い四角が、画面の左の真ん中に動きます(画像の2)。

| プロパティ | 値 | 意味 |
|---|---|---|
| Size | {0, 240},{0, 150} | 横240、縦150ピクセルの枠 |
| Position | {0, 20},{0.5, -75} | 左から20ピクセル、上下は真ん中(0.5)から枠の半分(75)だけ上 |
5. ボタンを上から順に並べる
エクスプローラの「ShopFrame」にマウスを乗せて、右に出る「+」を押します(赤い枠)。

一覧の検索欄に「UIListLayout」と入れ、一覧の「UIListLayout」を押します(赤い枠)。UIListLayoutを入れた枠の中では、ボタンが自動で上から順に並びます。

プロパティの検索欄に「Padding」と入力し、Paddingを「0, 8」にします(赤い枠)。ボタンとボタンのあいだが8ピクセルあきます。

UIListLayoutを選んだ状態で、プロパティの検索欄に「SortOrder」と入力します。SortOrderは、最初から「LayoutOrder」になっています(赤い枠)。このままにすると、ボタンが一覧に書いた順番で並びます。右の選択が「Name」になっていたら、「LayoutOrder」に変えます。

6. ボタンを作るスクリプトを入れる
エクスプローラの「ShopGui」にマウスを乗せて、右に出る「+」を押します(赤い枠)。

一覧の検索欄に「LocalScript」と入れ、一覧の「LocalScript」を押します(赤い枠)。

LocalScriptが入り、中身の画面が開きます。エクスプローラで「LocalScript」を押して選び、F2キーを押して名前を「ShopClient」に変えます(赤い枠)。

開いているShopClientの画面で、中身を全部消して、次のコードを貼り付けます。
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ShopItems = require(ReplicatedStorage:WaitForChild("ShopItems"))
local buyItem = ReplicatedStorage:WaitForChild("BuyItem")
local player = Players.LocalPlayer
local frame = script.Parent:WaitForChild("ShopFrame")
local coins = player:WaitForChild("leaderstats"):WaitForChild("Coins")
-- 一覧の物ごとに、ボタンを1つ作る
for i, item in ShopItems do
local button = Instance.new("TextButton")
button.Name = item.id
button.LayoutOrder = i
button.Size = UDim2.new(1, 0, 0, 44)
button.TextScaled = true
button.Parent = frame
local function refresh()
if player:GetAttribute("Owned_" .. item.id) then
button.Text = item.name .. "(買った)"
else
button.Text = item.name .. " " .. item.price .. "コイン"
end
end
refresh()
player:GetAttributeChangedSignal("Owned_" .. item.id):Connect(refresh)
button.Activated:Connect(function()
if player:GetAttribute("Owned_" .. item.id) then return end
if coins.Value < item.price then
button.Text = "コインが足りない"
task.wait(1.5)
refresh()
return
end
buyItem:FireServer(item.id)
end)
end
貼り付けたら、エクスプローラのShopGuiの中に「ShopClient」と「ShopFrame」が並んでいるかを確かめます(赤い枠)。

| コードの部分 | していること |
|---|---|
| for i, item in ShopItems do | 一覧の商品ごとに、ボタン(TextButton)を1つ作ってShopFrameに入れる |
| refresh | ボタンの文字を「名前 値段コイン」か「名前(買った)」にする |
| GetAttributeChangedSignal | サーバーが買った印を付けたら、すぐにボタンの文字を変える |
| button.Activated | コインが足りなければ「コインが足りない」と出し、足りればサーバーに商品のidを送る |
ボタンの側でもコインを確かめているのは、「コインが足りない」とすぐに見せるためです。買えるかどうかの本当の確かめは、サーバーのShopServiceがします。
7. テストで買い物をする
3D画面の上の作品のタブ「Place6」を押して3D画面に戻り、F5キーでテストを始めます(タブの名前はパソコンによって違います)。画面の左に、一覧の順にボタンが2つ並びます(画像の1)。右上のCoinsは100です(画像の2)。
右上の名前の欄はモザイクにしています。

「キラキラ 80コイン」を押すと、ボタンが「キラキラ(買った)」に変わります(画像の1)。右上のCoinsは80減って20になり(画像の2)、体のまわりにキラキラが付きます(画像の3)。

コインが20のまま「はやい靴 50コイン」を押すと、ボタンの文字が「コインが足りない」に変わります(赤い枠)。1.5秒たつと元の文字に戻り、Coinsは20のままです。

8. 生き返ったあとも効き目が残るか確かめる
Escキーを押すと出るメニューで、「リスポーン」を押します(赤い枠)。アバターと名前はモザイクにしています。

確認の画面で、もう一度「リスポーン」を押します(赤い枠)。

スポーン地点で生き返ったあとも、ボタンは「キラキラ(買った)」のままで(画像の1)、体のまわりにキラキラが付いています(画像の2)。

| 試したこと | 結果 |
|---|---|
| テストを始める | 左にボタンが2つ、右上のCoinsは100 |
| キラキラを買う | Coinsが20になり、ボタンが「(買った)」、体にキラキラ |
| コイン20ではやい靴を押す | 「コインが足りない」と出て、Coinsは20のまま |
| リスポーンする | キラキラもボタンの「(買った)」も残った |
9. 商品を1つ足してみる
Shift + F5キーでテストを停止します。上のタブの「ShopItems」を押して、一覧の画面を開きます。中身を全部消して、次のコードを貼り付けます。キラキラの行の下に、「とてもはやい靴」の1行を足しています(赤い枠)。
-- お店で売る物の一覧。ここに1行足すと、お店のボタンも1つ増える
local ShopItems = {
{ id = "SpeedBoots", name = "はやい靴", price = 50, kind = "speed", value = 24 },
{ id = "Sparkles", name = "キラキラ", price = 80, kind = "sparkles" },
{ id = "SuperBoots", name = "とてもはやい靴", price = 90, kind = "speed", value = 32 },
}
return ShopItems

3D画面の上の作品のタブ「Place6」を押して3D画面に戻り、F5キーでテストを始めます(タブの名前はパソコンによって違います)。お店のボタンが3つになり、いちばん下に「とてもはやい靴 90コイン」が出ました(赤い枠)。このように、「ShopItems」のコードに1行足すだけで商品が増えます。

数字を変えて調整する
ShopServiceとShopItemsは、スクリプトの中の数字です。エクスプローラで「ShopService」(ServerScriptServiceの中)や「ShopItems」(ReplicatedStorageの中)をダブルクリックして開き、表の名前の行の数字を書き換えます。
ShopFrameのSizeはプロパティです。エクスプローラでShopGuiの中の「ShopFrame」を押して選び、プロパティの検索欄に「Size」と入力します。AbsoluteSizeやAutomaticSizeなど名前に「Size」を含む欄がいくつか並ぶので、名前がちょうど「Size」の欄に入力して、Enterキーを押します。
| 変えたいこと | 変える場所 | 例 |
|---|---|---|
| 最初のコイン | ShopServiceのSTART_COINS | ゲームで集めたコインで買わせるなら0にする |
| 商品の値段 | ShopItemsのprice | 50 → 30 |
| 速く走れる靴の速さ | ShopItemsのvalue | 24 → 20。プレイヤーの歩く速さの初期値は16 |
| 商品が増えて枠に入らない | ShopFrameのSize | 縦を150から200にする。ボタン1つは縦44、あいだは8 |
ショップが動かないときの確かめ方
| 症状 | 見るところ | 直し方 |
|---|---|---|
| ボタンが1つも出ない | ShopClientの場所 | ShopGuiの中にあり、ShopFrameと名前が合っているか |
| 出力に「Infinite yield possible」と出る | 名前 | ShopItems・BuyItemがReplicatedStorageにあり、名前が合っているか。この表示の読み方はInfinite yield possibleの直し方で解説しています |
| ボタンを押してもCoinsが減らない | ShopService | ServerScriptServiceにあり、RunContextが「Server」か |
| 右上にCoinsが出ない | ShopService | leaderstatsとCoinsの名前が合っているか |
| ボタンが重なる・並び順がおかしい | UIListLayout | ShopFrameの中にあり、SortOrderが「LayoutOrder」か |
AIに相談するときの伝え方
Roblox Studioでお店の画面を作っています。
ReplicatedStorageのModuleScript「ShopItems」に商品の一覧(id, name, price, kind, value)があり、StarterGuiのLocalScriptが一覧からボタンを作り、RemoteEvent「BuyItem」でidだけをサーバーに送っています。
ServerScriptServiceのScriptで、Coinsを確かめて減らし、SetAttributeで買った印を付けています。
買った物をDataStoreに保存して、次に遊んだときも持っているようにしたいです。
よくある質問
抜けて入り直すと、買った物は残る?
この記事のコードでは残りません。買った印(属性)は、ゲームを抜けると消えます。次に遊んだときも残したいときは、DataStoreで保存する方法の仕組みで、買った物のidを保存します。
Robuxで売る商品も、このお店に並べられる?
このお店は、ゲームの中のコインで買う作りです。Robuxで売るときは、ゲームパスか開発者製品の仕組みを使い、購入画面はRoblox側の画面を開きます。
次は、手を振る動きを作って、ゲームの中で動かします。次のステップ(上級 4/40)
次に知りたいことを選ぶ
- 次のステップ:手を振る動きを作って、ゲームの中で動かします → ロブロックス(Roblox)スタジオのアニメーションの作り方
- ゲームの中でコインを集めたい → ロブロックス(Roblox)でコイン集めゲームを作る方法
- ボタンからサーバーに知らせる仕組みを知りたい → ロブロックス(Roblox)のRemoteEventの使い方
- 買った物を保存したい → ロブロックス(Roblox)のDataStoreの使い方