マッチは、タイマーが切れたり、単一のプレイヤーが残されたりするなど、いくつかの条件で終了する可能性があります。
敗北したプレイヤーを管理する
現在、敗北したプレイヤーはアリーナにリスポーンします。代わりに、次の一致合を待つためにロビーに戻します。
- PlayerManager では、respawnPlayerInLobby() という名前のローカル関数を作成します。その関数では、フォロー中のことを行います:
- プレイヤーの RespawnLocation プロパティを lobbySpawn に設定します。
- Player:LoadCharacter() でキャラクターをリロードします。LoadCharacter() は、プレイヤーをスポーン時に再作成し、持っていたツールを削除します。
匿名関数を使用する
匿名関数は、特定の状況下で高度なスクリプトでよく使用されます。定義する前に、スクリプトが直面する可能性のある状況を理解することが重要です。
これを考えてください:敗北したプレイヤーをロビーにテレポートするには、リスポーン機能をプレイヤーの死亡イベントに接続する必要があります。問題はありますが。過去に私たちが持っていたようにイベントを接続すると、Died イベントからプレイヤーの名前を取得する方法はありません。スクリプトは、名前が必要で、敗北したプレイヤーをアクティブなプレイヤーのテーブル追跡から削除します。
死亡イベントをトリガーしたプレイヤーの名前を取得するには、匿名関数を使用します。 匿名関数 には名前がなく、別々に作成するのではなく、直接 Connect() 内で作成できます。
サンプルの無記名関数は次のように、構文を表示します。
myPlayer.Died:Connect(function()
print(player)
end)
死亡イベントをコードする
この機能では、プレイヤーのキャラクターが死んたときに、再スポーンする機能をトリガーする。
プレイヤーの死亡イベントにアクセスするには、PlayerManager > preparePlayer() で、プレイヤーのヒューマノイド用の変数を追加します。
local function preparePlayer(player, whichSpawn)player.RespawnLocation = whichSpawnplayer:LoadCharacter()local character = player.Character or player.CharacterAdded:Wait()local sword = playerWeapon:Clone()sword.Parent = characterlocal humanoid = character:WaitForChild("Humanoid")endDied イベントに接続する無名の関数を作成します。開始するには、humanoid.Died:Connect() をタイプします。次に、 内 Connect() 、タイプ function() 、プレス Enter で自動完了 end 、余分な括弧を削除する。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()end)匿名関数では、respawnPlayerInLobby() を呼び出します。player をパスし、マッチに入る準備をするプレイヤーを保存する変数を渡します。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()respawnPlayerInLobby(player)end)サーバー を開始し、マッチをプレイする。プレイヤーが死亡すると、ロビーで再スポーンするかどうかをテストします。プレイヤーを倒すには、彼らのところに歩いて行き、ロビーで再スポーンしたかどうかを確認できるまで武器を使用します。
Player2 を攻撃する リスポーン後のロビーでプレイヤー2
注意, 必要に応じてテストする方法もいくつかあります。
- プレイヤーを殺すには、サーバー > 出力ウィンドウ > コマンドバーで、コピーして貼り付けてください:workspace.Player1.Humanoid.Health = 0。Press Enter を押してコマンドを実行します。他のプレイヤーを削除するには、Player2、Player3などを使用します
- ゲーム設定 > matchDuration をより長い時間に設定すると、すべてのプレイヤーを見つけて取り除く時間が増える可能性があります。
- より迅速なテストを行うには、GameSettings > minimumPlayers を 2 のような小さな数値に変更します。
ゲームを終わらせる
敗北したプレイヤーがリスポーンしたので、ゲームを終わらせる作業を開始します。マッチ終了イベントを作成したことを覚えていますか?タイマーが切れたり、勝者が見つかったりすると発射されます。
ゲームを終了した条件を他のスクリプトに伝えるには、TimerUp と FoundWinner の変数を持つテーブルを作成します。マッチ終了イベントが発動すると、変数を渡して他のスクリプトが応答できるようになります。
ゲーム設定で、endStates という名前の空のモジュールテーブルを作成します。
local GameSettings = {}-- ゲーム変数GameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- ゲームが終了わる可能性のある方法。GameSettings.endStates = {}return GameSettings2つの変数 TimerUp と FoundWinner を作成し、それぞれ名前に一致する文字列に設定します。これらの文字列はコードをテストするために使用されます。
GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}
タイマーで終了
タイマーが終了すると、マッチ終了イベントを発動し、一致する終了状態変数を送信します。そうすると、そのイベントを監視している他のスクリプトが、対応して応答できます。イベントがファイアシグナルを発信している間、リスニングスクリプトによって受信されたデータを送信できることも覚えておいてください、例えば TimerUp または FoundWinner です。
In ゲームマネージャー , in the while true do ループ, line matchEnd.Event:Wait() を見つけます。線の始まりに、local endState = を追加します。
while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()end正しい状態が受信されたことを確認するには、endState を含む印刷文を追加します。
while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()print("Game ended with: " .. endState)endIn MatchManager で、timeUp() と remove の印刷文を削除します。次に、マッチ終了イベントを発射するには、matchEnd:Fire() を入力し、gameSettings.endStates.TimerUp をパスします。
-- 値local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")local timeLeft = displayValues:WaitForChild("TimeLeft")-- マッチ時間を追跡するために使用される新しいタイマーオブジェクトを作成します。local myTimer = timer.new()-- ローカル機能local function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)end一致をテストします。タイマーが切れると、印刷文が TimerUp 変数に保存された文字列を含んでいるかどうかをチェックします。
トラブルシュートのヒント
この時点では、メッセージは表示されませんでした。以下のいずれかを試してください。
- 終了状態変数が呼ばれる場所で、ここのように正確に書かれていることを確認してください: gameSettings.endStates.TimerUp。
- Make sure to use : (colon operator) ドット演算子の代わりに を使用してください, like in .
勝利する一致合をコードする
次に、スクリプトは勝利したプレイヤーを識別し、負けたプレイヤーを削除し、タイマーを停止するなどのクリーンアップを実行する必要があります。試合は、1人のプレイヤーが残った場合にも終了します。FoundWinner 条件が満たされているかどうかを確認するには、マッチでプレイヤーを追跡するテーブルに残された数をチェックする機能が必要です。
プレイヤー数をチェック
試合は、残りのプレイヤーが 1 人しかいない場合に終了します。これをチェックするには、スクリプトはラウンドでプレイヤーを追跡する必要があります。1人のプレイヤーが残されたら、勝者が割り当てられます。
PlayerManager では、次の変数を定義します:
- モジュールスクリプトフォルダ
- ゲーム設定モジュール - 終了状態変数にアクセスするために使用
- イベントフォルダとマッチエンドイベント - イベントを発動
local PlayerManager = {}-- サービスlocal Players = game:GetService("Players")local ServerStorage = game:GetService("ServerStorage")local ReplicatedStorage = game:GetService("ReplicatedStorage")-- モジュールlocal moduleScripts = ServerStorage:WaitForChild("ModuleScripts")local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))-- イベントlocal events = ServerStorage:WaitForChild("Events")local matchEnd = events:WaitForChild("MatchEnd")上 respawnPlayerInLobby() 、新しいローカル関数 checkPlayerCount() を追加します。
-- プレイヤー変数local activePlayers = {}local playerWeapon = ServerStorage.Weaponlocal function checkPlayerCount()endlocal function respawnPlayerInLobby(player)その機能内では、if 然後文を使用して勝者をチェックします。その文では:
- activePlayers テーブルのサイズが 1 かどうかをチェックします。
- そうなると、matchEnd を発射し、gameSettings.endStates.FoundWinner をパスします。
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
プレイヤーを削除する
プレイヤーが削除されない限り、正確なカウントは維持できません。プレイヤーが敗北すると、プレイヤーテーブルから削除して正確なプレイヤー数を維持します。次に、アクティブなプレイヤーテーブルのサイズを確認して、勝者がいるかどうかを確認します。
の下で、パラメーター名が の新しいローカル関数を作成します。
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endendlocal function removeActivePlayer(player)endactivePlayers テーブルでプレイヤーを見つけるには、for ループを使用してそれを順回しします。次に、名前に一致するプレイヤーが関数にパスされた場合に実行する if 文を追加します。
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thenendendendプレイヤーを削除するには、if 文で:
- playersLeft オブジェクトの値を #activePlayers に設定します。
- checkPlayerCount() を実行して勝利するプレイヤーをチェックします。
local function removeActivePlayer(player)for playerKey, whichPlayer in activePlayers doif whichPlayer == player thentable.remove(activePlayers, playerKey)playersLeft.Value = #activePlayerscheckPlayerCount()endendend
イベントとテストを接続する
まったく新しい関数を使用するには、プレイヤーの Died イベントに接続された無名関数からそれを呼び出します。
preparePlayer() を見つけます。Died イベント接続の無記名関数で、removeActivePlayer() を呼び出します。その後、プレイヤーをパラメータとして渡します。
humanoid.Died:Connect(function()respawnPlayerInLobby(player)removeActivePlayer(player)end)勝利したプレイヤーが見つかるかどうかを確認するには、 テストサーバー を開始します。プレイヤーが 1人しか残っていないときは、出力ウィンドウに FoundWinner が表示されるはずです。
テストを続けて、マッチが終了するようにします。新しいマッチが開始すると、出力ウィンドウにエラーが表示されます:
このエラーは、タイマーが停止していなかったため、次のセクションで修正されます。
タイマーを停止する
試合が勝利したプレイヤーで終わるたびに、タイマーも停止する必要があります。時間切れ前にタイマーを停止するには、マッチ終了イベントが発動するたびにタイマーが停止するようにします。これはイベントを作成するメリットの 1つです。複数の状況で再利用でき、原因と結果の関係をスクリプトすることができます。
In MatchManager では、新しいローカル関数 stopTimer() を作成します。内部では、タイマーを停止するために myTimer:stop() を入力します。
-- マッチ時間を追跡するために使用される新しいタイマーオブジェクトを作成します。local myTimer = timer.new()-- ローカル機能local function stopTimer()myTimer:stop()endlocal function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endマッチが終了するとタイマーを停止するには、matchEnd イベントを stopTimer() に接続します。
-- モジュール機能function MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManagerテスト 前のエラーがもはや発生しないように、 サーバー を開始します。1人のプレイヤーを除き、すべてを排除してから、試合終了後数秒待ちます。
次のステップ
2つの勝利条件が終わったとき、ゲームループを終了するためにまだいくつかのタスクが残っています。たとえば、勝利したプレイヤーはロビーにテレポートされることはありません。次のレッスンでは、試合がプレイヤーに終わった方法を表示し、最後に全ループを完了するようにゲームをリセットします。
完了したスクリプト
以下は、作業を確認するための完了したスクリプトです。
PlayerManager スクリプト
local PlayerManager = {}
-- サービス
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- モジュール
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
-- イベント
local events = ServerStorage:WaitForChild("Events")
local matchEnd = events:WaitForChild("MatchEnd")
-- マップ変数
local lobbySpawn = workspace.Lobby.StartSpawn
local arenaMap = workspace.Arena
local spawnLocations = arenaMap.SpawnLocations
-- 値
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local playersLeft = displayValues:WaitForChild("PlayersLeft")
-- プレイヤー変数
local activePlayers = {}
local playerWeapon = ServerStorage.Weapon
-- ローカル機能
local function checkPlayerCount()
if #activePlayers == 1 then
matchEnd:Fire(gameSettings.endStates.FoundWinner)
end
end
local function removeActivePlayer(player)
for playerKey, whichPlayer in activePlayers do
if whichPlayer == player then
table.remove(activePlayers, playerKey)
playersLeft.Value = #activePlayers
checkPlayerCount()
end
end
end
local function respawnPlayerInLobby(player)
player.RespawnLocation = lobbySpawn
player:LoadCharacter()
end
local function onPlayerJoin(player)
player.RespawnLocation = lobbySpawn
end
local function preparePlayer(player, whichSpawn)
player.RespawnLocation = whichSpawn
player:LoadCharacter()
local character = player.Character or player.CharacterAdded:Wait()
local sword = playerWeapon:Clone()
sword.Parent = character
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
respawnPlayerInLobby(player)
removeActivePlayer(player)
end)
end
-- モジュール機能
function PlayerManager.sendPlayersToMatch()
local arenaSpawns = spawnLocations:GetChildren()
for playerKey, whichPlayer in Players:GetPlayers() do
table.insert(activePlayers, whichPlayer)
local spawnLocation = table.remove(arenaSpawns, 1)
preparePlayer(whichPlayer, spawnLocation)
end
playersLeft.Value = #activePlayers
end
-- イベント
Players.PlayerAdded:Connect(onPlayerJoin)
return PlayerManager
ゲーム設定スクリプト
local GameSettings = {}-- ゲーム変数GameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- ゲームが終了わる可能性のある方法。GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}return GameSettings
ゲームマネージャースクリプト
-- サービスlocal ServerStorage = game:GetService("ServerStorage")local Players = game:GetService("Players")-- モジュールスクリプトlocal moduleScripts = ServerStorage:WaitForChild("ModuleScripts")local matchManager = require(moduleScripts:WaitForChild("MatchManager"))local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))local displayManager = require(moduleScripts:WaitForChild("DisplayManager"))-- イベントlocal events = ServerStorage:WaitForChild("Events")local matchEnd = events:WaitForChild("MatchEnd")while true dodisplayManager.updateStatus("Waiting for Players")repeattask.wait(gameSettings.intermissionDuration)until #Players:GetPlayers() >= gameSettings.minimumPlayersdisplayManager.updateStatus("Get ready!")task.wait(gameSettings.transitionTime)matchManager.prepareGame()local endState = matchEnd.Event:Wait()print("Game ended with: " .. endState)end
MatchManager スクリプト
local MatchManager = {}
-- サービス
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- モジュールスクリプト
local moduleScripts = ServerStorage:WaitForChild("ModuleScripts")
local playerManager = require(moduleScripts:WaitForChild("PlayerManager"))
local gameSettings = require(moduleScripts:WaitForChild("GameSettings"))
local timer = require(moduleScripts:WaitForChild("Timer"))
-- イベント
local events = ServerStorage:WaitForChild("Events")
local matchStart = events:WaitForChild("MatchStart")
local matchEnd = events:WaitForChild("MatchEnd")
-- 値
local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")
local timeLeft = displayValues:WaitForChild("TimeLeft")
-- マッチ時間を追跡するために使用される新しいタイマーオブジェクトを作成します。
local myTimer = timer.new()
-- ローカル機能
local function stopTimer()
myTimer:stop()
end
local function timeUp()
matchEnd:Fire(gameSettings.endStates.TimerUp)
end
local function startTimer()
print("Timer started")
myTimer:start(gameSettings.matchDuration)
myTimer.finished:Connect(timeUp)
while myTimer:isRunning() do
-- +1 を追加すると、タイマーの表示が 0 ではなく 1 で終わることを保証できます。
timeLeft.Value = (myTimer:getTimeLeft() + 1) // 1
-- 待機時間を設定しないことで、より正確なループが提供されます
task.wait()
end
end
-- モジュール機能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager