ロブロックス(Roblox)スタジオでタワーディフェンスを作る方法【後編】|お金でタワーを買って好きな場所に置く

制作手順難易度: 中級所要時間: 約40分(目安)情報確認日: 2026年10月16日

「タワーディフェンスで、タワーを自分で好きな場所に置けるようにしたい」「敵を倒したらお金が増えるようにしたい」

ロブロックス(Roblox)スタジオで作るタワーディフェンスの後編です。実際の画像付きで誰でも簡単に分かるように解説します。前編では、敵が道を歩き、タワーが近くの敵を撃つところまで作りました。後編では、敵を倒すとお金がもらえて、画面のボタンを押してから地面をクリックすると、そこにタワーを置けるようにします。

中級ステップ19/28 前の記事:ロブロックス(Roblox)スタジオでタワーディフェンスを作る方法【前編】 全体の順番を見る

使うもの:前編で作ったタワーディフェンス。お金を右上に出す「leaderstats」はコイン集めゲームの作り方、ボタンからサーバーに知らせる「RemoteEvent」はRemoteEventの使い方と同じしくみです。

今回の完成状態:下の画像のように、ボタンに「置きました!」と出て(画像の1)、クリックした場所にタワーが立ち(画像の2)、右上のMoneyが減れば成功です(画像の3)。

タワーを置くしくみ

タワーを置くときは、遊ぶ人の画面とサーバーが、次の順番で知らせ合います。

順番どこですること
1遊ぶ人の画面(LocalScript)ボタンが押されたら「置く場所を選ぶ」状態にする
2遊ぶ人の画面(LocalScript)地面がクリックされたら、その位置をRemoteEventでサーバーに送る
3サーバー(Script)お金が足りるか、置ける場所かを自分で確かめる
4サーバー(Script)大丈夫なら、お金を減らしてタワーを置き、結果を画面に返す

お金を減らすのも、タワーを置くのも、サーバーだけです。画面の側にお金の計算を書くと、ずるをする人に「お金を減らさずに置いた」と送られてしまいます。

1. タワーの手本をServerStorageにしまう

前編の終わりの状態から始めます。エクスプローラの「Towers」の中の「Tower」を選び、Ctrl+Dで複製します。Towersの中にTowerが2つ並びます(赤い枠)。

エクスプローラで下に増えたほうのTowerをドラッグして、「ServerStorage」の上で離します。ServerStorageの中にTowerが入ります(赤い枠)。これが、買ったときに複製して置く手本です。

キーボードで移すこともできます。Towerを選んでCtrl+Xで切り取り、「ServerStorage」を選んでCtrl+Shift+V(選んだものの中に貼り付けるショートカット)を押します。ただ、選んでいる場所によってはこのショートカットが効かず、ServerStorageの中に入らないことがありました。そのときは、エクスプローラでTowerがどこにあるかを確かめて、上のドラッグでServerStorageに移してください。切り取ったTowerが見当たらないときは、Towersの中のTowerをもう一度Ctrl+Dで複製してから移します。

2. 知らせの通り道(RemoteEvent)を入れる

エクスプローラの「ReplicatedStorage」にマウスを乗せて「+」を押し、検索欄に「RemoteEvent」と入れて、一覧の「RemoteEvent」を押します(赤い枠)。

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

3. 画面にボタンを置く

エクスプローラの「StarterGui」にマウスを乗せて「+」を押し、検索欄に「ScreenGui」と入れて、一覧の「ScreenGui」を押します(赤い枠)。

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

エクスプローラの「TowerGui」にマウスを乗せて「+」を押し、検索欄に「TextButton」と入れて、一覧の「TextButton」を押します(赤い枠)。

プロパティの検索欄に「Size」と入れ、Sizeを「{0, 240},{0, 50}」にします(赤い枠)。横240、縦50のボタンになります。

プロパティの検索欄に「Position」と入れ、Positionを「{0, 20},{1, -80}」にします(赤い枠)。画面の左下、下の端から80上の位置にボタンが移ります。

プロパティの検索欄に「TextScaled」と入れ、チェックを入れます(赤い枠)。

