試合を終わらせる

*このコンテンツは、ベータ版のAI(人工知能)を使用して翻訳されており、エラーが含まれている可能性があります。このページを英語で表示するには、 こちら をクリックしてください。

マッチは、タイマーが切れたり、単一のプレイヤーが残されたりするなど、いくつかの条件で終了する可能性があります。

敗北したプレイヤーを管理する

現在、敗北したプレイヤーはアリーナにリスポーンします。代わりに、次の一致合を待つためにロビーに戻します。

  1. PlayerManager では、respawnPlayerInLobby() という名前のローカル関数を作成します。その関数では、フォロー中のことを行います:
  • プレイヤーの RespawnLocation プロパティを lobbySpawn に設定します。
  • Player:LoadCharacter() でキャラクターをリロードします。LoadCharacter() は、プレイヤーをスポーン時に再作成し、持っていたツールを削除します。

匿名関数を使用する

匿名関数は、特定の状況下で高度なスクリプトでよく使用されます。定義する前に、スクリプトが直面する可能性のある状況を理解することが重要です。

これを考えてください:敗北したプレイヤーをロビーにテレポートするには、リスポーン機能をプレイヤーの死亡イベントに接続する必要があります。問題はありますが。過去に私たちが持っていたようにイベントを接続すると、Died イベントからプレイヤーの名前を取得する方法はありません。スクリプトは、名前が必要で、敗北したプレイヤーをアクティブなプレイヤーのテーブル追跡から削除します。

死亡イベントをトリガーしたプレイヤーの名前を取得するには、匿名関数を使用します。 匿名関数 には名前がなく、別々に作成するのではなく、直接 Connect() 内で作成できます。

サンプルの無記名関数は次のように、構文を表示します。


myPlayer.Died:Connect(function()
print(player)
end)

死亡イベントをコードする

この機能では、プレイヤーのキャラクターが死んたときに、再スポーンする機能をトリガーする。

  1. プレイヤーの死亡イベントにアクセスするには、PlayerManager > preparePlayer() で、プレイヤーのヒューマノイド用の変数を追加します。


    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")
    end
  2. Died イベントに接続する無名の関数を作成します。開始するには、humanoid.Died:Connect() をタイプします。次に、 Connect() 、タイプ function() 、プレス Enter で自動完了 end 、余分な括弧を削除する。


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    end)
  3. 匿名関数では、respawnPlayerInLobby() を呼び出します。player をパスし、マッチに入る準備をするプレイヤーを保存する変数を渡します。


    local humanoid = character:WaitForChild("Humanoid")
    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    end)
  4. サーバー を開始し、マッチをプレイする。プレイヤーが死亡すると、ロビーで再スポーンするかどうかをテストします。プレイヤーを倒すには、彼らのところに歩いて行き、ロビーで再スポーンしたかどうかを確認できるまで武器を使用します。

    Player2 を攻撃する
    リスポーン後のロビーでプレイヤー2

注意, 必要に応じてテストする方法もいくつかあります。

  • プレイヤーを殺すには、サーバー > 出力ウィンドウ > コマンドバーで、コピーして貼り付けてください:workspace.Player1.Humanoid.Health = 0。Press Enter を押してコマンドを実行します。他のプレイヤーを削除するには、Player2、Player3などを使用します
  • ゲーム設定 > matchDuration をより長い時間に設定すると、すべてのプレイヤーを見つけて取り除く時間が増える可能性があります。
  • より迅速なテストを行うには、GameSettings > minimumPlayers を 2 のような小さな数値に変更します。

ゲームを終わらせる

敗北したプレイヤーがリスポーンしたので、ゲームを終わらせる作業を開始します。マッチ終了イベントを作成したことを覚えていますか?タイマーが切れたり、勝者が見つかったりすると発射されます。

ゲームを終了した条件を他のスクリプトに伝えるには、TimerUpFoundWinner の変数を持つテーブルを作成します。マッチ終了イベントが発動すると、変数を渡して他のスクリプトが応答できるようになります。

  1. ゲーム設定で、endStates という名前の空のモジュールテーブルを作成します。


    local GameSettings = {}
    -- ゲーム変数
    GameSettings.intermissionDuration = 5
    GameSettings.matchDuration = 10
    GameSettings.minimumPlayers = 2
    GameSettings.transitionTime = 5
    -- ゲームが終了わる可能性のある方法。
    GameSettings.endStates = {
    }
    return GameSettings
  2. 2つの変数 TimerUpFoundWinner を作成し、それぞれ名前に一致する文字列に設定します。これらの文字列はコードをテストするために使用されます。


GameSettings.endStates = {
TimerUp = "TimerUp",
FoundWinner = "FoundWinner"
}

タイマーで終了

タイマーが終了すると、マッチ終了イベントを発動し、一致する終了状態変数を送信します。そうすると、そのイベントを監視している他のスクリプトが、対応して応答できます。イベントがファイアシグナルを発信している間、リスニングスクリプトによって受信されたデータを送信できることも覚えておいてください、例えば TimerUp または FoundWinner です。

  1. In ゲームマネージャー , in the while true do ループ, line matchEnd.Event:Wait() を見つけます。線の始まりに、local endState = を追加します。


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    end
  2. 正しい状態が受信されたことを確認するには、endState を含む印刷文を追加します。


    while true do
    displayManager.updateStatus("Waiting for Players")
    repeat
    task.wait(gameSettings.intermissionDuration)
    until #Players:GetPlayers() >= gameSettings.minimumPlayers
    displayManager.updateStatus("Get ready!")
    task.wait(gameSettings.transitionTime)
    matchManager.prepareGame()
    local endState = matchEnd.Event:Wait()
    print("Game ended with: " .. endState)
    end
  3. In 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
  4. 一致をテストします。タイマーが切れると、印刷文が TimerUp 変数に保存された文字列を含んでいるかどうかをチェックします。

