- 完成動画
- はじめに
- パート① 敵を倒すとコインを落とす
- パート② コインを拾う
- パート③ ショップでコインを使う ※更新予定
- 使用する主な機能
- エクスプローラー構成
- 実装するにあたっての考え方
- 手順
- スクリプトの内容
- 【MainFrame>LocalScript】サービスとプレイヤーの取得
- 【MainFrame>LocalScript】プレイヤーとリモートイベントの取得
- 【MainFrame>LocalScript】ボタンの取得
- 【MainFrame>LocalScript】各ボタンのクリックイベント処理
- 【ToziruButton>LocalScript】ボタン・GUI要素の取得
- 【ToziruButton>LocalScript】ボタンがクリックされた時の処理
- 【ShopScript】サービスとオブジェクトの取得
- 【ShopScript】ツールの価格テーブル
- 【ShopScript】購入処理のメイン部分(イベント接続)
- 【ShopScript】不正なツール名を排除
- 【ShopScript】コインが足りているか確認
- 【ShopScript】すでに持っていないかチェック
- 【ShopScript】ツールを渡してコインを減らす
- 【StarterPlayerScripts>LocalScript】プレイヤーとGUIの取得
- 【StarterPlayerScripts>LocalScript】ProximityPromptの取得
- 【StarterPlayerScripts>LocalScript】ProximityPromptが発動されたときの処理
- パート③ まとめ
完成動画
はじめに
本記事では「敵を倒すとコインが出てくる」「そのコインを拾ってお金にする」「集めたお金でショップでアイテムを買う」といった、ゲームらしい要素を段階的に実装していくチュートリアルシリーズです。
パート① 敵を倒すとコインを落とす
使用する主な機能
- ReplicatedStorage:全プレイヤーに共有されるオブジェクト(コイン)を格納
- Humanoid.Diedイベント:敵が倒されたタイミングを取得
- Clone()とPosition:コインを複製し、敵の位置に表示
手順動画
エクスプローラー構成
Workspace
└Drooling Zombie(Model)
└Coin(Script)
ReplicatedStorage
└Coin(MeshPart)
StarterPack
└Handgun(Tool)
実装するにあたっての考え方
敵を倒したときに「どこに・どんなタイミングで・何を出すか」がポイントになります。この例では、敵の死亡時にコインを敵の位置に出現させるようにしています。コインは事前にReplicatedStorage
に用意しておき、スクリプトで複製して使いまわします。
手順
- ツールボックスからコインのモデルを追加
- コインをReplicatedStorageに入れる
- ツールボックスから敵を倒す銃を追加
- 銃をStarterPackに入れる
- ツールボックスから敵になるゾンビを追加
- ゾンビの子要素にScript(Coin)を追加
- コードを記入
- ゾンビモデルのプライマリーパーツを設定
- プレイして敵を倒してみる
スクリプトの内容
local enemy = script.Parent -- 敵のオブジェクト
local replicatedStorage = game:GetService("ReplicatedStorage")
local coinTemplate = replicatedStorage:WaitForChild("Coin") -- あらかじめ作っておいたコインモデル
local function onEnemyDied()
-- コインを複製して、敵の場所に置く
local coin = coinTemplate:Clone()
coin.Position = enemy.PrimaryPart.Position
coin.Parent = workspace
end
-- 敵が死んだときにonEnemyDiedを呼び出す
enemy.Humanoid.Died:Connect(onEnemyDied)
敵オブジェクトとコインテンプレートの取得
local enemy = script.Parent
local replicatedStorage = game:GetService("ReplicatedStorage")
local coinTemplate = replicatedStorage:WaitForChild("Coin")
enemy
はこのスクリプトが仕込まれている敵のモデルを指します。replicatedStorage
は全プレイヤーが共通して使えるストレージ領域です。coinTemplate
はあらかじめReplicatedStorage
に用意しておいたコインのモデル。WaitForChild
を使うことで、スクリプト実行時にコインが確実に存在するまで待ってから取得しています。
敵が倒れたときに呼び出す関数の定
local function onEnemyDied()
local coin = coinTemplate:Clone()
coin.Position = enemy.PrimaryPart.Position
coin.Parent = workspace
end
- 敵が倒れたときに呼ばれる関数
onEnemyDied
を定義。 coinTemplate:Clone()
で新しいコインを複製。coin.Position = enemy.PrimaryPart.Position
で、敵が倒れた位置にコインを設置。coin.Parent = workspace
によって、コインがワールド上に表示されるようになります。
敵の死亡イベントに関数を接続
enemy.Humanoid.Died:Connect(onEnemyDied)
- 敵モデルに含まれる
Humanoid
のDied
イベントを使って、敵が倒れた瞬間にonEnemyDied
関数を呼び出しています。 - この行があることで、プレイヤーが敵を倒すとコインが現れる仕組みが動きます。
パート① まとめ
このパートでは、敵を倒すとコインが出現する仕組みを作りました。ゾンビモデルにスクリプトを追加し、死亡イベントを使ってコインを出現させる基本的なロジックを学びました。次のパートでは、このコインを「拾える」ように発展させていきます。
パート② コインを拾う
使用する主な機能
Touched
イベント:プレイヤーがコインに触れたときの反応を検出するために使用します。leaderstats
によるスコア管理:プレイヤーのコイン数を記録し、リーダーボードに表示するための仕組みです。GetPlayerFromCharacter
メソッド:コインに触れたキャラクターがどのプレイヤーに属するかを判断します。Instance.new
でのオブジェクト作成:leaderstats
とCoins
の作成に使います。Destroy
メソッド:拾われたコインをゲーム内から削除して、再取得を防ぎます。- 状態管理用のフラグ変数:フラグ変数を使って、コインが複数回拾われないように制御します。
手順動画
エクスプローラー構成
Workspace
└Drooling Zombie(Model)
└Coin(Script)
└Drooling Zombie(Model)
└Coin(Script)
└Drooling Zombie(Model)
└Coin(Script)
ReplicatedStorage
└Coin(MeshPart)
└CoinScript(Script)
StarterPack
└tommy gun
ServerScriptService
└Script
実装するにあたっての考え方
まず、プレイヤーがコインに触れたときに取得できるように、Touched
イベントを使って処理を実装します。
次に、拾ったコインがリーダーボードの「Coins」値に反映されるように、leaderstats
とCoins
をプレイヤー参加時に用意しておきます。
最後に、同じコインを何度も取得できないようにするため、フラグ変数を使って、一度取得されたコインは再処理されないようにします。これにより、複数の敵から出現したコインも正しく管理されます。
手順
- ServerScriptServiceにScriptを追加
- コードを記入
- CoinにScriptを追加、名前をCoinScriptに変更
- コードを記入
- 敵を複製
- プレイ
- 敵を倒し、コインを取得
- リーダーボードのCoinが増えていることを確認
スクリプトの内容
CoinScript
local coin = script.Parent
local pickedUp = false
coin.Touched:Connect(function(hit)
if pickedUp then return end
local character = hit.Parent
local player = game.Players:GetPlayerFromCharacter(character)
if player then
pickedUp = true
local stats = player:FindFirstChild("leaderstats")
if stats then
local coins = stats:FindFirstChild("Coins")
if coins then
coins.Value += 1
end
end
coin:Destroy()
end
end)
【CoinScript】コインオブジェクトの取得
local coin = script.Parent
この行では、スクリプトが入っているコインのパーツ(MeshPart
や Part
)自体を coin
という変数に代入しています。
つまり、このスクリプトが貼り付けられているオブジェクトを扱う準備をしています。
【CoinScript】1回しか取得できないように制御する変数
local pickedUp = false
コインを複数回拾われないようにするためのフラグ(旗)です。
一度でも拾われたら true
に変更され、以降の処理をスキップできます。
【CoinScript】プレイヤーが触れたときの処理の開始
coin.Touched:Connect(function(hit)
ここで、コインに何かが触れたときに動く処理を定義しています。hit
は触れた相手のパーツを指します。たとえば、プレイヤーの足や腕など。
【CoinScript】既に拾われていたら処理を止める
if pickedUp then return end
最初にフラグを確認して、すでにコインが拾われていたらこれ以上処理しないようにしています。
これがないと、1つのコインで複数回加算されてしまう恐れがあります。
【CoinScript】プレイヤーのキャラクターを取得
local character = hit.Parent
local player = game.Players:GetPlayerFromCharacter(character)
ここでは、触れてきた hit
(たとえば足など)からその親(キャラクターのモデル)を取り出しています。
さらに GetPlayerFromCharacter
を使って、そのキャラクターがどのプレイヤーに属するのかを取得します。
【CoinScript】コイン加算処理の開始
if player then
pickedUp = true
プレイヤーが見つかったら(=本物のプレイヤーだったら)、ここから実際に加算処理に入ります。
同時に pickedUp
を true
にして、今後二度とこのコインが拾われないようにします。
【CoinScript】leaderstatsからコイン数を取得して加算
local stats = player:FindFirstChild("leaderstats")
if stats then
local coins = stats:FindFirstChild("Coins")
if coins then
coins.Value += 1
Robloxでは、スコアやお金などの情報を leaderstats
という名前のフォルダで管理することが多いです。
ここではその中の Coins
という値を探して、見つかった場合は +1
してコイン数を増やします。
【CoinScript】コインの削除
coin:Destroy()
コインを拾ったら、ワールドから削除(破壊)します。
これによって見た目にも「拾った」感じになりますし、二重取得も防げます。
ServerScriptService > Script
game.Players.PlayerAdded:Connect(function(player)
-- leaderstatsの作成
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
-- Coinsの追加
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = leaderstats
end)
【Script】プレイヤーがゲームに参加したときの処理
game.Players.PlayerAdded:Connect(function(player)
この行は、プレイヤーがゲームに参加したときに実行される関数を登録しています。player
という引数には、参加したプレイヤーの情報が入ります。
【Script】leaderstats(統計フォルダ)の作成
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
leaderstats
はスコアボードで使われる特別なフォルダです。
このフォルダをプレイヤーの中に作ることで、ゲーム画面の上に表示される「リーダーボード」に情報を追加できます。
【Script】Coins(コイン数)を初期化して追加
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = leaderstats
ここでは、IntValue(整数の変数)を作成して、それを Coins
という名前で leaderstats
に入れています。
最初の値は 0
にして、ゲームを始めたばかりの状態にします。
これにより、スクリプト側から player.leaderstats.Coins.Value
のようにしてコイン数を操作できます。
パート② まとめ
このパートでは、コインを拾って所持金を増やす仕組みを実装しました。
コインに触れたときに一度だけ取得できるようフラグで制御し、リーダーボードの「Coins」に反映させることで、ゲーム画面でコイン数が確認できます。
これで、敵を倒してコインを集める流れが完成しました。
次のパートでは、集めたコインを使ってショップでアイテムを購入する機能を実装していきます。
パート③ ショップでコインを使う ※更新予定
使用する主な機能
- ProximityPrompt:NPCやショップの前に立つとGUIを表示するために使用
- RemoteEvent:クライアント(GUI)からサーバー(購入処理)へ情報を送信するために使用
- GUI(ScreenGui)とButton:購入用インターフェースの表示とボタン操作
- Clone()とBackpackへの挿入:武器購入時にプレイヤーへアイテムを渡す処理
エクスプローラー構成
Workspace
└Drooling Zombie(Model)
└Drooling Zombie(Model)
└Drooling Zombie(Model)
└Shop(Model) ※ツールボックスから追加
└EPart(既存のパーツの名前を変更)
└ProximityPrompt
ReplicatedStorage
└RemoteEvents(フォルダ)
└PurchaseToolEvent(RemoteEvent)
└Tools(フォルダ)
└ClassicSword(Tool) ※ツールボックスから追加
└RocketLauncher(Tool)※ツールボックスから追加
└tommy gun(Tool) ※ツールボックスから追加
└Coin(MeshPart)
└CoinScript(Script)
StarterPack
└tommy gun ※ツールボックスから追加
ServerScriptService
└leaderstatsScript(Script)
└ShopScript(Script)
StarterGui
└ShopGui(ScreenGui)
└MainFrame(Frame)
├LocalScript
├GunButton(TextButton)
├RocketButton(TextButton)
├SwordButton(TextButton)
├ToziruButton(TextButton)
│└LocalScript
├GunLabel(TextLabel)
├RocketLabel(TextLabel)
├SwordLabel(TextLabel)
└Title(TextLabel)
StarterPlayer
├StarterCharacterScripts
└StarterPlayerScripts
└LocalScript
実装するにあたっての考え方
- ProximityPromptの使用
ProximityPromptを使って、プレイヤーが特定の場所に近づいたときにショップ用のGui(ScreenGui)を表示させる。 - Toolの購入処理
Gui内の購入ボタンを押すと、RemoteEventを介してサーバーに通知し、ReplicatedStorage
にあるToolをBackpack
に追加する。 - 購入可否の判定
サーバー側で以下の条件を確認:
・プレイヤーの所持コインがToolの価格以上であること
・すでにそのToolをBackpack
に持っていないこと
以上を満たす場合のみToolを渡し、コインを減算。満たさない場合は無反応。
手順
ショップのモデルとProximityPromptの追加
- ツールボックスからShopのモデルを追加
- Shopの子要素にあるパーツを1つ選び、名前をEPartに変更
- EPartの子要素にProximityPromptを追加
- ProximityPromptのプロパティを変更(テキスト関連)
GUIの作成
- StarterGuiにScreenGuiを追加、名前をShopGuiに変更
- ScreenGuiにFrameを追加、名前をMainFrameに変更
- MainFrameにTextLabelを追加、名前をTitleに変更し、位置を調整する
- 同様に他のTextLabelとTextButtonを追加、名前変更、位置調整をする ※今回は仕組みの紹介がメインのためGUIの設定方法は省略しています
- MainFrameの直下にLocalScriptを追加
- ToziruButtonの直下にLocalScriptを追加
ReplicatedStorage
- フォルダを2つ追加
- 1つをRemoteEventsという名前に変更(RemoteEventを扱うフォルダ)
- もう1つをToolsという名前に変更(購入できる武器を扱うフォルダ)
- RemoteEventsにRemoteEventを追加し、名前をPurchaseToolEventに変更
- Toolsにツールボックスから武器を選んで追加
必要なスクリプトの追加
- ServerScriptServiceにScriptを追加し、名前をShopScriptに変更
- ServerScriptServiceに既にあるScriptの名前をleaderstatsScriptに変更
- StarterPlayerScriptsにLocalScriptを追加
スクリプトの内容
MainFrame > LocalScript
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local player = Players.LocalPlayer
local event = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("PurchaseToolEvent")
local gui = script.Parent
local swordBtn = gui:WaitForChild("SwordButton")
local rocketBtn = gui:WaitForChild("RocketButton")
local gunBtn = gui:WaitForChild("GunButton")
swordBtn.MouseButton1Click:Connect(function()
event:FireServer("ClassicSword")
end)
rocketBtn.MouseButton1Click:Connect(function()
event:FireServer("RocketLauncher")
end)
gunBtn.MouseButton1Click:Connect(function()
event:FireServer("tommy gun")
end)
【MainFrame>LocalScript】サービスとプレイヤーの取得
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
この部分では、Players
サービスと ReplicatedStorage
サービスを取得しています。
Players
は現在ゲームに参加しているプレイヤー情報を管理するサービスです。ReplicatedStorage
は、クライアントとサーバー間で共有するデータやオブジェクトを格納するための場所です。
【MainFrame>LocalScript】プレイヤーとリモートイベントの取得
local player = Players.LocalPlayer
local event = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("PurchaseToolEvent")
Players.LocalPlayer
で現在のクライアント側プレイヤーを取得します(LocalScript
でのみ使用可能)。RemoteEvents
フォルダの中にあるPurchaseToolEvent
というRemoteEvent
を取得しています。
これは、ボタンが押されたときにサーバー側へ「○○を買いたい」と通知するために使います。
【MainFrame>LocalScript】ボタンの取得
local gui = script.Parent
local swordBtn = gui:WaitForChild("SwordButton")
local rocketBtn = gui:WaitForChild("RocketButton")
local gunBtn = gui:WaitForChild("GunButton")
このブロックでは、MainFrame
内にある3つの購入ボタン(Sword、Rocket、Gun)を取得しています。WaitForChild
を使うことで、まだ読み込み中の可能性があるオブジェクトにも確実にアクセスできます。
【MainFrame>LocalScript】各ボタンのクリックイベント処理
swordBtn.MouseButton1Click:Connect(function()
event:FireServer("ClassicSword")
end)
rocketBtn.MouseButton1Click:Connect(function()
event:FireServer("RocketLauncher")
end)
gunBtn.MouseButton1Click:Connect(function()
event:FireServer("tommy gun")
end)
- 各ボタンがクリックされたとき、それぞれ指定されたツール名を引数として
PurchaseToolEvent
に渡してFireServer
を実行しています。 FireServer
はクライアントからサーバーにイベントを送る方法で、「この武器を買いたい」という意図をサーバーに伝えています。- 実際の購入処理(コインの確認、ツールの付与など)はサーバー側の
Script
で行われます。
ToziruButton > LocalScript
local button = script.Parent
local mainFrame = button.Parent
local shopGui = mainFrame.Parent
button.MouseButton1Click:Connect(function()
shopGui.Enabled = false
end
【ToziruButton>LocalScript】ボタン・GUI要素の取得
local button = script.Parent
local mainFrame = button.Parent
local shopGui = mainFrame.Parent
この3行は、それぞれのUI要素への参照を取得しています。
script.Parent
でこのスクリプトが入っているToziruButton
(閉じるボタン)を取得button.Parent
でToziruButton
の親要素であるMainFrame
を取得mainFrame.Parent
でMainFrame
の親であるShopGui
(ScreenGui)を取得
【ToziruButton>LocalScript】ボタンがクリックされた時の処理
button.MouseButton1Click:Connect(function()
shopGui.Enabled = false
end)
この部分では、ToziruButton
がクリックされたときの処理を定義しています。
MouseButton1Click
は左クリックに反応するイベントです。Connect(function() ... end)
でイベント発火時に実行される処理を設定しています。shopGui.Enabled = false
によって、ShopGui
全体を非表示にします(これによりGUIが画面から消える)。
ShopScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("PurchaseToolEvent")
local toolsFolder = ReplicatedStorage:WaitForChild("Tools")
-- 各ツールの価格表
local prices = {
ClassicSword = 1,
RocketLauncher = 2,
["tommy gun"] = 3
}
event.OnServerEvent:Connect(function(player, toolName)
local price = prices[toolName]
if not price then return end
local leaderstats = player:FindFirstChild("leaderstats")
local coins = leaderstats and leaderstats:FindFirstChild("Coins")
if not coins or coins.Value < price then return end
-- 既に持っていないかチェック
local backpack = player:FindFirstChild("Backpack")
if backpack:FindFirstChild(toolName) then return end
-- 複製して渡す
local tool = toolsFolder:FindFirstChild(toolName)
if tool then
local clonedTool = tool:Clone()
clonedTool.Parent = backpack
coins.Value = coins.Value - price
end
end)
【ShopScript】サービスとオブジェクトの取得
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local event = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("PurchaseToolEvent")
local toolsFolder = ReplicatedStorage:WaitForChild("Tools")
ReplicatedStorage
はクライアントとサーバー間で共有されるストレージ領域。PurchaseToolEvent
は、プレイヤーがGUIからアイテム購入をリクエストしたときに発火される RemoteEvent。Tools
フォルダには渡す武器(例:ClassicSword, RocketLauncher, tommy gun)が格納されている。
【ShopScript】ツールの価格テーブル
local prices = {
ClassicSword = 1,
RocketLauncher = 2,
["tommy gun"] = 3
}
このテーブルは、各ツールに必要な コイン数 を定義しています。
キーがツール名、値がその価格です。
【ShopScript】購入処理のメイン部分(イベント接続)
event.OnServerEvent:Connect(function(player, toolName)
この行では、クライアントから発火された購入リクエストをサーバーで受け取り、処理を開始します。player
はリクエストを送ってきたプレイヤー、toolName
は欲しいツールの名前です。
【ShopScript】不正なツール名を排除
local price = prices[toolName]
if not price then return end
価格テーブルに存在しないツール名が来た場合には処理を終了します。
【ShopScript】コインが足りているか確認
local leaderstats = player:FindFirstChild("leaderstats")
local coins = leaderstats and leaderstats:FindFirstChild("Coins")
if not coins or coins.Value < price then return end
- プレイヤーの
leaderstats
にあるCoins
を確認し、価格以上あるかを判定します。 - コインが不足していたら処理を終了します。
【ShopScript】すでに持っていないかチェック
local backpack = player:FindFirstChild("Backpack")
if backpack:FindFirstChild(toolName) then return end
- 同じ名前のツールをすでに持っているか確認します。
- 持っていれば、重複しないようにスキップします。
【ShopScript】ツールを渡してコインを減らす
local tool = toolsFolder:FindFirstChild(toolName)
if tool then
local clonedTool = tool:Clone()
clonedTool.Parent = backpack
coins.Value = coins.Value - price
end
Tools
フォルダから目的のツールを探し、複製(Clone()
)してプレイヤーのBackpack
に追加。- コインを消費(減算)します。
StarterPlayerScripts > LocalScript
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local shopGui = player:WaitForChild("PlayerGui"):WaitForChild("ShopGui")
local prompt = workspace:WaitForChild("Shop"):WaitForChild("EPart"):WaitForChild("ProximityPrompt")
prompt.Triggered:Connect(function()
shopGui.Enabled = true
end)
【StarterPlayerScripts>LocalScript】プレイヤーとGUIの取得
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local shopGui = player:WaitForChild("PlayerGui"):WaitForChild("ShopGui")
Players.LocalPlayer
で現在のプレイヤーを取得。PlayerGui
の中にあるShopGui
(ScreenGui)を参照。- この
ShopGui
は最初はEnabled = false
にしておくことで、非表示の状態から開始できる。
【StarterPlayerScripts>LocalScript】ProximityPromptの取得
local prompt = workspace:WaitForChild("Shop"):WaitForChild("EPart"):WaitForChild("ProximityPrompt")
workspace
に配置された「Shop」フォルダ内の「EPart」(部品)の中にあるProximityPrompt
を取得。- プレイヤーがこの部品に近づくと、画面に「Eキーを押してショップを開く」などの表示が出る。
【StarterPlayerScripts>LocalScript】ProximityPromptが発動されたときの処理
prompt.Triggered:Connect(function()
shopGui.Enabled = true
end)
ProximityPrompt.Triggered
は、プレイヤーがプロンプトの指示に従ったとき(例:Eキーを押したとき)に発火。- そのタイミングで
ShopGui.Enabled = true
にしてショップ画面を表示。
パート③ まとめ
このパートでは、ショップでコインを使って武器を購入する機能を作成しました。
- プレイヤーがProximityPromptでGUIを開く
- GUIのボタン操作でRemoteEventを使ってサーバーに購入を依頼
- サーバー側でコインの所持数とアイテム保有状況を確認
- 問題なければツールをプレイヤーのBackpackへ付与し、コインを減算
という一連の流れを通して、GUIとサーバーの連携による実践的なシステムが実装できました。
コメント