プロパティの検索欄に「Text」と入れ、Textを「タワーを置く(50)」にします(画像の1)。画面の左下にボタンが出ます(画像の2)。ボタンの作り方はボタンの作り方でも解説しています。

4. ボタンと地面のクリックを伝えるLocalScriptを入れる

エクスプローラの「TextButton」にマウスを乗せて「+」を押し、検索欄に「LocalScript」と入れて、一覧の「LocalScript」を押します(赤い枠)。

エクスプローラでF2キーを押し、名前を「PlaceClient」に変えて開き、もとから入っている1行を消して、次のコードを貼り付けます。エクスプローラのTextButtonの中にPlaceClientが見えます(赤い枠)。

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local placeTower = ReplicatedStorage:WaitForChild("PlaceTower")

local button = script.Parent
local mouse = Players.LocalPlayer:GetMouse()

local BUTTON_TEXT = "タワーを置く(50)"
local placing = false -- 置く場所を選んでいる途中か

-- ボタンを押すと「置く場所を選ぶ」状態になる(もう一度押すとやめる)
button.Activated:Connect(function()
	placing = not placing
	if placing then
		button.Text = "置く場所をクリック"
	else
		button.Text = BUTTON_TEXT
	end
end)

-- 選んでいる途中に地面をクリックしたら、その位置をサーバーに伝える
mouse.Button1Down:Connect(function()
	if not placing then
		return
	end
	placing = false
	button.Text = BUTTON_TEXT
	placeTower:FireServer(mouse.Hit.Position)
end)

-- サーバーからの返事を、ボタンに1.5秒だけ出す
placeTower.OnClientEvent:Connect(function(message)
	button.Text = message
	task.wait(1.5)
	if not placing then
		button.Text = BUTTON_TEXT
	end
end)
コードの部分していること
button.Activatedボタンが押されたら「置く場所を選ぶ」状態にして、ボタンの文字を「置く場所をクリック」に変える
mouse.Button1Down選んでいる途中に画面がクリックされたら、マウスが指していた位置をサーバーに送る
mouse.Hit.Positionマウスの先にある地面などの位置
OnClientEventサーバーから返ってきた「置きました!」などを、ボタンに1.5秒だけ出す

このLocalScriptは位置を送るだけで、お金には触りません。

5. お金とタワーを置くScriptを入れる

エクスプローラの「ServerScriptService」にマウスを乗せて「+」を押し、検索欄に「Script」と入れて、一覧の「Script」を押します。

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

ShopServiceを選んだまま、プロパティの検索欄に「RunContext」と入れて、「▼動作」の欄にあるRunContextの一覧から「Server」を選びます(赤い枠)。RunContextは、スクリプトをどこで動かすかを決める設定です。「Server」にすると、サーバーで動きます。前編のWaveServiceやTowerServiceと同じ設定です。

開いているShopServiceの画面で、もとから入っている1行を消し、次のコードを貼り付けます(赤い枠)。

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")

local td = workspace:WaitForChild("TowerDefense")
local towers = td:WaitForChild("Towers")
local enemies = td:WaitForChild("Enemies")
local placeTower = ReplicatedStorage:WaitForChild("PlaceTower")
local towerTemplate = ServerStorage:WaitForChild("Tower")

local START_MONEY = 100 -- 最初に持っているお金
local REWARD = 10 -- 敵を1体倒すともらえるお金
local PRICE = 50 -- タワー1つの値段
local CENTER = Vector3.new(0, 0, -30) -- 置ける場所の中心
local AREA = 30 -- 中心からこの距離(スタッド)までなら置ける

