ラウンドの間、プログラムはタイムを追跡し、異なるスクリプトの間で信号を送る必要があります。時間はタイムスクリプトで管理し、Robloxのコーディングの概念であるイベントは、試合終了などの変化を知らせます。
イベントでシグナルを送信する
プレイヤーがアリーナにいる状態で、イベントを使って試合開始を合図し、タイマーのコードを開始することができます。その後、イベントを使って試合終了を知らせ、プレイヤーをロビーに戻すことができます。
これらのイベントはあらかじめ用意されているものではないので、バインダブル(bindable) イベントと呼ばれるカスタムイベントのオブジェクトを作成する必要があります。バインダブルイベントは、プレイヤーからのアクションによく使われ、Touched や Changed のようなイベントに似ています。
複数のスクリプトが同じバインダブルイベントをリッスンすることができます。これにより、コードが整理され、必要に応じて試合の開始や終了のためのコードを後から追加することが容易になります。
バインド可能なイベントの作成
試合の開始時と終了時にバインド可能なイベント オブジェクトを作成することから始めます。バインド可能なイベントはクライアントと対話しないため、ServerStorage に格納できます。
- ServerStorage で、Events という名前の新しいフォルダーを作成します。そのフォルダーに MatchStart とMatchEndという名前の 2 つの BindableEvents を作成します。
イベントの使用
現在、プレイヤーがアリーナに入場すると、タイマーを開始するのではなく、インターミッションが再開され続けています。メインループは、次のコードに移る前に、MatchEndイベントが発生するまで停止して待機するように指示する必要があります。
イベントには2つの組み込み関数があります。Connect() と Wait() です。以前のように Connect() を使う代わりに、MatchEnd で Wait() を呼び、MatchEnd が発生するまでゲームマネージャースクリプトを一時停止させます。この場合、ゲームマネージャーが試合終了のシグナルを受け取るまで、wait 関数がコードを一時停止させます。
- GameManagerで、Event フォルダと MatchEnd イベント用の変数を作成します。
-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- Events
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
- スクリプトは、試合の終了イベントが発生するのを待ってから次に進むようにします。ループの最後に、次のように入力します。
matchEnd.Event:Wait()
while true do
repeat
wait(gameSettings.intermissionDuration)
print("Restarting intermission")
until Players.NumPlayers >= gameSettings.minimumPlayers
print("Intermission over")
wait(gameSettings.transitionTime)
matchManager.prepareGame()
-- Placeholder wait for the length of the game.
matchEnd.Event:Wait()
end
- ゲームをテストしてください。プレイヤーがアリーナに入った後、中断ループが続かないことを確認します。スクリプトは、matchEnd シグナルの発行を待っている状態です。
トラブルシューティング
この時点でコードが期待通りに動作しない場合は以下のいずれかを試してみてください。
- matchEnd.Event:Wait() でのドットまたはコロン演算子の使用を再確認してください。
- MatchEnd が BindableEvent であり、RemoteEvent などの別のタイプではないことを確認してください。
タイマーの使用
試合終了の条件のひとつにタイムアップがありますが、これはスクリプトで処理されます。
タイマーの設定
ゲームにタイマーを追加するには、以下の手順で作成したモジュールスクリプトを使用します。タイマーの開始と終了、残り時間を返す関数が含まれています。
- ServerStorage > ModuleScripts で、Timer という名前の新しいモジュール スクリプトを作成します。
以下のコードに置き換えます。
local Timer = {}
Timer.__index = Timer
function Timer.new()
local self = setmetatable({}, Timer)
self._finishedEvent = Instance.new("BindableEvent")
self.finished = self._finishedEvent.Event
self._running = false
self._startTime = nil
self._duration = nil
return self
end
function Timer:start(duration)
if not self._running then
local timerThread = coroutine.wrap(function()
self._running = true
self._duration = duration
self._startTime = tick()
while self._running and tick() - self._startTime < duration do
wait()
end
local completed = self._running
self._running = false
self._startTime = nil
self._duration = nil
self._finishedEvent:Fire(completed)
end)
timerThread()
else
warn("Warning: timer could not start again as it is already running.")
end
end
function Timer:getTimeLeft()
if self._running then
local now = tick()
local timeLeft = self._startTime + self._duration - now
if timeLeft < 0 then
timeLeft = 0
end
return timeLeft
else
warn("Warning: could not get remaining time, timer is not running.")
end
end
function Timer:isRunning()
return self._running
end
function Timer:stop()
self._running = false
end
return Timer
- MatchManagerでは、GameSettings モジュールと Timer モジュールを必要とします。
local MatchManager = {}
-- Services
local ServerStorage = game:GetService("ServerStorage")
-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
- timer.new() で新しいタイマーオブジェクトを作成し、myTimer 変数に代入しておきます。このオブジェクトを使ってタイマーの開始と停止を制御します。
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- Creates a new timer object to be used to keep track of match time.
local myTimer = timer.new()
タイマーモジュールのスクリプトは他のスクリプトから呼び出すことができ、特定の時間後にトラップを出現させたい場合など、必要に応じてさらにタイマーを作成することができます。複数の状況でタイマーを使用するには、myTrapTimer = timer.new() のように、新しいタイマー・オブジェクトを作成します。タイマー・オブジェクトは、再利用するのではなく、一つの目的にのみ使用すべきです。
起動と停止
タイマーを作成したので、次にそのオブジェクト内の start() と stop() 関数を使用します。以下は、その関数の解説です。
- start(time) : 時間(秒)をパラメーターとしてタイマーを開始します。
- finished:Connect(functionName) : タイマーが終了すると、パラメーターで渡された関数を実行します。
- MatchManager で、 timeUp() という名前の新しい関数を作成して、タイマーが終了するたびに実行するようにします。テストのために print 文を入れておきます。
local myTimer = timer.new()
-- Local Functions
local function timeUp()
print("Time is up!")
end
-- Module Functions
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
end
return MatchManager
- timeup() の下に、print 文を含む startTimer という名前の関数を追加します。タイマーは後でゲーム内に表示します。
-- Local Functions
local function timeUp()
print("Time is up!")
end
local function startTimer()
print("Timer started")
end
- タイマーの開始と停止は startTimer() で行います。
- myTimer.start() を呼び出します。gameSettings.matchDurationを渡します。
- myTimer.finished:Connect() を呼び出します。timeUp 関数を渡します。
-- Local Functions
local function startTimer()
print("Timer started")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
end
タイマーを開始する
MatchStart イベントを使って、試合開始時にタイマーをスタートさせることができます。
- MatchManager のモジュール変数の下に、Event フォルダ、MatchStart、MatchEnd(これは今後のレッスンで使用します)を格納するための変数を作成します。
-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- Events
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
--Creates timer
local myTimer = timer.new()
- 「return MatchManager」の上で、試合開始イベントをstartTimer 関数に接続します。
-- Module Functions
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
end
matchStart.Event:Connect(startTimer)
return MatchManager
- 試合開始イベントを発生させるには、prepareGame() の中で matchStart:Fire() と入力します。
-- Module Functions
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
- ゲームをテストします。出力ウィンドウで、タイマーのスタートとストップ関数のprint文が表示されていることを確認します。
完成したスクリプト
ここまでに完成したスクリプトを掲載しますのでチェックしてみてください。
MatchManager スクリプト
local MatchManager = {}
-- Services
local ServerStorage = game:GetService("ServerStorage")
-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- Events
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- Creates a new timer object to be used to keep track of match time.
local myTimer = timer.new()
-- Local Functions
local function timeUp()
print("Time is up!")
end
local function startTimer()
print("Timer started")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
end
-- Module Functions
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
return MatchManager
GameManager スクリプト
-- Services
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- Module Scripts
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local matchManager = require(moduleScripts:WaitForChild("MatchManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- Events
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
while true do
repeat
wait(gameSettings.intermissionDuration)
print("Restarting intermission")
until Players.NumPlayers >= gameSettings.minimumPlayers
print("Intermission over")
wait(gameSettings.transitionTime)
matchManager.prepareGame()
-- Placeholder wait for the length of the game.
matchEnd.Event:Wait()
end
[ 3.プレイヤーの管理 ]
[ 5.GUIの作成 ]