トラブルシュートのヒント

この時点では、メッセージは表示されませんでした。以下のいずれかを試してください。

  • 終了状態変数が呼ばれる場所で、ここのように正確に書かれていることを確認してください: gameSettings.endStates.TimerUp
  • Make sure to use : (colon operator) ドット演算子の代わりに を使用してください, like in .

勝利する一致合をコードする

次に、スクリプトは勝利したプレイヤーを識別し、負けたプレイヤーを削除し、タイマーを停止するなどのクリーンアップを実行する必要があります。試合は、1人のプレイヤーが残った場合にも終了します。FoundWinner 条件が満たされているかどうかを確認するには、マッチでプレイヤーを追跡するテーブルに残された数をチェックする機能が必要です。

プレイヤー数をチェック

試合は、残りのプレイヤーが 1 人しかいない場合に終了します。これをチェックするには、スクリプトはラウンドでプレイヤーを追跡する必要があります。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")
  2. respawnPlayerInLobby() 、新しいローカル関数 checkPlayerCount() を追加します。


    -- プレイヤー変数
    local activePlayers = {}
    local playerWeapon = ServerStorage.Weapon
    local function checkPlayerCount()
    end
    local function respawnPlayerInLobby(player)
  3. その機能内では、if 然後文を使用して勝者をチェックします。その文では:

    • activePlayers テーブルのサイズが 1 かどうかをチェックします。
    • そうなると、matchEnd を発射し、gameSettings.endStates.FoundWinner をパスします。

    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end

プレイヤーを削除する

プレイヤーが削除されない限り、正確なカウントは維持できません。プレイヤーが敗北すると、プレイヤーテーブルから削除して正確なプレイヤー数を維持します。次に、アクティブなプレイヤーテーブルのサイズを確認して、勝者がいるかどうかを確認します。

  1. の下で、パラメーター名が の新しいローカル関数を作成します。


    local function checkPlayerCount()
    if #activePlayers == 1 then
    matchEnd:Fire(gameSettings.endStates.FoundWinner)
    end
    end
    local function removeActivePlayer(player)
    end
  2. activePlayers テーブルでプレイヤーを見つけるには、for ループを使用してそれを順回しします。次に、名前に一致するプレイヤーが関数にパスされた場合に実行する if 文を追加します。


    local function removeActivePlayer(player)
    for playerKey, whichPlayer in activePlayers do
    if whichPlayer == player then
    end
    end
    end
  3. プレイヤーを削除するには、if 文で:

    • 呼び出し table.remove() 。括弧の内側で、activePlayers 、見るテーブル、および playerKey - テーブルから削除するプレイヤーをパスします。
    • playersLeft オブジェクトの値を #activePlayers に設定します。
    • checkPlayerCount() を実行して勝利するプレイヤーをチェックします。

    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

イベントとテストを接続する

まったく新しい関数を使用するには、プレイヤーの Died イベントに接続された無名関数からそれを呼び出します。

  1. preparePlayer() を見つけます。Died イベント接続の無記名関数で、removeActivePlayer() を呼び出します。その後、プレイヤーをパラメータとして渡します。


    humanoid.Died:Connect(function()
    respawnPlayerInLobby(player)
    removeActivePlayer(player)
    end)
  2. 勝利したプレイヤーが見つかるかどうかを確認するには、 テストサーバー を開始します。プレイヤーが 1人しか残っていないときは、出力ウィンドウに FoundWinner が表示されるはずです。

  3. テストを続けて、マッチが終了するようにします。新しいマッチが開始すると、出力ウィンドウにエラーが表示されます:

このエラーは、タイマーが停止していなかったため、次のセクションで修正されます。

タイマーを停止する

試合が勝利したプレイヤーで終わるたびに、タイマーも停止する必要があります。時間切れ前にタイマーを停止するには、マッチ終了イベントが発動するたびにタイマーが停止するようにします。これはイベントを作成するメリットの 1つです。複数の状況で再利用でき、原因と結果の関係をスクリプトすることができます。

  1. In MatchManager では、新しいローカル関数 stopTimer() を作成します。内部では、タイマーを停止するために myTimer:stop() を入力します。


    -- マッチ時間を追跡するために使用される新しいタイマーオブジェクトを作成します。
    local myTimer = timer.new()
    -- ローカル機能
    local function stopTimer()
    myTimer:stop()
    end
    local function timeUp()
    matchEnd:Fire(gameSettings.endStates.TimerUp)
    end
  2. マッチが終了するとタイマーを停止するには、matchEnd イベントを stopTimer() に接続します。


    -- モジュール機能
    function MatchManager.prepareGame()
    playerManager.sendPlayersToMatch()
    matchStart:Fire()
    end
    matchStart.Event:Connect(startTimer)
    matchEnd.Event:Connect(stopTimer)
    return MatchManager
  3. テスト 前のエラーがもはや発生しないように、 サーバー を開始します。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 = 5
GameSettings.matchDuration = 10
GameSettings.minimumPlayers = 2
GameSettings.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 do
displayManager.updateStatus("Waiting for Players")
repeat
task.wait(gameSettings.intermissionDuration)
until #Players:GetPlayers() >= gameSettings.minimumPlayers
displayManager.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