-- 参加した人ごとに Money を用意する
local function addMoney(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	local money = Instance.new("IntValue")
	money.Name = "Money"
	money.Value = START_MONEY
	money.Parent = leaderstats
end

Players.PlayerAdded:Connect(addMoney)
-- 上の WaitForChild を待っている間に入ってきた人にも用意する
for _, player in Players:GetPlayers() do
	if not player:FindFirstChild("leaderstats") then
		addMoney(player)
	end
end

local function getMoney(player)
	local leaderstats = player:FindFirstChild("leaderstats")
	return leaderstats and leaderstats:FindFirstChild("Money")
end

-- 敵が倒れたら、遊んでいる全員にお金を渡す
enemies.ChildAdded:Connect(function(enemy)
	local humanoid = enemy:WaitForChild("Humanoid")
	humanoid.Died:Connect(function()
		for _, player in Players:GetPlayers() do
			local money = getMoney(player)
			if money then
				money.Value += REWARD
			end
		end
	end)
end)

-- 置く場所に重なると困る部品(道・目印・拠点・タワー)
local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Include
params.FilterDescendantsInstances = {
	td:WaitForChild("Road"),
	td:WaitForChild("Waypoints"),
	td:WaitForChild("Base"),
	towers,
}

placeTower.OnServerEvent:Connect(function(player, position)
	-- 1. 送られてきたものが本当に位置(Vector3)か
	if typeof(position) ~= "Vector3" then
		return
	end
	-- 2. お金が足りるか(サーバーが自分で調べる)
	local money = getMoney(player)
	if not money or money.Value < PRICE then
		placeTower:FireClient(player, "お金が足りません")
		return
	end
	-- 3. 置ける広さの中か
	local spot = Vector3.new(math.round(position.X), 3, math.round(position.Z))
	if (Vector3.new(spot.X, 0, spot.Z) - CENTER).Magnitude > AREA then
		placeTower:FireClient(player, "ここには置けません")
		return
	end
	-- 4. 道やほかのタワーに重ならないか
	local hits = workspace:GetPartBoundsInBox(CFrame.new(spot), Vector3.new(3, 6, 3), params)
	if #hits > 0 then
		placeTower:FireClient(player, "ここには置けません")
		return
	end
	-- 全部だいじょうぶなら、お金を減らしてタワーを置く
	money.Value -= PRICE
	local tower = towerTemplate:Clone()
	tower.Position = spot
	tower.Parent = towers
	placeTower:FireClient(player, "置きました!")
end)
コードの部分していること
addMoney参加した人ごとに、右上に出るMoneyを、START_MONEYで決めた100で用意する
humanoid.Died敵が倒れたら、遊んでいる全員のMoneyを、REWARDで決めた10だけ増やす
typeof(position)送られてきたものが本当に位置かを確かめる
money.Value < PRICEお金が50より少なければ「お金が足りません」と返す
AREA道のまわり(中心から30スタッド)より遠ければ「ここには置けません」と返す
GetPartBoundsInBox置く場所に道・目印・拠点・ほかのタワーがあれば「ここには置けません」と返す
towerTemplate:Clone()ServerStorageの手本を複製して、クリックした場所に置く

置いたタワーは「Towers」フォルダーに入ります。前編のTowerServiceは「Towers」の中のパーツを全部タワーとして動かすので、置いたタワーはすぐに敵を撃ち始めます。TowerServiceは書きかえなくて大丈夫です。

6. テストでお金を確かめる

3D画面の上の作品のタブ「Place2」を押して3D画面に戻り、F5キーでテストを始めます(タブの名前はパソコンによって違います)。右上にMoneyの一覧が出ます(一覧が出ないときはTabキーを押すと出ます)。最初のお金は100です(画像の1)。左下にはボタンが出ています(画像の2)。

画像は、前編と同じように、道全体が見えるようにカメラを上に引いて写しています。前編のタワーが敵を倒すたびに、Moneyが10ずつ増え、3体倒して130になりました。

7. タワーを置く

ボタンを押すと、ボタンの文字が「置く場所をクリック」に変わります(画像の1)。道の内側の、まだ何もない地面をクリックします(画像の2)。

クリックした場所にタワーが立ち(画像の2)、ボタンに「置きました!」と出ました(画像の1)。右上のMoneyは、置く前の画像の130から、90になっています(画像の3)。タワーの代金50が引かれ、そのあと敵を1体倒して10増えたためです。置いたタワーのまわりにも青い丸が出て、すぐに敵を撃ち始めました。

8. 置けない場所を確かめる

ボタンを押してから道の上をクリックすると、タワーは置かれず、ボタンに「ここには置けません」と出ました(画像の1、2)。Moneyも減りません。この画像は、タワーを置いたあとに敵を倒してMoneyが130まで増えたところで試しています。

道から遠く離れた、置ける広さの外をクリックしても、「ここには置けません」と出ました(画像の1、2)。この画像は、タワーを何本か足してウェーブを最後まで守りきったあとに試したものです。道が灰色っぽく見えるのは、タワーの届く範囲を示す青い丸が重なっているためです。

タワーを置いていってMoneyが0になったあとにボタンを押してクリックすると、「お金が足りません」と出て、タワーは置かれませんでした(画像の2、3)。タワーを5つ足したので、拠点の体力は10のまま「ぜんぶ守りきった!」になりました(画像の1)。

試したこと結果
敵を倒すMoneyが10ずつ増えた
道の内側の地面をクリックタワーが立ち、Moneyが50減った
道の上をクリック「ここには置けません」、Moneyは減らない
置ける広さの外をクリック「ここには置けません」、Moneyは減らない
Money 0でクリック「お金が足りません」
タワーを足して最後まで拠点の体力10のまま守りきった

前編のタワー1つだけでは体力3まで減りましたが、タワーを足すと1体も拠点にたどり着きませんでした。

数字を変えて遊びを調整する

変えたいこと変える数例
最初のお金ShopServiceのSTART_MONEY100 → 50にすると、最初は1つしか置けない
1体倒したときのお金ShopServiceのREWARD10 → 5
タワーの値段ShopServiceのPRICE50 → 100。ボタンの文字のBUTTON_TEXTも同じ数に直す
置ける広さShopServiceのAREA30 → 20にすると、道の近くにしか置けない

ゲームを難しくしたいときは、お金を減らすより、前編のWaveServiceで敵の速さや体力を上げるほうが、遊ぶ人に変化が伝わりやすくなります。

タワーが置けないときの確かめ方

症状見るところ直し方
ボタンを押しても文字が変わらないPlaceClientTextButtonの中にあるLocalScriptか(Scriptでは動かない)
どこをクリックしても何も起きないPlaceTowerReplicatedStorageの中にあるか、名前が合っているか
いつも「ここには置けません」クリックした場所道の上や、ほかのタワーのすぐ横をクリックしていないか
置けたのにタワーが見えないServerStorageのTower手本のTowerがServerStorageの中にあるか
置いたタワーが撃たない置いた場所置いたTowerが「Towers」フォルダーの中に入っているか
右上にMoneyが出ないleaderstatsテスト中にTabキーを押したか。「leaderstats」が小文字で合っているか

AIに相談するときの伝え方

Roblox Studioで、キットを使わずにタワーディフェンスを作っています。
StarterGuiのTextButtonの中のLocalScriptで、ボタンを押したあと地面をクリックすると、mouse.Hit.PositionをReplicatedStorageのRemoteEvent「PlaceTower」でサーバーに送っています。
ServerScriptServiceのScript「ShopService」で、お金(leaderstatsのMoney)が50以上あり、道やほかのタワーに重ならなければ、ServerStorageのTowerを複製して置いています。
置いたタワーをクリックすると、30払って強くできるようにしたいです。お金はサーバーでだけ変えてください。

よくある質問

スマホでも置ける?

このコードは、パソコンのマウスのクリックで動きます。スマホで遊べるようにするボタンの作り方は、ボタンの作り方で解説しています。

2人で遊ぶとお金はどうなる?

敵が倒れると、遊んでいる全員のMoneyが10ずつ増えます。タワーは、置いた人のMoneyだけが減ります。みんなで同じ拠点を守る遊び方になります。

抜けてもお金を残したい

このコードでは、ゲームを抜けるとお金は消えます。残したいときは、DataStoreで保存します。保存のしかたはDataStoreの使い方で解説しています。

次のステップ(中級 20/28)

次は、朝・夕方・夜を作り、夜の街灯を光らせます。

→ ロブロックス(Roblox)スタジオで夜にする方法

次に知りたいことを選ぶ

次に読む記事