マッチは、タイマーが切れたり、1人のプレイヤーが残ったりするなど、いくつかのコンディションで終了できます。
敗北したプレイヤーを管理する
現在、倒れたプレイヤーはアリーナでリスポーンします。代わりに、ロビーに戻して次一致マッチを待ちます。
- PlayerManager で、 respawnPlayerInLobby() という名前のローカル関数を作成します。その関数で、フォロー中のことを行います:
- プレイヤーの RespawnLocation をロビースポーンに設定します。
- Reload the character with Player:LoadCharacter() . Remember, LoadCharacter() recreates the player at their spawn, removing any tools they had.
匿名関数を使用する
匿名関数は、特定の状況下の下で使用されることがよくあります。匿名関数を定義する前に、スクリプトが遭遇する可能性のある状況を理解することは重要です。
これを考慮してください: 敗北したプレイヤーをロビーにテレポートするには、respawn 機能はプレイヤーの Died イベントに接続する必要があります。 問題はあります。如果果したプレイヤーをロールトから削除するために、イベントを追跡するスクリプトを変更する必要があります。
死亡イベントをトリガーしたプレイヤーの名前を取得するには、匿名関数を使用します。 匿名関数 は名前を持ちません、および直接 Connect() 内に作成できます。
サンプルの匿名関数は、構文を示す以下にあります。
myPlayer.Died:Connect(function()
print(player)
end)
死亡イベントをコード化する
この機能には、プレイヤーのキャラクターが死亡するたびに、それらをリスポーンする機能が含まれています。
PlayerManager > preparePlayer() の Died イベントにアクセスするには、player のヒューマノイドに変数を追加します。
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")end死亡イベントに接続する匿名関数を作成します。 Start by typing humanoid.Died:Connect() . 次に、 内部 Connect() 、 1> 内の1> 4> Function4> 、 7> を入力7> で自動完了し、追加の親括を削除します。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()end)匿名関数で、 respawnPlayerInLobby() を呼び出します。パスを player 、プレイヤーがマッチに参加する準備をする変数を保存します。
local humanoid = character:WaitForChild("Humanoid")humanoid.Died:Connect(function()respawnPlayerInLobby(player)end)サーバーを開始し、 サーバー とマッチをプレイします。プレイヤーが死亡すると、ロビーにリスポーンします。プレイヤーを倒すには、プレイヤー に近づき、武器 を使用して、ロビー でリスポーンしたことを確認するまで歩きましょう。
注、必要に応じてテスト方法も異なります。
- プレイヤーをキルするには、Server > 出力ウィンドウ > コマンドバーに、コピーしてパスト: workspace.Player1.Humanoid.Health = 0。 Enter を押してコマンドを実行します。他のプレイヤーを削除するには、Player2、Player3、などを使用します。
- ゲーム設定 > matchDuration を長くすると、すべてのプレイヤーを見つけ、削除するためのより多くの時間が提供されます。
- より速いテストを実行するには、GameSettings > minimumPlayers を 2 より小さい数値に変更します。
ゲームを終了する
倒されたプレイヤーがリスポーンするので、ゲームを終了するために働き始めましょう。マッチエンドイベントを作成することを忘れないでください?タイマーが切れると、勝者が見つかると、それは発射されます。
ゲームが終了したコンディションを他のスクリプトに告知するには、 TimerUp および FoundWinner の変数を含むテーブルを作成します。マッチ終了イベントが発生すると、変数を通過するために他のスクリプトにパスされます。
In GameSettings で、 endStates という名前の空のモジュールテーブルを作成します。
local GameSettings = {}-- ゲーム変数GameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- ゲームが終了する可能性のある方法。GameSettings.endStates = {}return GameSettingsTimerUp と FoundWinner という名前の 2つの変数を作成します。各変数に彼らの名前に一致する文字列を設定します。これらの文字列はコードをテストするために使用されます。
GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}
タイマーで終了
タイマーが終了すると、マッチ終了イベントを発動し、マッチの終了状態変数を送信します。その結果、他のスクリプトがそのイベントに応答できます。たとえば、イベントの発信信号である TimerUp または FoundWinner を聞くと、スクリプトのリスナーがそのように応答できます。
In GameManager , while true do loop, find the 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() を見つけ、print 文を削除して、マッチ終了イベントを発動するには、matchEnd:Fire() を入力し、2> gameSettings.endSettings.TimerUp2> をパスします。
-- 値local displayValues = ReplicatedStorage:WaitForChild("DisplayValues")local timeLeft = displayValues:WaitForChild("TimeLeft")-- マッチ時間を追跡するために使用する新しいタイマーオブジェクトを作成します。local myTimer = timer.new()-- ローカル関数local function timeUp()matchEnd:Fire(gameSettings.endStates.TimerUp)endマッチをテストします。タイマーが切れると、印刷ステートメントに TimerUp 変数に保存されたストリングが含まれているかどうかを確認します。
トラブルシューティングのヒント
この時点でメッセージは表示されていません、以下の 1つを試してください。
- Check that wherever the end state variables are called, that they're written exactly, like here: gameSettings.endStates.TimerUp .
- ドットオペレーターの代わりに Fire() 、または matchEnd:Fire を使用してください。
勝利するマッチをコード化する
次に、スクリプトは勝利するプレイヤーを識別し、負けたプレイヤーを削除し、タイマーを停止するなどのクリーンアップを実行する必要があります。マッチが終了すると、FoundWinner コンディションが満たされることもあります。マッチで離れたプレイヤーがある場合は、FoundWinner コンディション
プレイヤーの数をチェック中
1人のプレイヤーしか残っていない場合、マッチは終了します。これを確認するには、スクリプトはプレイヤーをラウンドで追跡する必要があります。1人のプレイヤーが残った場合、勝者が割り当てられます。
PlayerManager で次の変数を定義します:
- ModuleScripts フォルダ
- GameSettings モジュール - エンドステート変数にアクセスする
- イベントフォルダと MatchEnd イベント - イベントを発射
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 であるかどうかをチェックします。
- If so, fire matchEnd and pass in gameSettings.endStates.FoundWinner .
local function checkPlayerCount()if #activePlayers == 1 thenmatchEnd:Fire(gameSettings.endStates.FoundWinner)endend
プレイヤーを削除する
精確なカウントを保つには、プレイヤーが削除されない限りはありません。プレイヤーが倒されると、精確なプレイヤーカウントを維持することはできません。次に、アクティブなプレイヤーテーブルからプレイヤーを削除することで、勝者があるかどうかを確認します。
Under checkPlayerCount() の下で、 removeActivePlayer() という名前の新しいローカル関数を作成し、 player というパラメータで名前付けされた新しいローカル関数を作成します。
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 イベントに接続された匿名関数から呼び出します。
Find preparePlayer() を検索する。 Died イベント接続を持つ匿名関数で、 removeActivePlayer() を呼び出します。その後、プレイヤーをパラメーターとして渡します。
humanoid.Died:Connect(function()respawnPlayerInLobby(player)removeActivePlayer(player)end)勝利したプレイヤーが見つかるかどうかを確認するには、 テストサーバー を開始します。出力ウィンドウには、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マッチが終了すると、タイマーを停止するには、マッチエンドイベントを stopTimer() に接続します。
-- モジュール機能function MatchManager.prepareGame()playerManager.sendPlayersToMatch()matchStart:Fire()endmatchStart.Event:Connect(startTimer)matchEnd.Event:Connect(stopTimer)return MatchManagerテスト 以前のエラーが再び表示されないように サーバー を開始します。すべてのプレイヤーを除き、マッチが終了した後数秒間お待ちください。
次のステップ
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
GameSettings スクリプト
local GameSettings = {}-- ゲーム変数GameSettings.intermissionDuration = 5GameSettings.matchDuration = 10GameSettings.minimumPlayers = 2GameSettings.transitionTime = 5-- ゲームが終了する可能性のある方法。GameSettings.endStates = {TimerUp = "TimerUp",FoundWinner = "FoundWinner"}return GameSettings
GameManager スクリプト
-- サービス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 = (math.floor(myTimer:getTimeLeft() + 1))
-- 待ち時間を設定しないと、より正確なループオファーが提供されます
task.wait()
end
end
-- モジュール機能
function MatchManager.prepareGame()
playerManager.sendPlayersToMatch()
matchStart:Fire()
end
matchStart.Event:Connect(startTimer)
matchEnd.Event:Connect(stopTimer)
return MatchManager