ラウンドを追加

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

ラウンドの追加 では、明確な開始と終了ポイントでゲームプレイを段階化し、プレイヤーが進捗状況を測定し、平等な競争環境を得るための定期的な機会を持つことができます。これはチームベースのゲームプレイに特に重要で、プレイヤーがそのラウンド中にチームに誰がいるかに応じてプレイスタイルを切り替える機会を提供するためです。

[サンプルレーザータグエクスペリエンス] を参考にして、このチュートリアルのセクションでは、Roblox の内蔵機能を使用して各ラウンドを構造化する方法、スクリプトガイドについて:

  • 個々のポイントとチームポイントをリセットしてラウンドを開始し、プレイヤーをチームスポーンゾーンにスポーンさせます。
  • 各プレイヤーの画面の上部に置かれるラウンドの目標を設定する変数をカスタマイズする。
  • チームのスコアに対するプレイヤーのポイント貢献を追跡する。
  • プレイヤーのチームがラウンドに勝ったか負けたかに応じて、ユニークな UI スクリーンをトリガーする。
  • プレイヤーを切断して中立ロビーにスポーンしてラウンドを終了する。

このセクションを完了すると、プレイヤーに正確で満足の行くブラスター動作を実装する方法を学びます。

ループを開始

サーバースクリプトサービス > ゲームプレイ > ラウンド は、ラウンドの実装に関するロジックのほとんどを処理し、ラウンドループの開始をマークするために startRoundLoopAsync() 関数を呼び出して開始します。プレイヤーがロビーに参加し、チームに分配されるのを待っている間、startRoundLoopAsync() は、resetScores() 機能を呼び出し、 サーバースクリプトサービス > ゲームプレイ > スコアリング で、リーダーボードとチームポイントの両方をリセットします。

スコアリング

function Scoring.resetScores()
for _, player in Players:GetPlayers() do
player.leaderstats.Points.Value = 0
end
for _, team in Teams:GetTeams() do
team:SetAttribute(GuiAttribute.teamPoints, 0)
end
end

今や誰もがゼロポイントから始まっているので、 は、 中立 スポーン場所の プロパティを 偽り に設定して、スポーン場所のプロパティと同じ プロパティを持つプレイヤーだけがそこにスポーンできるようにします。スポーン場所の TeamColor プロパティがサンプルのミントまたはカーネーションピンクチームではなく、 ホワイト に設定されているため、この構成ではすべてのプレイヤーがラウンドが活性である間、そこでスポーンまたはリスポーンすることを防ぎます。

現在ロビーにいるプレイヤーの場合、startRoundLoopAsync() は現在のエクスペリエンス内のすべてのプレイヤーをspawnPlayersInMap にパスし、 ServerScriptService > ゲームプレイ > ラウンド > spawnPlayersInMap に移動して、約同数のプレイヤーで全員をチームに分け、排序してバランスを取ります。

ロビーグループがチームに分類された後、エクスペリエンスに参加する新しいプレイヤーのために、startRoundLoopAsync()Players.PlayerAdded:Connect イベントを聞き、再び spawnPlayersInMap 関数を呼び出して、最少のプレイヤー数でチームに追加します。このプロセスに関する詳細は、スポーン場所の構成 前の スポーンとリスポーン セクションのチュートリアルから参照してください。

ラウンド

-- マップ上のすべてのプレイヤーをスポーンする
neutralSpawn.Neutral = false
spawnPlayersInMap(Players:GetPlayers())
-- 参加すると、マップ上で新しいプレイヤーをスポーンする
local playerAddedConnection = Players.PlayerAdded:Connect(function(player: Player)
spawnPlayersInMap({ player })
end)

目標を設定

各プレイヤーがチームメイトと一緒にアリーナにいるので、経験はラウンド内で成功するために何をすべきかの指示を提供する必要があります。サンプルレーザータグエクスペリエンスは、各プレイヤーの画面の上部に目的のプロンプトを提供し、勝つためにチームが行う必要があることについて明確な指示を提供することで、この要件を解決します。

UI カリキュラムで 目標 UI コンポーネントの構成と表示方法について詳しく学ぶことができる一方、このセクションでは、ラウンドが開始すると目標ゴールを実装する方法に焦点を当て、各チームがラウンドを完了するために必要なポイント量を設定する方法から始めます。

実行時の目標プロンプトは、プレイヤーが勝つには 3 ポイントを得る必要があると通知しますが、 StarterGui > HUDGui でプロンプトを調べると、ポイント値の配置可能な " %d" が含まれていることがわかります。

%d "は、いつでも更新して自分のゲームプレイ要件に合わせることができるプレースホルダーストリングで、 TEAM_SCORE_LIMIT 変数を ReplicatedStorage > TEAM_SCORE_LIMIT で更新して、自分のゲームプレイ要件に合わせることができます。たとえば、この数字を過度に高い 200 に設定した場合、プロンプトとチームポイントカウンターがそれに応じて更新されます。

チーム_スコア_制限

local TEAM_SCORE_LIMIT = 200 -- 更新された行、必ず戻戻るてください
return TEAM_SCORE_LIMIT

このシンプルな変数更新は、ランタイムで動作します。なぜなら、ラウンドが始まると、 ReplicatedStorage > HUDGuiSetup > SetObjective は、UIオブジェクティブの TEAM_SCORE_LIMIT オブジェクトにプレースホルダー文字列を交換するために、TextLabel モジュールスクリプトが必要だからです。

チーム_スコア_制限

local TEAM_SCORE_LIMIT = require(ReplicatedStorage.TEAM_SCORE_LIMIT)
local function setObjective(gui: ScreenGui)
local bodyTextLabel = gui.Objective.ObjectiveDisplay.Body.BodyTextLabel
bodyTextLabel.Text = bodyTextLabel.Text:format(TEAM_SCORE_LIMIT)
end

トラックポイント

プレイヤーがラウンドの目標を持ったので、経験は目標に到達するまで、各チームのポイントを追跡する必要があります。サービスのデフォルト動作は、各プレイヤーをチームの下に自動的にグループ化し、それぞれのプレイヤーの貢献をチームスコアに追加しますが、ラウンドベースのゲームプレイのために別の場所にポイントを保存し、モニタリングすることが重要です。なぜなら、プレイヤーが得点したら、ラウンドが終わる前に切断した場合、その貢献はリーダーボードから削除されるからです。

これが発生しないようにし、チームの目標に向けたすべての貢献が保存されるようにするには、 ReplicatedStorage > HUDGuiSetup > StartSyncingTeamPoints は、 属性の下ですべてのポイントを個別に保存します。As teamPoints 増分として、このモジュールスクリプトは機能 startSyncingTeamPoints を呼び出して、オブジェクティブUIコンポーネント内のチームカウンター Class.GuiObjects を見つけます。

チームカウンター と チームBCカウンター を見つけたとき、チームスポーンゾーンと関連する 属性 を取得します。TeamACounter は緑のチームのポイントを表示し、TeamBCounter はピンクのチームのポイントを追跡します。

チームポイントの同期開始

local function startSyncingTeamPoints(gui: ScreenGui)
for _, teamPointCounter in gui.Objective.TeamPointCounter:GetChildren() do
if not teamPointCounter:IsA("GuiObject") then
continue
end
local iconTeamColor = teamPointCounter:GetAttribute(GuiAttribute.teamColor)

モジュールスクリプトは次に、TeamACounter の 機能と TeamBCounter の カーネーションピンク 属性が、対応する サービスの下にある プロパティと一致するかどうかを検証するように呼び出します。そうなると、両チームが返されます。

チームポイントの同期開始

local function getTeamFromTeamColor(teamColor: Color3): Team?
for _, team in Teams:GetTeams() do
if team.TeamColor == teamColor then
return team
end
end
return nil
end

これが発生すると、startSyncingTeamPoints は両チームのカウンターの TextLabel オブジェクトをそれぞれの teamPoints 値に設定し、プレイヤーが反対チームの別のプレイヤーをタグしてポイントを得るたびに更新を続けます。

チームポイントの同期開始

teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)
team:GetAttributeChangedSignal(GuiAttribute.teamPoints):Connect(function()
teamPointCounter.TextLabel.Text = team:GetAttribute(GuiAttribute.teamPoints)

このセクションの内容は、これまでプレイヤーの画面上のポイントを追跡する方法に焦点が当てられてきましたが、チームが目標ゴールに到達してラウンドを勝利するときを知るために、サーバー上で追跡ポイントを処理するロジックをレビューすることが重要です。 サーバースクリプトサービス > ゲームプレイ > スコアリング を再訪問すると、モジュールスクリプトがバインド可能なイベントを作成して開始し、プレイヤーがポイントを得るたびに発動することがわかります。

スコアリング

local teamScoreChangedBindable = Instance.new("BindableEvent")
local Scoring = {
teamScoreChanged = teamScoreChangedBindable.Event,
}

次に、incrementScore 関数を呼び出し、以下のアクションを実行します:

  • Grabs the player's team and their current teamPoints value on the Team オブジェクト in the Teams サービス, then adds one.
  • リーダーボードにプレイヤーの個々のスコアを捕捉し、1つ追加します。
  • 以前に述べたバインド可能イベントを、プレイヤーのチームとスコアの両方で発射します。

このプロセスは、両方のプレイヤーの個人スコアとチームスコアの両方に関して、クライアントとサーバーの両方を効果的に一致させます。

スコアリング

function Scoring.incrementScore(player: Player, amount: number)
local team = player.Team
assert(team, `Player {player.Name} must be on a team to score a point, but has no team`)
local teamPoints = team:GetAttribute(GuiAttribute.teamPoints)
teamPoints += amount
team:SetAttribute(GuiAttribute.teamPoints, teamPoints)
local leaderstat = player.leaderstats.Points
leaderstat.Value += amount
teamScoreChangedBindable:Fire(team, teamPoints)
end

結果を表示

プレイヤーがお互いをタグし、チームのためのポイントを得点したとき、 サーバースクリプトサービス > ゲームプレイ > ラウンド チームが得点したかどうかを確認するために、ラウンド目標に達したかどうかをチェックします。チームのスコアが TEAM_SCORE_LIMIT 変数の ReplicatedStorage > TEAM_SCORE_LIMIT より低い場合、サーバーはチームのスコアが再び得られるまで待機し続けます。

しかし、チームのスコアが TEAM_SCORE_LIMIT 変数に達すると、スクリプトはプレイヤーの名前とチームの名前を持つ roundWinnerRemote イベントインスタンスを発動します。

ラウンド

-- ラウンドが各スコアの後に終了したかどうかをチェック
local team: Team
local score: number = 0
while score < TEAM_SCORE_LIMIT do
team, score = Scoring.teamScoreChanged:Wait()
end
-- 勝利したチームを表示
for _, player in Players:GetPlayers() do
-- ラウンド終了時にプレイヤーが所属するチームを送信する
-- プレイヤーのチームが削除されようとしているため、クライアント
-- 自分のチームをチェックできない
roundWinnerRemote:FireClient(player, team, player.Team)
end

各クライアントリストの ReplicatedStorage > RoundResultsGuiSetup スクリプトは、この roundWinnerRemote イベントインスタンスを聞き取るので、次のことができます:

  • ラウンドの結果とプレイヤーが勝利チームにいたかどうかを発表するユニークな StarterGui > RoundResultsGui UI画面を表示する
  • 勝利または敗北のオーディオクリップを再生します。

たとえば、プレイヤーが勝利ポイントを獲得したチームにいる場合、勝利テキストを表示する UI 画面と、楽しい音を再生するオーディオクリップの形で、ラウンド結果に対する複数のフィードバックを受け取ります。逆に、プレイヤーが勝利ポイントを獲得したチームにいない場合、敗北テキストを表示する UI 画面と、不吉な音を再生するオーディオクリップを受け取ります。

勝利フィードバック
フィードバックを打ち負かす
ラウンド結果GUI設定

local function onRoundWinner(winner: Team, localTeam: Team?)
local victoryDefeatText = "Round ended!"
if localTeam then
-- チームが勝った場合、勝利を表示します! そうでない場合は敗北を表示します...
local isVictory = winner == localTeam
if isVictory then
victorySound:Play()
victoryDefeatText = VICTORY_TEXT
else
defeatSound:Play()
victoryDefeatText = DEFEAT_TEXT
end
end

チームをリセットする

同時に、 サーバースクリプトサービス > ゲームプレイ > ラウンド がチームがラウンド目標に到達し、それぞれのプレイヤーに適切な UI 表示をトリガーするとともに、ラウンドから全プレイヤーをアリーナからロビーに移動し、ラウンドから切断して、それぞれのプレイヤーに適切な UI 表示をトリガーします。これは、ラウンドを正式に終了し、両チームをリセットするプロセスを開始します。

スポーン場所の設定 で同じロジックを使用し、ラウンドでは、中立スポーン場所のプロパティを真に設定して、プレイヤーはチームのステータスに関係なくそこにスポーンできるようになります。これは、ロビーがプレイヤーがラウンドから切断された後にスポーンできる唯一の場所になることを意味します。

ラウンド

-- みんなをロビーに送る
playerAddedConnection:Disconnect()
neutralSpawn.Neutral = true
spawnPlayersInLobby(Players:GetPlayers())

インターミッションの後、 ラウンド サーバースクリプトは、すべてのスコアをリセットし、新しいチームに分類して再びループを開始します。サンプルは、サーバー内にプレイヤーがなくなるまで、このサイクル的なラウンドプロセスを再び繰り返します。

プレイヤーが自分のチームでマップにスポーンし、フルラウンドをプレイできるようになったことで、次のセクションでは、各ブラスターの動作の背後にあるスクリプトについて教えます。