デザインの実装は、組み込まれたUI要素とカスタムUI要素を使用してスタジオでワイヤーフレームを作成するプロセスです。スクリプトを使用してコンテキストに応じたUIをトリガーします。このチュートリアルのエキサイティングなステップでは、すべてのデザインや努力が結集し、プレイヤーとのインタラクションのために完成し、準備が整った一連のワークフローを見ることができます。
サンプルレーザータグ体験 .rbxlファイルを参照として、このユーザーインターフェイス設計カリキュラムのこのセクションでは、UI計画を実現する方法を示し、以下のガイダンスを含みます。
- UIアセットライブラリからアセットIDを取得して、サンプルのレーザータグ体験のUIコンポーネントを再現します。
- スタジオでさまざまなデバイスをエミュレートして、異なる画面やアスペクト比でUIがどのように表示されるかを確認します。
このセクションの技術をレビューした後、自分のプロジェクトに適用して、プレイヤーが体験内でできることをナビゲートするのに役立つエキサイティングなUIコンポーネントを作成できます。
アセットライブラリを取得する
アセットライブラリは、インベントリに追加して簡単にアクセスおよび再利用できるアセットのコレクションです。あなたのプロジェクトで使用するアセットライブラリは、Creator Storeから9つの2D個別UI要素アセットと、このチュートリアルのこのセクションで作成している目的、ブラスターセレクタ、プレイヤー情報コンポーネントの最終バージョンを含んでいます。

rbxassetid://14309094777

rbxassetid://14309094641

rbxassetid://14309678581

rbxassetid://14304828203

rbxassetid://14304827304

rbxassetid://14309678701

rbxassetid://14304826876

rbxassetid://14304827147

rbxassetid://18308375067

rbxassetid://18308372597

rbxassetid://14400935532

rbxassetid://14401148777

rbxassetid://14462567943

rbxassetid://14309187282

rbxassetid://14309518632
アセットライブラリをインベントリから体験に取得するには:
アセットライブラリをインベントリに追加します。
- アセットライブラリの詳細ページに移動します。
- 右上のコーナーで、モデルを取得ボタンをクリックします。アセットライブラリがあなたのインベントリに入り、プラットフォーム上の任意のプロジェクトでこれらのアセットを再利用できます。
スタジオで、ホームタブに移動し、次にツールボックスボタンをクリックします。ツールボックスウィンドウが開きます。

ツールボックスウィンドウで、インベントリタブをクリックします。マイモデルソートが表示されます。

ドロップダウンメニューをクリックし、マイパッケージソートを選択します。
最終画面UIコンポーネントタイルをクリックし、次にエクスプローラーウィンドウで完了したコンポーネントを選択し、それをStarterGuiサービスにドラッグします。これで、最終コンポーネントのいずれかを有効にして、そのデザインを参照できます。
デバイスをエミュレートする
スタジオのデバイスエミュレーターを使用すると、プレイヤーがさまざまなデバイスでUIをどのように表示し、インタラクトするかをテストできます。このツールは、実装プロセスの重要な部分です。なぜなら、スタジオのビューポートのアスペクト比は、プレイヤーがあなたの体験にアクセスするために使用する画面のアスペクト比を必ずしも反映しているわけではなく、すべてのデバイスでUIが読みやすく、アクセス可能であることが重要だからです。
例えば、UIをさまざまな画面サイズでテストしないと、大きな画面を持つプレイヤーはあなたのテキストを読むことができなかったり、アイコンを解読できなかったりするかもしれません。また、小さな画面を持つプレイヤーは、UI要素がディスプレイ上に過剰にスペースを取っているため、3D空間を確認できないかもしれません。
さまざまな画面サイズでUIをエミュレートするには:
スタジオのテストメニューから、デバイスエミュレーターをオンにします。
解像度のドロップダウンから、実際の解像度を選択します。これにより、エミュレートしているデバイス上でUI要素の真の解像度が表示されます。

デバイスのドロップダウンから、電話、タブレット、デスクトップ、およびコンソールセクション内の少なくとも1つのデバイスを選択します。

ScreenGuiオブジェクトを作成する
すべてのプレイヤーの画面にUI要素を表示するには、ScreenGuiオブジェクトをStarterGuiサービスに作成できます。ScreenGuiオブジェクトは、画面上のUIの主要なコンテナであり、StarterGuiサービスは、プレイヤーが体験に参加する際にその内容を各プレイヤーのPlayerGuiコンテナにコピーします。
複数のScreenGuiオブジェクトを作成して、ゲームプレイ中のUI要素のグループをコンテキストに応じて整理して表示できます。たとえば、サンプルのレーザータグ体験では、プレイヤーがメインのユーザーフロー中に異なる条件を満たすまで初期状態で無効化された5つの個別のScreenGuiオブジェクトが含まれています:
- HUDGui - プレイヤーがラウンドにアクティブでいるときの体験のゲームプレイに関する重要な情報を表示します。たとえば、目的や各チームの合計ポイントなどです。
- PickABlasterGui - プレイヤーがラウンドを開始したり再参加したりしたときに、すべてのブラスターの選択肢を表示します。
- ForceFieldGui - プレイヤーがブラスターを選択しているときや、一時的に無敵でいるときに、六角グリッドを表示します。
- OutStateGui - プレイヤーがタグ付けされているとき、画面の周りにダークボーダーを表示します。
- RoundResultsGui - ラウンドの勝者チームに関する情報を含むダークオーバーレイを画面の上に表示します。
ScreenGuiオブジェクトを作成した後には、各コンテナの目的に応じて、その子のGuiObjectsを作成してカスタマイズできます。以下のセクションでは、プレイヤーがサンプルのレーザータグ体験で成功するために知っておくべき情報の3つのカテゴリに関するUI要素を実装する方法を学びます。プロセスのいずれかの部分を自分の体験の仕様に合わせて調整できます。
ScreenGuiオブジェクトを作成するには:
エクスプローラーウィンドウで、StarterGuiサービスにマウスを載せてから、**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
ScreenGuiを挿入します。

子UI要素のコンテキストに応じてScreenGuiの名前を変更します。
すべてのプレイヤーの画面に表示するために必要な各UI要素のグループについて、このプロセスを繰り返します。

目的UI
レイアウトのワイヤーフレームからの視覚的階層のベストプラクティスに従って、このセクションでは、体験の目的に関連するすべての画面上のUI要素を実装する方法を教えます。このUI要素のグループは画面の上部に近く、目的や各チームのポイントが勝つために最も重要だからです。

たとえば、サンプルには、プレイヤーがラウンドで成功するために何をすべきかを知るために参考にする目的UIコンポーネントが提供されています。プレイヤーが敵チームのメンバーをタグ付けしてポイントを獲得すると、このコンポーネントはヘッダーのプロンプト内の全体目標に対して各チームのスコアを追跡します。クライアントとサーバースクリプトがポイントを追跡するために一緒に機能する方法についての高レベルのレビューについては、ポイントを追跡のGameplay Scripting Curriculumをご覧ください。

サンプルのレーザータグ体験内で目的UIを正確に再現するには:
コンポーネント全体のコンテナを作成します。
HUDGui ScreenGuiオブジェクトにFrameを挿入します。
- エクスプローラーウィンドウで、StarterGuiサービスに移動します。
- その子HUDGuiオブジェクトにマウスを載せ、その後に⊕アイコンをクリックします。コンテキストメニューが表示されます。
- コンテキストメニューからFrameを挿入します。

新しいFrameを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0に設定し、フレームの起点を自分の上部中央に設定します(フレームの左から右へ50%、フレームの上から下へ0%)。
- BackgroundTransparencyを1に設定して、フレームの背景を完全に透明にします。
- Positionを{0.5, 0},{0.03, 0}に設定して、画面の上部中央にフレームを配置します(画面の左右50%、上から下へ3%の位置)。
- Sizeを{0.5, 0},{0.13, 0}に設定して、フレームの要素が画面の上部の大部分を占めてプレイヤーの注意を引くようにします(横50%、縦13%)。
- NameをObjectiveに設定します。

(オプション) ObjectiveにUIAspectRatioConstraintを挿入し、ラベルのアスペクト比がプレイヤーの画面サイズにかかわらず同じままになるようにします。サンプルでは、UIAspectRatioConstraint.AspectRatioプロパティは7に設定されています。
目的のプロンプトオブジェクト用のコンテナを作成します。
ObjectiveにFrameを挿入します。
新しいFrameを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0に設定して、フレームの起点を自分の上部中央に設定します(フレームの左から右へ50%、フレームの上から下へ0%)。
- BackgroundTransparencyを1に設定して、フレームの背景を完全に透明にします。
- Positionを{0.5, 0},{0, 0}に設定して、コンテナ内のフレームを中央に配置します(親フレームの左から右へ50%、上から下へ0%)。
- Sizeを{1, 0},{0.67, 0}に設定し、選択UIコンポーネントがコンテナの上から下へ約半分を占めるようにします(親フレームの横100%、縦67%)。
- NameをObjectiveDisplayに設定します。

タイトル要素を作成します。
ObjectiveDisplayにImageLabelを挿入します。
ImageLabelを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 1に設定し、ラベルの起点を自分の下部中央に設定します(ラベルの左から右へ50%、親ラベルの上から下へ100%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- LayoutOrderを-1に設定します。
- Positionを{0.5, 0},{0.34, 0}に設定し、ラベルを親フレームの上部上中央に配置します(親フレームの左から右へ50%、上から下へ34%位置)。
- Sizeを{0.46, 0},{0.34, 0}に設定し、プロンプトエリアをフレームのほぼ半分に広げます(親フレームの横46%、縦34%)。
- NameをHeaderに設定します。
- Imageをrbxassetid://14304828123に設定して、台形を表示します。
- ImageTransparencyを0.15に設定し、ヘッダーを半透明にします。

(オプション) ImageLabelにUIAspectRatioConstraintを挿入し、ラベルのアスペクト比がプレイヤーの画面サイズにかかわらず同じままになるようにします。サンプルでは、UIAspectRatioConstraint.AspectRatioプロパティは13.781に設定されています。
HeaderにTextLabelを挿入して、タイトルを表示します。
新しいラベルを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0.5に設定し、新しいラベルの起点を自分の中央に設定します(ラベルの左から右へ50%、上から下へ50%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.5, 0},{0.5, 0}に設定し、ラベルを親ラベルの中央に配置します(親ラベルの左から右へ50%、上から下へ50%)。
- Sizeを{0.62, 0},{0.55, 0}に設定し、テキストスペースを親ラベルの半分以上に広げます(親ラベルの横62%、縦55%)。
- NameをHeaderTextLabelに設定します。
- FontFaceをMontserratに設定して、未来的な美観を整えます。
- WeightをMediumに設定して、フォントを太くします。
- TextをOBJECTIVEに設定します。
- TextScaledを有効にします。

プロンプト要素を作成します。
ObjectiveDisplayにImageLabelを挿入します。
ImageLabelを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 1に設定し、ラベルの起点を自分の下部中央に設定します(ラベルの左から右へ50%、上から下へ100%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.5, 0},{1, 0}に設定し、ラベルを親フレームの底部中央に配置します(親フレームの左から右へ50%、上から下へ100%)。
- Sizeを{0.89, 0},{0.66, 0}に設定し、テキストスペースを親フレームの全幅近くに広げるようにします(親フレームの横89%、縦66%)。
- NameをBodyに設定します。
- Imageをrbxassetid://14304827265に設定し、逆さ台形を表示します。
- ImageColor3を0, 0, 0に設定し、画像を黒に染めます。
- ImageTransparencyを0.3に設定し、ヘッダーを半透明にします。

(オプション) ImageLabelにUIAspectRatioConstraintを挿入し、ラベルのアスペクト比がプレイヤーの画面サイズにかかわらず同じままになるようにします。サンプルでは、UIAspectRatioConstraint.AspectRatioプロパティは13.781に設定されています。
BodyにTextLabelを挿入して、プロンプトを表示します。
新しいラベルを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0.5に設定し、新しいラベルの起点を自分の中央に設定します(ラベルの左から右へ50%、上から下へ50%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.5, 0},{0.5, 0}に設定し、ラベルを親ラベルの中央に配置します(親ラベルの左から右へ50%、上から下へ50%)。
- Sizeを{0.85, 0},{0.39, 0}に設定し、テキストスペースを親ラベルの半分以上に広げます(親ラベルの横85%、縦39%)。
- NameをBodyTextLabelに設定します。
- FontFaceをMontserratに設定して、未来的な美観を整えます。
- WeightをMediumに設定して、フォントを太くします。
- TextColor3を255, 255, 255に設定し、ダークバックグラウンドに対してテキストを白くします。
- Textを**対戦相手にタグ付けしてポイントを獲得しよう!最初のチームが%dポイントで勝利。**に設定します。
- TextScaledを有効にします。

目的のチームカウンターのためのコンテナを作成します。
ObjectiveにFrameを挿入します。
新しいFrameを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 1に設定し、フレームの起点を自分の下部中央に設定します(フレームの左から右へ50%、上から下へ100%)。
- BackgroundTransparencyを1に設定して、フレームの背景を完全に透明にします。
- Positionを{0.5, 0},{1, 0}に設定して、コンテナの底部中央にフレームを配置します(親フレームの左から右へ50%、上から下へ100%)。
- Sizeを{0.44, 0},{0.27, 0}に設定し、選択UIコンポーネントが親フレームの左右の半分未満を占めるようにします(親フレームの横44%、縦27%)。
- NameをTeamPointCounterに設定します。

チームカウンターの周囲にパディングを作成します。
- ステップ5のフレームにUIListLayoutオブジェクトを挿入します。
- UIListLayoutオブジェクトを選択し、プロパティウィンドウで、
- Paddingを0.025, 0に設定して、将来のチームカウンターの間にスペースを提供します。
- FillDirectionをHorizontalに設定して、各チームカウンターが隣り合うように表示されるようにします。
- HorizontalAlignmentをCenterに設定して、各チームカウンターが互いに中央に整列するようにします。
グリーンチームカウンター要素を作成します。
TeamPointCounterにImageLabelを挿入します。
新しいImageLabelを選択し、プロパティウィンドウで、
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.5, 0},{1, 0}に設定して、ラベルを親フレームの底部中央に配置します(親フレームの左から右へ50%、上から下へ100%)。
- Sizeを{0.5, 0},{1, 0}に設定し、ラベルを親フレームの幅の半分に広げます(親フレームの横50%、縦100%)。
- NameをTeamACounterに設定します。
- Imageをrbxassetid://14304826831に設定して、方向のフェードを表示します。
- ImageColor3を88, 218, 171に設定して、画像をミントグリーンに染めます。

このラベルがグリーンチーム用であることを追跡するカスタム属性を設定します。
- プロパティウィンドウでAttributesセクションに移動し、プラスアイコンをクリックします。ポップアップダイアログが表示されます。
- 名前フィールドにteamColorと入力します。
- タイプドロップダウンメニューからBrickColorを選択します。
- 保存ボタンをクリックします。
- 新しいteamColor属性をMintに設定します。
TeamACounterにTextLabelを挿入して、プロンプトを表示します。
新しいラベルを選択し、プロパティウィンドウで、
- AnchorPointを1, 0.5に設定し、新しいラベルの起点を自分の右中央に設定します(ラベルの左から右へ100%、上から下へ50%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.95, 0},{0.5, 0}に設定して、ラベルを親ラベルの右側に移動します(親ラベルの左から右へ95%、上から下へ50%)。
- Sizeを{0.85, 0},{0.39, 0}に設定し、テキストスペースを親ラベルの半分以上に広げます(親ラベルの横85%、縦39%)。
- FontFaceをMontserratに設定して、未来的な美観を整えます。
- WeightをBoldに設定して、フォントを太くします。
- TextColor3を255, 255, 255に設定して、ダークバックグラウンドに対してテキストを白くします。
- Textを**-**に設定します。
- TextScaledを有効にします。
- TextXAlignmentをRightに設定します。

TextLabelにUIStrokeオブジェクトを挿入し、プロパティウィンドウでColorを8, 78, 52に設定して、ダッシュをダークグリーンのストロークで囲みます。

ピンクチームカウンター要素を作成します。
TeamAICounterとその子を複製します。
複製されたTeamACounterを選択し、プロパティウィンドウで、
- NameをTeamBCounterに設定します。
- Imageをrbxassetid://14305849451に設定して、反対方向に進む方向のフェードを表示します。
- ImageColor3を255, 170, 255に設定して、画像をカーネーションピンクに染めます。
- teamColor属性をCarnation Pinkに設定します。
複製されたTextLabelをTeamBCounterの子として選択し、プロパティウィンドウで、
- AnchorPointを0, 0.5に設定して、新しいラベルの起点を自分の左中央に設定します(ラベルの左から右へ0%、上から下へ50%)。
- Positionを{0.05, 0},{0.5, 0}に設定して、ラベルを親ラベルの左側に移動します(親ラベルの左から右へ5%、上から下へ50%)。
- TextXAlignmentをLeftに設定します。
複製されたUIStrokeをTeamBCounterの子として選択し、プロパティウィンドウでColorを158, 18, 94に設定して、ダッシュをダークピンクのストロークで囲みます。

サンプルのレーザータグプレスファイル内で、目的のプロンプトをプログラム的に更新し、チームポイントを追跡するReplicatedStorageスクリプトを参照します。
次のスクリプトでは、setObjectiveおよびstartSyncingTeamPointsを含む、メインのHeads Up Display (HUD)を設定するために協力するモジュールスクリプトのセットが必要です。プレイヤーがラウンドに参加し、自分のブラスターを選択すると、このスクリプトはすべてのHUD UI要素がプレイヤーの状態、デバイスおよびチームのステータスに適切に表示されることを確実にします。
local Players = game:GetService("Players")local setPlayerPortrait = require(script.setPlayerPortrait)local setPlayerName = require(script.setPlayerName)local startSyncingTeamColor = require(script.startSyncingTeamColor)local setObjective = require(script.setObjective)local setupTouchButtonAsync = require(script.setupTouchButtonAsync)local startSyncingTeamPoints = require(script.startSyncingTeamPoints)local disableMouseWhileGuiEnabled = require(script.disableMouseWhileGuiEnabled)local setupHitmarker = require(script.setupHitmarker)local localPlayer = Players.LocalPlayerlocal gui = localPlayer.PlayerGui:WaitForChild("HUDGui")setPlayerPortrait(gui)setPlayerName(gui)startSyncingTeamColor(gui)setObjective(gui)startSyncingTeamPoints(gui)disableMouseWhileGuiEnabled(gui)setupHitmarker(gui)setupTouchButtonAsync(gui)
ブラスターUI
レイアウトのワイヤーフレームからの視覚的階層のベストプラクティスに従って、このセクションでは、プレイヤーのブラスターに関連するすべての画面上のUI要素を実装する方法を教えます。このUI要素のグループは画面の中央付近を占め、3D空間のアクションにプレイヤーの注意を引くための焦点として機能し、ゲームをプレイする上で最も重要です。

クロスヘア
クロスヘアは、プレイヤーが武器を発射する際に影響を与える場所を知らせるUI要素です。このUI要素は、プレイヤーがブラスターを正確に狙い、敵チームのメンバーをタグ付けするために必要不可欠な要素です。
ほとんどのファーストパーソンシューティング体験のように、サンプルのレーザータグ体験ではクロスヘアが画面の中心に配置され、プレイヤーが3D空間を移動している間に焦点を合わせる静的なものを提供します。これにより、動きによる病気を軽減するだけでなく、クロスヘアが環境に溶け込むことも可能になります。

サンプルのレーザータグ体験内でクロスヘアを正確に再現するには:
HUDGui ScreenGuiオブジェクトにImageLabelを挿入します。
エクスプローラーウィンドウで、StarterGuiサービスに移動します。
その子HUDGuiオブジェクトにマウスを載せ、その後に**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューからImageLabelを挿入します。

新しいImageLabelを選択し、プロパティウィンドウで、
- Imageをrbxassetid://14400935446に設定します。
- AnchorPointを0.5, 0.5に設定し、ラベルの起点をラベルの中央に設定します(ラベルの左から右へ50%、上から下へ50%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- NameをCrosshairに設定します。
- Positionを{0.5,0},{0.5,0}に設定し、ラベルを画面の中央に配置します。
- ScaleTypeをFitに設定して、画像がコンテナに収まり、さまざまな画面サイズで伸びないようにします。
(オプション) CrosshairにUIAspectRatioConstraintを挿入し、ラベルのアスペクト比がプレイヤーの画面サイズにかかわらず同じままになるようにします。サンプルでは、UIAspectRatioConstraint.AspectRatioプロパティは0.895に設定されています。
ヒットマーカー
ヒットマーカーは、ブラスターの発射が敵チームの他のプレイヤーに影響を与えたときだけ表示されるUI要素です。クロスヘアと同様に、このUI要素は、プレイヤーが対戦相手をうまくタグ付けしたときに視覚的なフィードバックを提供するため、ファーストパーソンシューティング体験に不可欠です。

サンプルのレーザータグ体験内でヒットマーカーを正確に再現するには:
Crosshair ImageLabelオブジェクトにImageLabelを挿入します。
エクスプローラーウィンドウで、StarterGuiサービスに移動します。
その子Crosshairオブジェクトにマウスを載せ、その後に**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューからImageLabelを挿入します。

新しいImageLabelを選択し、プロパティウィンドウで、
- Imageをrbxassetid://14401148736に設定して、長方形のヒットマーカーアイコンを表示します。
- AnchorPointを0.5, 0.5に設定し、ラベルの起点をラベルの中央に設定します。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.5,0},{0.5,0}に設定し、ラベルを画面の中央に配置します。
- NameをHitmarkerに設定します。
- Sizeを{0.6, 0},{0.06, 0}に設定し、クロスヘアの中心周囲の長方形のサイズを減少させます。
- ImageTransparencyを1に設定し、ヒットマーカーを完全に透明にします。次のステップのスクリプトが、プレイヤーの発射が敵チームのプレイヤーに影響を与えたときに透明度を戻します。
サンプルのレーザータグプレスファイル内で、発射が敵チームのプレイヤーに影響を与えたときにヒットマーカーをプログラム的に表示するReplicatedStorageスクリプトを参照します。
次のスクリプトでは、setupHitmarkerを含むメインのHeads Up Display (HUD)を設定するために協力するモジュールスクリプトのセットが必要です。プレイヤーがラウンドに参加し、自分のブラスターを選択すると、このスクリプトはすべてのHUD UI要素がプレイヤーの状態、デバイスおよびチームのステータスに適切に表示されることを確実にします。
local Players = game:GetService("Players")local setPlayerPortrait = require(script.setPlayerPortrait)local setPlayerName = require(script.setPlayerName)local startSyncingTeamColor = require(script.startSyncingTeamColor)local setObjective = require(script.setObjective)local setupTouchButtonAsync = require(script.setupTouchButtonAsync)local startSyncingTeamPoints = require(script.startSyncingTeamPoints)local disableMouseWhileGuiEnabled = require(script.disableMouseWhileGuiEnabled)local setupHitmarker = require(script.setupHitmarker)local localPlayer = Players.LocalPlayerlocal gui = localPlayer.PlayerGui:WaitForChild("HUDGui")setPlayerPortrait(gui)setPlayerName(gui)startSyncingTeamColor(gui)setObjective(gui)startSyncingTeamPoints(gui)disableMouseWhileGuiEnabled(gui)setupHitmarker(gui)setupTouchButtonAsync(gui)
ブラスターセレクター
ブラスターセレクターは、プレイヤーがラウンドに参加する前にブラスタータイプを選択するために使用するUIコンポーネントです。サンプルのレーザータグ体験では、複数のビームを発生させる広い水平分布を持つブラスターと、シングルビームを発生させるブラスターの2つのタイプのブラスターが提供されます。プレイヤーが選択するブラスターのタイプは、ラウンド中の戦略に影響を与え、このUIコンポーネントは全体的な体験にとって不可欠なワークフローです。
次のステップでは、異なるUI要素グループのいくつかのコンテナ、プロンプトを持つヘッダー、ナビゲーションと選択ボタン、そしてブラスターボタンのプレファブを作成する方法について詳述します。全体のコンポーネントに対するスクリプトロジックは、各ブラスタータイプを表すConfigurationインスタンスに応じて、ブラスターボタンプレファブ内に異なる視覚的特性を自動的に表示します。
この設定により、StarterGui.PickABlasterGui内で個別のボタンを作成することなく、他のブラスタータイプの追加Configurationインスタンスを作成できます。

サンプルのレーザータグ体験内でブラスターセレクターを正確に再現するには:
コンポーネント全体のコンテナを作成します。
PickABlaster ScreenGuiオブジェクトにFrameを挿入します。
- エクスプローラーウィンドウで、StarterGuiサービスに移動します。
- その子PickABlasterオブジェクトにマウスを載せ、その後に⊕アイコンをクリックします。コンテキストメニューが表示されます。
- コンテキストメニューからFrameを挿入します。

新しいフレームを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 1に設定し、フレームの起点を自分の下部中央に設定します(フレームの左から右へ50%、上から下へ100%)。
- BackgroundTransparencyを1に設定して、フレームの背景を完全に透明にします。
- Positionを{0.5, 0},{0.9, 0}に設定し、画面の底部中央近くにフレームを配置します(画面の左から右へ50%、上から下へ92.4%の位置)。
- Sizeを{0.8, 0},{0.25, 0}に設定し、ブラスターセレクターのUIコンポーネントが画面の大部分を占めてプレイヤーの注意を引くようにします(横80%、縦25%)。
- NameをComponentに設定します。

(オプション) ComponentにUIAspectRatioConstraintを挿入し、フレームとその子UI要素のアスペクト比がプレイヤーの画面サイズにかかわらず同じままになるようにします。サンプルでは、UIAspectRatioConstraint.AspectRatioプロパティは5に設定されています。
UI要素のグループを保持するためのコンテナを作成します。
ComponentにFrameを挿入します。
新しいフレームを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0.5に設定し、フレームの起点を自分の中央に設定します(フレームの左から右へ50%、上から下へ50%)。
- BackgroundTransparencyを1に設定して、フレームの背景を完全に透明にします。
- Positionを{0.5, 0},{0.375, 0}に設定し、親フレームの上部中央近くにフレームを配置します(親フレームの左から右へ50%、上から下へ37.5%の位置)。
- Sizeを{1, 0},{0.75, 0}に設定し、選択UIコンポーネントがコンテナの4分の3を占めるようにします(縦の100%、親フレームの75%)。
- NameをSelectionFrameに設定します。

ブラスターセレクターのプロンプトを作成します。
SelectionFrameにImageLabelを挿入します。
新しいラベルを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 1に設定し、ラベルの起点を自分の下部中央に設定します(ラベルの左から右へ50%、上から下へ100%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- LayoutOrderを-1に設定します。
- Positionを{0.5, 0},{0.22, 0}に設定し、ラベルを親フレームの上部上中央に配置します(親フレームの左から右へ50%、上から下へ22%の位置)。
- Sizeを{0.45, 0},{0.22, 0}に設定して、プロンプトエリアをフレームのほぼ半分に広げます(親フレームの横45%、縦22%)。
- NameをHeaderに設定します。
- Imageをrbxassetid://14304828123に設定して、台形を表示します。
- ImageTransparencyを0.15に設定し、ヘッダーを半透明にします。

(オプション) ラベルにUIAspectRatioConstraintを挿入し、ラベルのアスペクト比がプレイヤーの画面サイズにかかわらず同じままになるようにします。サンプルでは、UIAspectRatioConstraint.AspectRatioプロパティは13.78に設定されています。
HeaderにTextLabelを挿入して、プロンプトを表示します。
新しいラベルを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0.5に設定し、新しいラベルの起点を自分の中央に設定します(ラベルの左から右へ50%、上から下へ50%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- Positionを{0.5, 0},{0.5, 0}に設定し、ラベルを親ラベルの中央に配置します(親ラベルの左から右へ50%、上から下へ50%)。
- Sizeを{0.6, 0},{0.55, 0}に設定し、テキストスペースを親ラベルの半分以上に広げます(親ラベルの横60%、縦55%)。
- NameをHeaderTextLabelに設定します。
- FontFaceをMontserratに設定して、未来的な美観を整えます。
- WeightをMediumに設定して、フォントを太くします。
- Textをブラスターを選択に設定します。
- TextScaledを有効にします。

ブラスターボタンコンテナと選択矢印のためのコンテナを作成します。
- SelectionFrameにImageLabelを挿入します。
- 新しいラベルを選択し、プロパティウィンドウで、1. デフォルトの Image 値を削除します。
AnchorPoint を 0.5, 1 に設定して、ラベルの起点をラベルの下中央に設定します(ラベルの左から右まで50%、上から下まで100%)。
BackgroundColor を 0, 0, 0 に設定して、ラベルを黒くします。
BackgroundTransparency を 0.3 に設定して、ラベルの不透明度を30%減少させ、体験内のすべての黒いUI要素と一致させます。
Position を {0.5, 0},{1, 0} に設定して、ラベルをフレームの下中央に配置します(親フレームの左から右まで50%、上から下まで100%)。
Size を {1, 0},{0.77, 0} に設定して、ラベル領域をプロンプトの下のスペースに広げます(親フレームの横方向100%、縦方向77%を占める)。

コンテナの角を丸めます。
- ラベルに UICorner オブジェクトを挿入します。
- 新しいコーナーオブジェクトを選択し、Properties ウィンドウで、CornerRadius を 0.075, 0 に設定して、角を丸めます。

ブラスターのボタン用のコンテナを作成します。
ステップ4のラベルに Frame を挿入します。
新しいフレームを選択し、Properties ウィンドウで、
- AnchorPoint を 0.5, 0.5 に設定して、新しいフレームの起点を中央に設定します(フレームの左から右まで50%、上から下まで50%)。
- BackgroundTransparency を 1 に設定して、フレームの背景を完全に透明にします。
- Position を {0.5, 0},{0.5, 0} に設定して、フレームを親ラベルの中央に配置します(親フレームの左から右まで50%、上から下まで50%)。
- Size を {0.85, 0},{0.77, 0} に設定して、フレーム領域をラベルのほとんどを占めるように広げます(横方向85%、縦方向77%)。
- Name を Container に設定します。

すべての将来のブラスターのボタン用のパディングを作成します。
- ステップ5のフレームに UIListLayout オブジェクトを挿入します。
- 新しいレイアウトオブジェクトを選択し、Properties ウィンドウで、
- Padding を 0.035, 0 に設定して、すべての将来のボタンの間にスペースを提供します。
- FillDirection を Horizontal に設定して、各ボタンが横に表示されるようにします。
- HorizontalAlignment と VerticalAlignment の両方を Center に設定して、各ボタンが互いに中央に配置されるようにします。
左のナビゲーションボタンを作成します。
ステップ4の ImageLabel に ImageButton オブジェクトを挿入します。
新しいボタンを選択し、Properties ウィンドウで、
- デフォルトの Image 値を削除します。
- AnchorPoint を 0, 0.5 に設定して、新しいボタンの起点を左中央に設定します(ボタンの左から右まで0%、上から下まで50%)。
- BackgroundTransparency を 0.15 に設定して、ボタンが選択可能であることの視覚的フィードバックを提供します。
- Position を {0.02, 0},{0.5, 0} に設定して、親コンテナからボタンの左側にパディングを提供します(親ラベルの左から右まで2%、上から下まで50%)。
- Size を {0.04, 0},{0.33, 0} に設定して、選択ボタンをブラスターのボタンよりもはるかに小さくします(親フレームの横方向4%、縦方向33%)。
- Name を NavigationButtonLeft に設定します。

ボタンの角を丸めます。
- ボタンに UICorner オブジェクトを挿入します。
- 新しいコーナーオブジェクトを選択し、Properties ウィンドウで、CornerRadius を 0.1, 0 に設定して、角を丸めます。

ボタンに ImageLabel オブジェクトを挿入します。
新しいラベルを選択し、Properties ウィンドウで、
- AnchorPoint を 0.5, 0.5 に設定して、新しいラベルの起点を中央に設定します(ラベルの左から右まで50%、上から下まで50%)。
- Position を {0.45, 0},{0.5, 0} に設定して、ラベルを親ボタンの中央近くに配置します(親ボタンの左から右まで45%、上から下まで50%)。この値は中央に見えません。なぜなら、矢印は {0.5, 0},{0.5, 0} でボタンの中央に視覚的に見えないからです。
- Size を {0.8, 0},{0.8, 0} に設定して、プロンプトの下のスペースにラベル領域を広げます(親フレームの横方向80%、縦方向80%)。
- BackgroundTransparency を 1 に設定して、画像の背景を完全に透明にします。
- Image を rbxassetid://14309187238 に設定します。
- ScaleType を Fit に設定します。

右のナビゲーションボタンを作成します。
NavigationButtonLeft を複製します。
複製したボタンを選択し、Properties ウィンドウで、
- AnchorPoint を 1, 0.5 に設定して、新しいボタンの起点を右中央に設定します(ボタンの左から右まで100%、上から下まで50%)。
- Position を {0.98, 0},{0.5, 0} に設定して、親コンテナからボタンの右側にパディングを提供します(親ラベルの左から右まで98%、上から下まで50%)。
- Name を NavigationButtonRight に設定します。
ImageLabel の子オブジェクトを選択します。
- Rotation を 180 に設定して画像を反転させます。
- Position を {0.55, 0},{0.5, 0} に設定して、ラベルを親ボタンの中央近くに配置します(親ボタンの左から右まで55%、上から下まで50%)。この値は中央に見えません。なぜなら、矢印は {0.5, 0},{0.5, 0} でボタンの中央に視覚的に見えないからです。

SELECT ボタンを作成します。
Component に ImageButton を挿入します。このプロセスにより、選択ボタンを SelectionFrame から分離できるので、コンポーネントのメイン部分と選択ボタンの間にパディングを追加できます。
新しいボタンを選択し、Properties ウィンドウで、
- デフォルトの Image 値を削除します。
- AnchorPoint を 0.5, 1 に設定して、新しいボタンの起点をラベルの下中央に設定します(ボタンの左から右まで50%、上から下まで100%)。
- BackgroundTransparency を 0.15 に設定して、ボタンが選択可能であることの視覚的フィードバックを提供します。
- Position を {0.5, 0},{0.99, 0} に設定して、ボタンを親フレームの下中央近くに配置します(親フレームの左から右まで50%、上から下まで99%)。
- Size を {0.17, 0},{0.18, 0} に設定して、ボタンをブラスターのボタンの下に長くします(親フレームの横方向17%、縦方向18%)。
- Name を SelectButton に設定します。

ボタンの角を丸めます。
- ボタンに UICorner オブジェクトを挿入します。
- 新しいコーナーオブジェクトを選択し、Properties ウィンドウで、CornerRadius を 0.2, 0 に設定して、角を丸めます。

ボタンにアクションを表示するための TextLabel オブジェクトを挿入します。
新しいラベルを選択し、Properties ウィンドウで、
- AnchorPoint を 0.5, 0.5 に設定して、新しいラベルの起点を中央に設定します(ラベルの左から右まで50%、上から下まで50%)。
- BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
- Position を {0.5, 0},{0.5, 0} に設定して、ラベルをボタンの中央に移動させます(親ボタンの左から右まで50%、上から下まで50%)。
- Size を {0.9, 0},{0.55, 0} に設定して、テキストスペースを親ラベルの幅のほぼすべてに広げます(親ラベルの横方向90%、縦方向55%)。
- Name を SelectTextLabel に設定します。
- FontFace を Montserrat に設定して、未来的な美的に合うようにします。
- Weight を Medium に設定して、フォントを太くします。
- Text を SELECT に設定します。
- TextScaled を有効にします。

ブラスターのボタンプリファブを作成します。
- ReplicatedStorage サービス内に、UIオブジェクトを整理するためのフォルダー構造を作成します。このサンプルは、子フォルダー Guis を持つ Instances フォルダーを使用します。
- Guis フォルダー内に ImageButton オブジェクトを挿入します。
- 新しいボタンを選択し、Properties ウィンドウで、
- デフォルトの Image 値を削除します。
- AnchorPoint を 0.5, 0.5 に設定して、新しいボタンの起点を中央に設定します(ボタンの左から右まで50%、上から下まで50%)。
- BackgroundTransparency を 0.65 に設定して、ボタンがフォーカスされていないことを示す視覚的フィードバックを提供します。ステップ12のスクリプトが、ボタンがフォーカスされたときにプログラム的に視覚的フィードバックを提供します。
- LayoutOrder を 2 に設定します。
- Name を BlasterButtonPrefab に設定します。
- Size を {0.8, 0},{0.8, 0} に設定します。
- ImageTransparency を 1 に設定して、画像を完全に透明にします。
- BlasterButtonPrefab に UIAspectRatioConstraint を挿入して、ボタンのアスペクト比がプレイヤーの画面サイズに関係なく同じになるようにします。
- ボタンの角を丸めます。
- BlasterButtonPrefab に UICorner オブジェクトを挿入します。
- UICorner を選択し、Properties ウィンドウで CornerRadius を 0.05, 0 に設定して、角を丸めます。
- BlasterButtonPrefab に ImageLabel を挿入します。
- 新しいラベルを選択し、Properties ウィンドウで、
- デフォルトの Image 値を削除します。
- AnchorPoint を 0.5, 0.5 に設定して、新しいラベルの起点を中央に設定します(ラベルの左から右まで50%、上から下まで50%)。
- BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
- Position を {0.52, 0},{0.497, 0} に設定して、ラベルを親ボタンの中央近くに配置します(親ボタンの左から右まで52%、上から下まで49.7%)。この値は中央に見えません。なぜなら、ブラスターは {0.5, 0},{0.5, 0} でボタンの中央に視覚的に見えないからです。
- Size を {1.20, 0},{0.9, 0} に設定して、ラベル領域をボタンの外に広げます(親ボタンの横方向120%、縦方向90%)。
- ScaleType を Fit に設定します。
次の ReplicatedStorage スクリプトを参照します。サンプル Laser Tag プレースファイル内で、プログラム的に各ブラスター用のボタンを表示し、プレイヤーがフォーカスされていないボタンを選択したときにボタンのサイズを調整し、プレイヤーのブラスター選択をアバターに付加します。
以下のスクリプトは、ブラスターセレクターを作成するために協力して動作する一連のスクリプトを必要とします。プレイヤーが体験に参加するか、彼らの健康がゼロに達した後にラウンドに再出現すると、このスクリプトは、プレイヤーが選択を行うまでブラスターセレクターのすべてのUI要素をアクティブにします。
local Players = game:GetService("Players")local ReplicatedStorage = game:GetService("ReplicatedStorage")local GuiAttribute = require(ReplicatedStorage.GuiAttribute)local setupBlasterButtons = require(script.setupBlasterButtons)local connectResetSelectionOnEnabled = require(script.connectResetSelectionOnEnabled)local localPlayer = Players.LocalPlayerlocal gui = localPlayer.PlayerGui:WaitForChild("PickABlasterGui")setupBlasterButtons(gui)connectResetSelectionOnEnabled(gui)gui:SetAttribute(GuiAttribute.selectedIndex, 1)
ブラストボタン
ブラストボタンは、プレイヤーがモバイルまたはタブレットデバイスを通じて体験にアクセスしている場合に、彼らがブラスターを発射するために使うUIコンポーネントです。サンプルのレーザータグ体験では、クロスヘアとブラストのアイコンを組み合わせたブラストボタンを使用して、テキストなしでボタンの機能を伝えます。

サンプルの Laser Tag 体験の中でブラストボタンを正確に再現するには:
HUDGui ScreenGui オブジェクトに ImageButton を挿入します。
Explorer ウィンドウで、StarterGui サービスに移動します。
子の HUDGui オブジェクトにカーソルを合わせ、⊕ アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューから、ImageButton を挿入します。

ビューポート内で、プレイヤーの親指が自然に位置する場所にボタンを移動させ、プレイヤーのデバイスでボタンがどのように見えるかのビジュアル感覚を得ます。その後、Properties ウィンドウで、
- Image を rbxassetid://18308375035 に設定して、ブラストボタンアイコンを表示します。
- PressedImage を rbxassetid://18308372558 に設定して、プレイヤーがボタンを押したときにブラストボタンアイコンの反転バージョンを表示します。
- BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
- Name を BlastButton に設定します。
- ScaleType を Fit に設定して、画像がコンテナ内に収まり、さまざまな画面サイズで伸びないようにします。
- ImageTransparency を 0.3 に設定して、ラベルの不透明度を減少させ、体験内の全ての黒いUI要素と一致させます。
BlastButton に UIAspectRatioConstraint を挿入して、ボタンのアスペクト比がプレイヤーの画面サイズに関係なく同じになるようにします。
サンプル Laser Tag プレースファイル内の次の ReplicatedStorage スクリプトを参照して、プレイヤーがタッチ入力を使用してタッチコントロールを受け付けるデバイスで動作しているときに、ブラストボタンをプログラム的に表示します。
以下のスクリプトは、主なヘッズアップディスプレイ(HUD)を設定するために協力して動作する一連のモジュールスクリプトを必要とします。プレイヤーがラウンドに参加し、自分のブラスターを選択すると、このスクリプトはすべてのHUD UI要素がプレイヤーの状態、デバイス、およびチームの状態に合わせて適切に表示されるようにします。
local Players = game:GetService("Players")local setPlayerPortrait = require(script.setPlayerPortrait)local setPlayerName = require(script.setPlayerName)local startSyncingTeamColor = require(script.startSyncingTeamColor)local setObjective = require(script.setObjective)local setupTouchButtonAsync = require(script.setupTouchButtonAsync)local startSyncingTeamPoints = require(script.startSyncingTeamPoints)local disableMouseWhileGuiEnabled = require(script.disableMouseWhileGuiEnabled)local setupHitmarker = require(script.setupHitmarker)local localPlayer = Players.LocalPlayerlocal gui = localPlayer.PlayerGui:WaitForChild("HUDGui")setPlayerPortrait(gui)setPlayerName(gui)startSyncingTeamColor(gui)setObjective(gui)startSyncingTeamPoints(gui)disableMouseWhileGuiEnabled(gui)setupHitmarker(gui)setupTouchButtonAsync(gui)
プレイヤーUI
ワイヤーフレームでレイアウトを作成するからの視覚階層のベストプラクティスに従って、ここではプレイヤーの状態に関連するすべての画面上のUI要素を実装する方法を説明します。これらのUI要素のグループは画面の端近くに配置されています。なぜなら、プレイヤーはゲームプレイから注意をそらすことなく、この周辺情報を理解できるからです。

プレイヤーインジケーター
プレイヤーインジケーターは、プレイヤーがチームのスポーンゾーンにスポーンする際に、自身がどのチームに属しているかをすぐに判断できるようにするUIコンポーネントです。サンプルレーザータグ体験では、プレイヤーが 緑 チームまたは ピンク チームのいずれかにいる場合に応じて、2つのバージョンのプレイヤーインジケーターを提供します。


カラーテーマを選択するのガイダンスに従い、プレイヤーインジケーターの両バージョンは、チームカラーと一意の簡素アイコンを組み合わせています。これにより、小さな画面でも読みやすさが維持されます。2つの形式の視覚的フィードバックを提供することは、色盲のプレイヤーにとってデザインを見やすく保つために重要です。

サンプルの Laser Tag 体験内でプレイヤーインジケーターコンポーネントを正確に再現するには:
HUDGui ScreenGui オブジェクトに Frame を挿入します。
- Explorer ウィンドウで、StarterGui サービスに移動します。
- 子の HUDGui オブジェクトにカーソルを合わせ、⊕ アイコンをクリックします。コンテキストメニューが表示されます。
- コンテキストメニューから、Frame を挿入します。
新しい Frame を選択し、Properties ウィンドウで、
AnchorPoint を 0, 1 に設定して、フレームの起点を下中央に設定します(フレームの左から右まで0%、上から下まで100%)。
BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
Name を PlayerDisplay に設定します。
Position を {0.02, 0},{0.97, 0} に設定して、フレームを画面の左下近くに配置します。
Size を {0.23, 0},{0.08, 0} に設定して、フレームの長さを短くし、幅を広くします。
ClipsDescendants を有効にして、フレームを超えて拡張された子GuiObjectsをトリミングします。

多角形の形状を作成します。
PlayerDisplay に ImageLabel を挿入します。
新しいラベルを選択し、Properties ウィンドウで、
- Image を rbxassetid://14304828123 に設定して、台形アイコンを表示します。
- AnchorPoint を 1, 1 に設定して、ラベルの起点を右下に設定します(ラベルの左から右まで100%、上から下まで100%)。
- BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
- Name を Block に設定します。
- Position を {1,0},{1,0} に設定して、ラベルをフレームの右側に配置します。
- Size を {1.858, 0},{0.581, 0} に設定して、ラベルをフレームの外に広げ、フレームの長さのわずか半分以上に短くします。
- ImageTransparency を 0.15 に設定して、ラベルをわずかに透明にします。
- ScaleType を Fit に設定して、画像がそのコンテナ内に収まり、さまざまな画面サイズで伸びないようにします。

- Block に UIAspectRatioConstraint を挿入して、ラベルとその子UI要素のアスペクト比がプレイヤーの画面サイズに関係なく同じになるようにします。
- 新しい制約を選択し、Properties ウィンドウで AspectRatio を 13.78 に設定します。
プレイヤーのポートレート用のボックスを作成します。
PlayerDisplay に ImageLabel を挿入します。
新しいラベルを選択し、Properties ウィンドウで、
- Image プロパティ内のプレースホルダーの資産IDを削除します。ステップ7のスクリプトがプログラム的にプレイヤーのポートレートを画像ラベル内に挿入します。
- AnchorPoint を 0, 1 に設定して、ラベルの起点を左下に設定します(左から右まで0%、上から下まで100%)。
- BackgroundColor3 を 0, 0, 0 に設定して、ラベルの背景色を黒に設定します。
- BackgroundTransparency を 0.3 に設定して、ラベルの不透明度を30%減少させ、体験内の全ての黒いUI要素と一致させます。
- Name を PlayerPortrait に設定します。
- Position を {0.11, 0},{1, 0} に設定して、ラベルを多角形の左側に配置します。
- Size を {0.23, 0},{1, 0} に設定して、ラベルを小さくします。
- ImageTransparency を 0.15 に設定して、ラベルをわずかに透明にします。
- ScaleType を Fit に設定して、画像がそのコンテナ内に収まり、さまざまな画面サイズで伸びないようにします。

- PlayerPortrait に UIAspectRatioConstraint を挿入して、ラベルとその子UI要素のアスペクト比がプレイヤーの画面サイズに関係なく同じになるようにします。
- PlayerPortrait に UICorner を挿入し、Properties ウィンドウで CornerRadius を 0.05, 0 に設定して、角をわずかに丸めます。

プレイヤー名のためのテキストラベルを作成します。
PlayerDisplay に TextLabel オブジェクトを挿入します。
新しいラベルを選択し、Properties ウィンドウで、
- AnchorPoint を 0, 0.5 に設定して、新しいボタンの起点を左中央に設定します(左から右まで0%、上から下まで50%)。
- BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
- Name を PlayerNameTextLabel に設定します。
- Position を {0.35, 0},{0.72, 0} に設定して、ラベルをそのコンテナの右側に配置します(親ラベルの左から右まで35%、上から下まで72%)。
- Size を {0.52, 0},{0.3, 0} に設定して、テキストが多角形の形状エリアの大部分を占めるようにします(親フレームの横方向52%、縦方向30%)。
- FontFace を Montserrat に設定して、未来的な美的に合うようにします。
- Weight を Bold に設定して、フォントを太くします。
- Text プロパティ内のプレースホルダーのテキストを削除します。ステップ7のスクリプトがプログラム的にプレイヤーの名前をテキストラベルに挿入します。
- TextScaled を有効にします。
- TextXAlignment を Left に設定します。

プレイヤーのポートレートの左側に表示されるチームアイコンと色を作成します。
PlayerDisplay 内に Folder を挿入し、名前を TeamIcons に変更します。
緑 チームのアイコンと色を作成します。
- TeamIcons 内に ImageLabel を挿入します。
- 新しいラベルを選択し、Properties ウィンドウで、
- AnchorPoint を 0, 1 に設定して、ラベルの起点を左下に設定します(左から右まで0%、上から下まで100%)。
- BackgroundColor3 を 88, 218, 171 に設定して、ラベルの背景色をミントグリーンに設定します。
- Name を TeamAIcon に設定します。
- Position を {0, 0},{1, 0} に設定して、ラベルをフレームの左側に配置します。
- Size を {0.135, 0},{0.58, 0} に設定して、プレイヤーポートレートの左側にラベルを縮小します。
- ImageTransparency を 1 に設定して、ラベルを透明にします。

- このラベルが緑のチーム用であることを追跡するためのカスタム属性を構成します。このステップは、ステップ7のスクリプトにとって非常に重要です。
- Properties ウィンドウで、Attributes セクションに移動し、プラスアイコンをクリックします。ポップアップダイアログが表示されます。
- Name フィールドに teamColor と入力します。
- Type ドロップダウンメニューで BrickColor を選択します。
- Save ボタンをクリックします。
- 新しい teamColor 属性を Mint に設定します。
- TeamAIcon に UIAspectRatioConstraint を挿入して、ラベルとその子UI要素のアスペクト比がプレイヤーの画面サイズに関係なく同じになるようにします。
- アイコンを作成します。
- TeamAIcon に ImageLabel を挿入します。
- 新しいラベルを選択し、Properties ウィンドウで、
- Image を rbxassetid://14309678670 に設定して、緑チームのアイコンを表示します。
- AnchorPoint を 0.5, 0.5 に設定して、ラベルの起点を中央に設定します(左から右まで50%、上から下まで50%)。
- BackgroundTransparency を 1 に設定して、ラベルの背景を完全に透明にします。
- Name を Icon に設定します。
- Position を {0.5, 0},{0.5, 0} に設定して、ラベルをその親ラベルの中央に配置します。
- Size を {0.7, 0},{0.6, 0} に設定して、ラベルを縮小します。
- ScaleType を Fit に設定して、画像がそのコンテナ内に収まり、さまざまな画面サイズで伸びないようにします。

ピンク チームのアイコンと色を作成します。
- TeamAIcon とその子を複製します。
- 複製した TeamAIcon を選択し、Properties ウィンドウで、
- BackgroundColor3 を 255, 170, 255 に設定して、ラベルの背景色をカーネーションピンクに設定します。
- Name を TeamBIcon に設定します。
- teamColor 属性を Carnation Pink に設定します。
- 複製した TeamBIcon の子である Icon を選択し、Properties ウィンドウで Image を rbxassetid://14309678549 に設定して、ピンクチームのアイコンを表示します。

サンプル Laser Tag プレースファイル内の次の ReplicatedStorage スクリプトを参照して、プレイヤーがラウンド中にアクティブな状態で適切なチームカラーとアイコンを持つプレイヤーインジケーターをプログラム的に表示します。
以下のスクリプトは、主なヘッズアップディスプレイ(HUD)を設定するために協力して動作する一連のモジュールスクリプトを必要とします。プレイヤーがラウンドに参加し、ブラスターを選択すると、このスクリプトはすべてのHUD UI要素がプレイヤーの状態、デバイス、およびチームの状態に合わせて適切に表示されるようにします。
local Players = game:GetService("Players")local setPlayerPortrait = require(script.setPlayerPortrait)local setPlayerName = require(script.setPlayerName)local startSyncingTeamColor = require(script.startSyncingTeamColor)local setObjective = require(script.setObjective)local setupTouchButtonAsync = require(script.setupTouchButtonAsync)local startSyncingTeamPoints = require(script.startSyncingTeamPoints)local disableMouseWhileGuiEnabled = require(script.disableMouseWhileGuiEnabled)local setupHitmarker = require(script.setupHitmarker)local localPlayer = Players.LocalPlayerlocal gui = localPlayer.PlayerGui:WaitForChild("HUDGui")setPlayerPortrait(gui)setPlayerName(gui)startSyncingTeamColor(gui)setObjective(gui)startSyncingTeamPoints(gui)disableMouseWhileGuiEnabled(gui)setupHitmarker(gui)
フォースフィールドスクリーン
フォースフィールドスクリーンは、プレイヤーがラウンドに参加または再参加中に、敵チームの火から安全であることを知らせるためにビューポートにオーバーレイされるUI要素です。 アートスタイルを選択する のアイコンに関する美的ガイドラインに従って、サンプルのレーザータグ体験では、フォースフィールドを象徴するセミ透明な六角形パターンを利用しています。このデザイン決定は、体験内の全てのUIに対して全体的な未来的なアートスタイルを強化するだけでなく、プレイヤーの状態をテキストなしで伝達することにも貢献しています。

サンプルの Laser Tag 体験内でフォースフィールドスクリーンを正確に再現するには:1. ImageLabelをForceFieldGui ScreenGuiオブジェクトに挿入します。
Explorerウィンドウで、StarterGuiサービスに移動します。
その子のForceFieldGuiオブジェクトの上にカーソルを置き、**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューからImageLabelを挿入します。

新しいラベルを選択し、Propertiesウィンドウで、
Imageにrbxassetid://14462567888を設定します。
BackgroundTransparencyを0.8に設定して、フォースフィールドを半透明にします。
Sizeを{1, 0},{1, 0}に設定して、画像が親のScreenGui全体を占めるようにします(水平に100%、垂直に100%)。
ScaleTypeをTileに設定して、六角形が画面全体にタイル状になるようにします。
TileSizeを{0, 104},{0, 180}に設定します。

ラベルにUIGradientオブジェクトを挿入します。
新しいグラデーションオブジェクトを選択し、Propertiesウィンドウで、
Colorを青から白に変わり、再び青になるカラーシーケンスに設定します。
Colorを120, 192, 250に設定して、すべての六角形に淡い青色を適用します。
Colorプロパティをクリックし、**⋯**ボタンをクリックします。カラーシーケンスのポップアップが表示されます。

カラーシーケンスの下部軸の各三角形は、画像の左から右にそのポイントでのプロパティの色値を決定するキー・ポイントです。
カラーシーケンスをクリック&ドラッグしてTime値0.05に達するまで移動し、次にColorの隣にある小さな四角をクリックしてColorsポップアップウィンドウを開きます。
明るい白を選択し、ポップアップウィンドウを閉じます。
カラーシーケンスをクリック&ドラッグしてTime値0.95に達するまで移動し、再びColorsポップアップウィンドウを開き、前回と同じ白色を選択します。

Rotationを225に設定して、カラーシーケンスの青い部分を左上と右下隅に表示します。

Transparencyを、フォースフィールドが揺らめいているように見える数値シーケンスに設定します。
Transparencyプロパティをクリックし、**⋯**ボタンをクリックします。数値シーケンスのポップアップが表示されます。数値シーケンスの最初と最後にある各正方形は、画像のそのポイントでのプロパティの透明度値を決定するキー・ポイントです。
次の時間と値のプロパティを数値シーケンス全体で設定します:
- Time = 0, Value = 0.25
- Time = .101, Value = 0.875
- Time = .183, Value = 0
- Time = .3, Value = 1
- Time = .7, Value = 1
- Time = 1, Value = 0.9


ステップ2からImageLabelを複製します。
複製したラベル内のUIGradientオブジェクトを選択し、Propertiesウィンドウで、
Rotationを-45に設定して、画像を反転させてY軸に沿ってほぼ互いに鏡のように見えるようにします。

Transparencyを調整して、揺れがより自然に見えるようにします。
- Transparencyプロパティをクリックし、**⋯**ボタンをクリックします。数値シーケンスのポップアップが表示されます。
- 3番目のキー・フレームを選択し、Deleteボタンをクリックします。

サンプルLaser Tagプレースファイル内の次のReplicatedStorageスクリプトを参照し、プログラムでプレイヤーがラウンドに参加または再参加するときにフォースフィールド画面を表示します。
次のReplicatedStorage.ForceFieldClientVisualsクライアントスクリプトは、デフォルトのForceFieldビジュアルをStarterGui.ForceFieldGuiで置き換えます。プレイヤーがエクスペリエンスに入って、Durationプロパティが0より大きいSpawnLocationにスポーンすると、すべてのエクスペリエンスでデフォルトの動作は、自分のアバターに保護用の青いオーブを提供し、一時的に健康を失わないようにします。
このスクリプトは、ForceFieldがキャラクターに追加されるときにリスニングを開始し、デフォルトの一人称フォースフィールドビジュアルを無効にし、その後ForceFieldGui ScreenGuiオブジェクトを有効にします。この操作は、プレイヤーが他のプレイヤーがエクスペリエンスに復活するのを見るときの三人称ビジュアルには影響を与えません。


local Players = game:GetService("Players")
local localPlayer = Players.LocalPlayer
local function onCharacterAddedAsync(character: Model)
local forceField = character:WaitForChild("ForceField", 3)
if not forceField then
-- プレイヤーがフォースフィールドが無効になっているスポーンポイントでスポーンした場合
return
end
forceField.Visible = false
localPlayer.PlayerGui:WaitForChild("ForceFieldGui").Enabled = true
forceField.Destroying:Wait()
localPlayer.PlayerGui.ForceFieldGui.Enabled = false
end
if localPlayer.Character then
onCharacterAddedAsync(localPlayer.Character)
end
localPlayer.CharacterAdded:Connect(onCharacterAddedAsync)
リスポーン画面
リスポーン画面は、プレイヤーが抜けたことを通知するためにビューを暗くし、サーバーがスポーンゾーンに戻る処理を行っていることを通知するUI要素です。このUI要素は、プレイヤーが自分が削除されたことを処理し、アクティブなラウンドに再参加する前に次の動きを戦略的に考える時間を与えるために重要です。
サンプルレーザータグ体験におけるカスタムリスポーン動作の詳細については、ゲームプレイスクリプトのカリキュラムからキャラクターをリスポーンするを参照してください。

サンプルLaser Tag体験内でリスポーン画面を正確に再現するには:
センター情報バナーを作成します。
OutStateGui ScreenGuiオブジェクトにImageLabelを挿入します。
Explorerウィンドウで、StarterGuiサービスに移動します。
その子のOutStateGuiオブジェクトの上にカーソルを置き、**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューからImageLabelを挿入します。

新しいラベルを選択し、Propertiesウィンドウで、
AnchorPointを0.5, 0.5に設定して、新しいボタンの原点を中央に設定します(ラベルの左から右に50%、上から下に50%)。
BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをそのコンテナの中央に配置します(親のScreenGuiの左から右に50%、上から下に50%)。
Sizeを{0.48, 0},{0.06, 0}に設定して、ラベルを広げます(親のScreenGuiの水平に48%、垂直に6%)。
NameをBlockに設定します。
Imageをrbxassetid://14304827265に設定して、画像を trapezoid(台形)にします。
ImageColorを0,0,0に設定して、台形を黒にします。
ImageTransparencyを0.3に設定して、ラベルの不透明度を30%減らし、体験内のすべての黒いUI要素に合わせます。

BlockにUIAspectRatioConstraintを挿入して、ラベルとその子のUI要素のアスペクト比がプレイヤーの画面サイズに関係なく同じままであることを保証します。
新しい制約を選択し、PropertiesウィンドウでAspectRatioを13.78に設定します。
BlockにTextLabelを挿入して、情報テキストを表示します。
新しいラベルを選択し、Propertiesウィンドウで、
AnchorPointを0.5, 0.5に設定して、ラベルの原点を中央に設定します(ラベルの左から右に50%、上から下に50%)。
BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをその親ラベルの中央に配置します(親ラベルの左から右に50%、上から下に50%)。
Sizeを{.85, 0},{0.55, 0}に設定して、テキストが台形の面積のほとんどを占められるようにします(親ラベルの水平に85%、垂直に55%)。
NameをBodyTextLabelに設定します。
FontFaceをMontserratに設定して、未来的な美学に合うようにします。
WeightをBoldに設定して、フォントを太くします。
Textを**Respawning…**に設定します。
TextColor3を255, 255, 255に設定して、テキストを白にします。
TextScaledを有効にします。

ヘッダーを作成します。
BlockにImageLabelを挿入します。
新しいラベルを選択し、Propertiesウィンドウで、
AnchorPointを0.5, 1に設定して、ラベルの原点を自分の下-中心に設定します(ラベルの左から右に50%、上から下に100%)。
BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
Positionを{0.5, 0},{0, 0}に設定して、ラベルをその親ラベルの上-真ん中に配置します(親ラベルの左から右に50%、上から下に0%)。
Sizeを{0.46, 0},{0.56, 0}に設定して、ラベルを広げます(親ラベルの水平に46%、垂直に56%)。
NameをHeaderに設定します。
Imageをrbxassetid://14304826985に設定して、画像を多方向のフェードにします。
ImageColorを245, 46, 46に設定して、フェードを赤にし、プレイヤーがラウンドから一時的に非アクティブであることを示します。

HeaderにTextLabelを挿入して、情報テキストを表示します。
新しいラベルを選択し、Propertiesウィンドウで、
AnchorPointを0.5, 0.5に設定して、ラベルの原点を中央に設定します(ラベルの左から右に50%、上から下に50%)。
BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをその親ラベルの中央に配置します(親ラベルの左から右に50%、上から下に50%)。
Sizeを{.85, 0},{0.55, 0}に設定して、テキストがフェード面積のほとんどを占められるようにします(親ラベルの水平に85%、垂直に55%)。
NameをHeaderTextLabelに設定します。
FontFaceをMontserratに設定して、未来的な美学に合うようにします。
WeightをBlackに設定して、フォントを太くします。
Textを**TAGGED - YOU'RE OUT!**に設定します。
TextColor3を255, 255, 255に設定して、テキストを白にします。
TextScaledを有効にします。

画面の境界にフェードを作成します。
- OutStateGuiにImageLabelを挿入します。
- 新しいラベルを選択し、Propertiesウィンドウで、
- AnchorPointを0.5, 0.5に設定して、ラベルの原点を中央に設定します(ラベルの左から右に50%、上から下に50%)。
- BackgroundColor3を0,0,0に設定して、ラベルの背景色を黒にします。
- BackgroundTransparencyを0.5に設定して、ラベルの背景を半透明にします。
- Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをそのコンテナの中央に配置します(親のScreenGuiの左から右に50%、上から下に50%)。
- Sizeを{1, 0},{1, 0}に設定して、ラベルを全画面に広げます(親ScreenGuiの水平に100%、垂直に100%)。
- ZIndexを-1に設定して、フェードが他のUI要素の後ろに表示されるようにします。
- NameをHeaderに設定します。
- Imageをrbxassetid://14309518613に設定して、画像を境界フェードにします。
- ImageTransparencyを0.1に設定して、フェードをわずかに半透明にします。
サンプルLaser Tagプレースファイル内の次のReplicatedStorageスクリプトを参照し、プレイヤーの健康がゼロに達し、彼らが自分のチームのスポーンゾーンに戻るプロセス中にリスポーン画面をプログラムで表示します。
次のReplicatedStorage.PlayerStateHandlerクライアントスクリプトには、playerState属性に応じて異なるタイプの動作をトリガーする関数が含まれています。すべてのイベント応答は、プレイヤーのコントロール、カメラの動き、どのUIレイヤーが表示されるかを有効または無効にする必要があるため、論理的にこのスクリプトにグループ化されています。
プレイヤーの健康がゼロに達すると、playerStateがTaggedOutになり、onTaggedOut()関数がトリガーされます。onTaggedOut()は、次の動作を即座にトリガーします:
- プレイヤーはアリーナ内で動けなくなります。
- プレイヤーはカメラを動かせなくなります。
- プレイヤーはブラスターを使用できなくなります。
- StarterGui.OutStateGuiが排他的に有効になります。
プレイヤーがリスポーンした際には、playerStateがSelectingBlasterとなり、onSelectingBlaster()関数がトリガーされます。onSelectingBlaster()は、次にStarterGui.PickABlasterGuiを排他的に有効にし、リスポーン画面を自動的に無効にします。これらの条件の詳細については、クライアント状態を処理するを参照してください。
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local PlayerState = require(ReplicatedStorage.PlayerState)
local PlayerAttribute = require(ReplicatedStorage.PlayerAttribute)
local BlasterState = require(ReplicatedStorage.Blaster.BlasterState)
local togglePlayerMovement = require(script.togglePlayerMovement)
local togglePlayerCamera = require(script.togglePlayerCamera)
local scheduleDestroyForceField = require(ReplicatedStorage.scheduleDestroyForceField)
local localPlayer = Players.LocalPlayer
local playerGui = localPlayer.PlayerGui
local guiLayers = {
playerGui:WaitForChild("HUDGui"),
playerGui:WaitForChild("OutStateGui"),
playerGui:WaitForChild("PickABlasterGui"),
}
-- 除外された例外を除いてすべてのUIレイヤーを無効にする
local function setGuiExclusivelyEnabled(enabledGui: ScreenGui?)
-- guiLayersは独占的に設定されるべきguiのリストを含んでいます。
for _, screenGui in guiLayers do
screenGui.Enabled = screenGui == enabledGui
end
end
local function onSelectingBlaster()
-- プレイヤーがブラスターを選びながらカメラが見れるようにします
togglePlayerCamera(true)
togglePlayerMovement(false)
setGuiExclusivelyEnabled(playerGui.PickABlasterGui)
-- ブラスター選択中はブラスターを無効にします
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
local function onPlaying()
-- ブラスター選択後はプレイヤーの動きを有効にします
togglePlayerMovement(true)
setGuiExclusivelyEnabled(playerGui.HUDGui)
-- プレイ中はブラスターを有効にします
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Ready)
-- プレイヤーがプレイを始めたときにフォースフィールドを破壊するロジックをスケジュールします
scheduleDestroyForceField()
end
local function onTaggedOut()
-- タグ付けされたときはコントロールを無効にします
togglePlayerMovement(false)
togglePlayerCamera(false)
setGuiExclusivelyEnabled(playerGui.OutStateGui)
-- タグ付けされたときはブラスターを無効にします
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
local function onInLobby()
-- ロビーにいる間はコントロールを有効にします
togglePlayerMovement(true)
togglePlayerCamera(true)
-- ロビーにいる間はすべてのHUDを隠します
setGuiExclusivelyEnabled(nil)
-- ロビーにいる間はブラスターを無効にします
localPlayer:SetAttribute(PlayerAttribute.blasterStateClient, BlasterState.Disabled)
end
local function onPlayerStateChanged(newPlayerState: string)
if newPlayerState == PlayerState.SelectingBlaster then
onSelectingBlaster()
elseif newPlayerState == PlayerState.Playing then
onPlaying()
elseif newPlayerState == PlayerState.TaggedOut then
onTaggedOut()
elseif newPlayerState == PlayerState.InLobby then
onInLobby()
else
warn(`無効なプレイヤー状態 ({newPlayerState})`)
end
end
-- もし初期プレイヤー状態が設定されていれば、それを処理します
local initialPlayerState = localPlayer:GetAttribute(PlayerAttribute.playerState)
onPlayerStateChanged(initialPlayerState)
local function updateFromPlayerState()
onPlayerStateChanged(localPlayer:GetAttribute(PlayerAttribute.playerState))
end
-- 将来のプレイヤー状態の更新を処理します
localPlayer:GetAttributeChangedSignal(PlayerAttribute.playerState):Connect(updateFromPlayerState)
-- リスポーン後に変更が依然として適用されることを確認します
localPlayer.CharacterAdded:Connect(updateFromPlayerState)
SurfaceGuiオブジェクトを作成する
3D空間の部品の表面にUIを表示し、各プレイヤーのスクリプト論理に応じた反応を示すには、UIを表示したい部品にSurfaceGuiオブジェクトを親として設定できます。この技術により、UIとそのスクリプト論理がサーバーと各プレイヤーのクライアント両方で利用可能になります。
SurfaceGuiオブジェクトには、3D空間の部品の表面に表示されるすべてのGuiObjectsが含まれています。サンプルのレーザータグ体験には、各プレイヤーのブラスターの上に表示されるクールダウンメーターとしての一つのSurfaceGuiオブジェクトのみが含まれています。このオブジェクトには、各プレイヤーの入力に応じて反応し、ブラスターを再発射できるタイミングの視覚的フィードバックを提供するために、各プレイヤーに必要なスクリプト論理が必要です。
SurfaceGuiオブジェクトを作成するには:
- Explorerウィンドウで、ReplicatedStorageサービスの上にカーソルを置き、**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
- コンテキストメニューからPartオブジェクトを挿入します。
- パート内にScreenGuiオブジェクトを挿入します。
- 子のUI要素の文脈に応じてSurfaceGuiの名前を変更します。
- 3D空間内で表示するすべてのUI要素に対してこのプロセスを繰り返します。

クールダウンメーター
クールダウンメーターは、プレイヤーが次にブラスターを発射できるまで待たなければならない時間を通知するUIコンポーネントです。このわずかな間隔により、プレイヤーがクリックやボタンを押すだけで発射できる速さでブラスターを発射できないように制御され、レーザータグのゲームプレイにおいて現実的ではありません。
サンプルのLaser Tag体験内でクールダウンメーターを正確に再現するには:
SurfaceGuiオブジェクトを保持する部分を作成します。
- Explorerウィンドウで、Workspaceの上にカーソルを置き、⊕アイコンをクリックします。コンテキストメニューが表示されます。
- コンテキストメニューからblock部分を挿入します。この部分は、プロセスの各ステップで変更を視覚化できるようにする一時的な場所です。
部分をプレイヤーのキャラクターがブラスターを持つ位置に合わせて配置および向きを整え、次にPropertiesウィンドウで、
Transparencyを1に設定して、パートを完全に透明にします。
NameをCooldownBarPrefabに設定します。
Sizeを0.169, 0.027, 2.537に設定して、ブラスターの長さに近いサイズにスケールします。
CanCollideとCanQueryを無効にします。

CooldownBarPrefabにSurfaceGuiを挿入します。
新しいSurfaceGuiを選択し、Propertiesウィンドウで、
FaceをTopに設定して、UIが上向きに表示されるようにします。
LightInfluenceとMaxDistanceを0に設定します。
PixelsPerStudを200に設定します。

黒いバーを作成します。
SurfaceGui内にImageLabelを挿入します。
新しいラベルを選択し、Propertiesウィンドウで、
- デフォルトのImage値を削除します。
- AnchorPointを0.5, 0.5に設定して、ラベルの原点を中央に設定します(ラベルの左から右に50%、上から下に50%)。
- BackgroundColor3を0,0,0に設定して、背景色を黒に設定します。
- BackgroundTransparencyを0.4に設定して、ラベルの背景を半透明にします。
- Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをそのコンテナの中央に配置します(親のSurfaceGuiの左から右に50%、上から下に50%)。
- Sizeを{1, 0},{1, 0}に設定して、ラベルをそのパート全体に広げます(親SurfaceGuiの水平に100%、垂直に100%)。
- NameをContainerに設定します。

コンテナの角を丸めます。
ContainerにUICornerオブジェクトを挿入します。
UICornerを選択し、PropertiesウィンドウでCornerRadiusを0.15, 0に設定して角をわずかに丸めます。

赤いバーを作成します。
- ContainerにImageLabelを挿入します。
- 新しいラベルを選択し、Propertiesウィンドウで、
- デフォルトのImage値を削除します。
- AnchorPointを1, 0.5に設定して、ラベルの原点を右の中央に設定します(ラベルの左から右に100%、上から下に50%)。
- BackgroundColor3を172, 13, 13に設定して、背景色を濃い赤に設定します。
- BackgroundTransparencyを0.2に設定して、ラベルの背景をわずかに透明にします。
- NameをBarに設定します。
- Positionを{1, 0},{0.5, 0}に設定して、ラベルをその親のラベルの右の中央に配置します(親ラベルの左から右に100%、上から下に50%)。
- Sizeを{0, 0},{1, 0}に設定して、ラベルをその親ラベルの上端に伸ばします(親ラベルの幅の0%、高さの100%)。このステップは、ステップ8のスクリプトで発生するツイーン動作にも利益をもたらします。
ラベルの角を丸めます。
- BarにUICornerオブジェクトを挿入します。
- UICornerを選択し、PropertiesウィンドウでCornerRadiusを0.15, 0に設定して角をわずかに丸めます。
CooldownBarPrefabをReplicatedStorageに移動します。
UIオブジェクトを整理するためのフォルダ構造を作成します。サンプルでは、Instancesフォルダ内にGuisフォルダを使用しています。

CooldownBarPrefabをGuisに移動します。
サンプルLaser Tagプレースファイル内の次のReplicatedStorageスクリプトを参照し、プレイヤーのブラスターにクールダウンメーターをプログラムで取り付け、その後プレイヤーがブラスターを発射したときに赤いバーをアニメートします。
次のReplicatedStorage.FirstPersonBlasterVisualsクライアントスクリプトは、プレイヤーの一人称ブラスターのすべての視覚論理を処理します。これは、レーザータグのゲームプレイにとってよりリアルに感じられるブラスターの視覚をセットアップするために協力するモジュールスクリプトのセットを必要とします。
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local BlastData = require(ReplicatedStorage.Blaster.BlastData)
local PlayerAttribute = require(ReplicatedStorage.PlayerAttribute)
local PlayerState = require(ReplicatedStorage.PlayerState)
local getBlasterConfig = require(ReplicatedStorage.Blaster.getBlasterConfig)
local runBlastVisuals = require(script.runBlastVisuals)
local setupAnimations = require(script.setupAnimations)
local addCooldownBar = require(script.addCooldownBar)
local runCooldownBarEffect = require(script.runCooldownBarEffect)
local laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEvent
local RIG_OFFSET_FROM_CAMERA = CFrame.new(2, -2, -3) * CFrame.Angles(math.rad(0.25), math.rad(95.25), 0)
local localPlayer = Players.LocalPlayer
local currentCamera = Workspace.CurrentCamera
local rigModel = nil
local cooldownBar = nil
local animations = {}
local function addFirstPersonVisuals()
local blasterConfig = getBlasterConfig()
-- 一人称用のリグを追加
rigModel = blasterConfig.RigModel:Clone()
rigModel.Parent = Workspace
-- クールダウンバーを追加
cooldownBar = addCooldownBar(rigModel.PrimaryPart.CooldownBarAttachment)
animations = setupAnimations(blasterConfig, rigModel)
end
local function removeFirstPersonVisuals()
for _, animation in animations do
animation:Stop()
animation:Destroy()
animation = nil
end
if rigModel then
-- リグに親付けされているため、クールダウンバーも削除されます
rigModel:Destroy()
rigModel = nil
end
end
-- ブラスターが発射されるときに一人称の視覚効果を実行します
laserBlastedBindableEvent.Event:Connect(function(blastData: BlastData.Type)
runBlastVisuals(rigModel.PrimaryPart.TipAttachment, blastData, animations.blastAnimation)
runCooldownBarEffect(cooldownBar)
end)
-- 存在する場合はカメラにリグをバインドします
RunService.RenderStepped:Connect(function()
if rigModel then
-- カメラの位置とRIG_OFFSET_FROM_CAMERAに基づいてリグのCFrameを更新します
rigModel:PivotTo(currentCamera.CFrame * RIG_OFFSET_FROM_CAMERA)
end
end)
-- プレイ中にブラスタータイプが変更されるときに視覚を変更します
localPlayer:GetAttributeChangedSignal(PlayerAttribute.blasterType):Connect(function()
local playerState = localPlayer:GetAttribute(PlayerAttribute.playerState)
if playerState == PlayerState.Playing then
removeFirstPersonVisuals()
addFirstPersonVisuals()
end
end)
-- プレイヤー状態が変更されるときに視覚を変更します
localPlayer:GetAttributeChangedSignal(PlayerAttribute.playerState):Connect(function()
local newPlayerState = localPlayer:GetAttribute(PlayerAttribute.playerState)
-- プレイヤーがブラスターを選択しているとき、またはロビーにいるときは視覚を削除します
if newPlayerState == PlayerState.SelectingBlaster or newPlayerState == PlayerState.InLobby then
removeFirstPersonVisuals()
-- プレイヤーがブラスター選択を完了したときは視覚を再び追加します
elseif newPlayerState == PlayerState.Playing then
addFirstPersonVisuals()
end
end)
BillboardGuiオブジェクトを作成する
3D空間内で、スクリプト論理が反応し、各プレイヤーのカメラに常に向くように、たとえばプレイヤーの名前やマップマーカーなどのUI要素を表示するには、BillboardGuiオブジェクトをBasePartまたはAttachmentの子として作成できます。これは3D空間に存在します。
サンプルレーザータグ体験には、ReplicatedStorageサービス内に二つの異なるBillboardGuiオブジェクトが含まれています:
- OtherPlayerIndicatorGuiPrefab - ラウンドでアクティブな各プレイヤーの頭上にピンクまたは緑の円を表示します。
- TaggedOutIndicatorGuiPrefab - ラウンドから離脱したときにプレイヤーの頭上に表示されます。
BillboardGuiオブジェクトを作成した後、その子GuiObjectsを各コンテナの目的に応じて作成およびカスタマイズできます。今後のセクションでは、サンプルのレーザータグ体験内で両方のインジケータータイプのUI要素を実装する方法を学びます。プロセスの任意の部分を、自分の体験の仕様に合わせて調整できます。
BillboardGuiオブジェクトを作成するには:
- コンテキストメニューからBillboardGuiオブジェクトを挿入します。
- BillboardGuiをその子のUI要素の文脈に応じて名前を変更します。
- プレイヤーの頭上に文脈的に表示する必要があるすべてのUI要素に対してこのプロセスを繰り返します。
チームインジケーター
チームインジケーターは、ラウンド内の他のプレイヤーが属するチームをプレイヤーに通知するUI要素であり、味方と敵のチームメンバーを簡単に区別できるようにします。この情報は、ファーストパーソンシューティングゲームのゲームプレイにおいてプレイヤーが戦闘ゾーン内で迅速な戦略的意思決定を行うことを必要とするため、重要です。そうすれば、プレイヤーはタグ付けされて試合に負けないように次のターゲットにすぐに移動できます。

サンプルLaser Tag体験内でチームインジケーターを正確に再現するには:
一時的なリグにBillboardGuiオブジェクトを挿入します。
ツールバーのHomeまたはAvatarタブからCharacterをクリックします。
利用可能なオプションから選択します。サンプルでは、R15リグタイプ、女性ボディシェイプ、そしてRthroアバターを使用しています。リグは3DビューポートおよびExplorerウィンドウ内に「Rig」という名前で表示されます。
Explorerウィンドウで、リグの子であるHeadメッシュに移動し、**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューからBillboardGuiを挿入します。

新しいBillboardGuiを選択し、Propertiesウィンドウで、
LightInfluenceを0に設定して、環境光がインジケーターの色に影響を与えないようにします。
NameをOtherPlayerIndicatorPrefabに設定します。
Sizeを{0, 10},{0, 10}に設定して、ラベルをかなり小さくします。
StudsOffsetWorldSpaceを0, 4, 0に設定して、リグの頭上に配置します。

OtherPlayerIndicatorPrefabにFrameオブジェクトを挿入します。
新しいフレームを選択し、Propertiesウィンドウで、
AnchorPointを0.5, 0.5に設定して、フレームの原点を中央に設定します(フレームの左から右に50%、上から下に50%)。
BackgroundColor3を255, 3, 0に設定して、フレームの背景色を赤(プレースホルダー色)に設定します。
Positionを{0.5, 0},{0.5, 0}に設定して、フレームをそのコンテナの中央に配置します(親BillboardGuiの左から右に50%、上から下に50%)。
Sizeを{1, -2},{1, -2}に設定して、フレームをBillboardGuiの表面積に短縮します。

フレーム内にUICornerオブジェクトを挿入して、角を完全に丸めます。

フレーム内にUIStrokeオブジェクトを挿入し、インジケーターの円をアウトラインします。

OtherPlayerIndicatorPrefabをReplicatedStorageに移動します。
サンプルLaser Tag 1Aプレースファイル内の次のReplicatedStorageスクリプトを参照し、アクティブなラウンドに参加している各プレイヤーにチームインジケーターを表示します。ただし、敵チームに属していて遮られている場合は表示されません。
次のReplicatedStorage.OtherPlayerIndicatorGuiSetupスクリプトは、プレイヤーがアクティブラウンドのアリーナにスポーンするときに実行されます。これは、addIndicatorToCharacter()関数を呼び出すことによって、ラウンドに参加している各プレイヤーキャラクターのHeadオブジェクトを見つけます。プレイヤーがすでにチームインジケーターを持っていない場合は、スクリプトがotherPlayerIndicatorPrefab UIをクローンしてキャラクターのHeadに追加し、チームインジケーターの色をそのチームの色に設定します。
他のプレイヤーが同じチームに属している場合、インジケーターは常に表示されます。3D空間内に遮るものがなければ、敵チームに属している他のプレイヤーもインジケーターが表示されます。
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local localPlayer = Players.LocalPlayer
local otherPlayerIndicatorPrefab = ReplicatedStorage.Instances.Guis.OtherPlayerIndicatorPrefab
local characterSpawnConnectionsByPlayer: { [Player]: RBXScriptConnection } = {}
local playerAddedConnection: RBXScriptConnection?
local function removeIndicatorFromPlayer(player: Player)
if not player.Character then
return
end
local head = player.Character:WaitForChild("Head", 3)
if not head then
return
end
local gui = head:FindFirstChild(otherPlayerIndicatorPrefab.Name)
if gui then
gui:Destroy()
end
end
local function addIndicatorToCharacter(otherCharacter: Model?)
local otherPlayer = Players:GetPlayerFromCharacter(otherCharacter)
if not otherPlayer then
return
end
task.spawn(function()
local otherHead = otherCharacter:WaitForChild("Head", 3)
if not otherHead then
return
end
-- ラウンドに参加しているプレイヤーに対してのみインジケーターを追加
if not otherPlayer.Team then
return
end
-- 重複したインジケーターの追加を避け、新しいものを存在しない場合にのみ作成
local gui = otherHead:FindFirstChild(otherPlayerIndicatorPrefab.Name)
if not gui then
gui = otherPlayerIndicatorPrefab:Clone()
gui.Frame.BackgroundColor3 = otherPlayer.TeamColor.Color
gui.Parent = otherHead
end
-- プレイヤーが味方の場合、インジケーターが常に上に表示されます
local isFriendly = otherPlayer.Team == localPlayer.Team
gui.AlwaysOnTop = isFriendly
end)
end
local function addIndicatorWhenCharacterSpawns(player: Player)
if characterSpawnConnectionsByPlayer[player] then
return
end
local connection = player.CharacterAdded:Connect(addIndicatorToCharacter)
characterSpawnConnectionsByPlayer[player] = connection
end
local function stopSyncingIndicators()
for _, connection in characterSpawnConnectionsByPlayer do
connection:Disconnect()
end
table.clear(characterSpawnConnectionsByPlayer)
if playerAddedConnection then
playerAddedConnection:Disconnect()
playerAddedConnection = nil
end
for _, player in Players:GetPlayers() do
removeIndicatorFromPlayer(player)
end
end
local function addIndicatorToPlayer(player: Player)
if player == localPlayer then
return
end
addIndicatorToCharacter(player.Character)
addIndicatorWhenCharacterSpawns(player)
end
local function startSyncingIndicators()
for _, player in Players:GetPlayers() do
addIndicatorToPlayer(player)
end
if not playerAddedConnection then
playerAddedConnection = Players.PlayerAdded:Connect(addIndicatorToPlayer)
end
end
local function onLocalTeamChanged()
local localTeam = localPlayer.Team
if localTeam then
startSyncingIndicators()
else
stopSyncingIndicators()
end
end
localPlayer:GetPropertyChangedSignal("Team"):Connect(onLocalTeamChanged)
onLocalTeamChanged()
タグ付けされたインジケーター
タグ付けされたインジケーターは、他のプレイヤーがラウンドで非アクティブになり、自分たちのスポーンゾーンに戻るプロセス中であることをプレイヤーに通知するUI要素です。この情報は、ファーストパーソンシューティングゲームのゲームプレイにおいて、プレイヤーが次のターゲットに移動しなければならないため、重要です。そうしなければ、長時間同じ場所でプレイすることで自分が脆弱になることができます。

サンプルLaser Tag体験内でタグ付けされたインジケーターを正確に再現するには:
一時的なリグにBillboardGuiオブジェクトを挿入して、プロセスの各ステップで変更を視覚化します。
ツールバーのHomeまたはAvatarタブからCharacterをクリックします。
利用可能なオプションから選択します。サンプルでは、R15リグタイプ、男性ボディシェイプ、そしてRthroアバターを使用しています。リグは3DビューポートおよびExplorerウィンドウ内に「Rig」という名前で表示されます。
Explorerウィンドウで、リグの子であるHeadメッシュに移動し、**⊕**アイコンをクリックします。コンテキストメニューが表示されます。
コンテキストメニューからBillboardGuiを挿入します。

新しいBillboardGuiを選択し、Propertiesウィンドウで、
LightInfluenceを0に設定して、環境光がインジケーターの色に影響を与えないようにします。
NameをTaggedOutIndicatorGuiPrefabに設定します。
Sizeを{3, 0},{0.5, 0}に設定して、ラベルのためのスペースを広げます。
StudsOffsetを0, 3.25, 0に設定して、プレイヤーの頭上に設定します。
1. TaggedOutIndicatorGuiPrefabにImageLabelオブジェクトを挿入します。
新しいラベルを選択し、プロパティウィンドウで、
- AnchorPointを0.5, 0.5に設定して、ラベルの原点をラベルの中央に設定します(ラベルの左から右までの50%、上から下までの50%)。
- BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
- NameをFrameに設定します。
- Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをそのコンテナの中央に配置します(親のBillboardGuiの左から右までの50%、上から下までの50%)。
- Sizeを{1, 0},{1, 0}に設定して、ラベルを全体のBillboardGuiに広げます(親のBillboardGuiの水平方向に100%、垂直方向に100%)。
- Imageをrbxassetid://14304826985に設定して、画像を多方向のフェードにします。
- ImageColorを245, 46, 46に設定して、ラベルを赤く色付けします。

FrameにTextLabelオブジェクトを挿入します。
新しいラベルを選択し、プロパティウィンドウで、
AnchorPointを0.5, 0.5に設定して、ラベルの原点をラベルの中央に設定します(ラベルの左から右までの50%、上から下までの50%)。
BackgroundTransparencyを1に設定して、ラベルの背景を完全に透明にします。
NameをBodyTextLabelに設定します。
Positionを{0.5, 0},{0.5, 0}に設定して、ラベルをそのコンテナの中央に配置します(親のラベルの左から右までの50%、上から下までの50%)。
Sizeを{0.85, 0},{0.7, 0}に設定して、テキストがフェードエリアのほとんどを占めるようにします(親の画像ラベルの水平方向に85%、垂直方向に70%)。
FontFaceをMontserratに設定して、未来的な美学を適合させます。
WeightをBoldに設定して、フォントを太くします。
TextをTAGGEDに設定します。
TextColor3を255, 255, 255に設定して、テキストを白色にします。
TextScaledを有効にします。

TaggedOutIndicatorGuiPrefabをReplicatedStorageに移動します。
サンプルLaser Tag 1Aプレイスファイル内の以下のServerScriptServiceスクリプトを参照し、プレイヤーがチームのスポーンゾーンにリスポーンしている間、タグ付けされているインジケーターをプログラムで表示します。
次のServerScriptService.SetupHumanoidサーバースクリプトは、プレイヤーが体験をロードするとすぐに実行されます。これにより、プレイヤーのキャラクターがデータモデルに追加されるたびに、setupHumanoidAsyncがそのHumanoidで呼び出されます。
local Players = game:GetService("Players")
local setupHumanoidAsync = require(script.setupHumanoidAsync)
local function onCharacterAdded(player: Player, character: Model)
local humanoid = character:WaitForChild("Humanoid")
setupHumanoidAsync(player, humanoid)
end
local function onPlayerAdded(player: Player)
-- プレイヤーが既にキャラクターを持っている場合はonCharacterAddedを呼び出す
if player.Character then
onCharacterAdded(player, player.Character)
end
-- このプレイヤーの将来のキャラクタースポーンのためにonCharacterAddedを呼び出す
player.CharacterAdded:Connect(function(character: Model)
onCharacterAdded(player, character)
end)
end
-- ゲームに既にいるプレイヤーにはonPlayerAddedを呼び出す
for _, player in Players:GetPlayers() do
onPlayerAdded(player)
end
-- 将来のすべてのプレイヤーにはonPlayerAddedを呼び出す
Players.PlayerAdded:Connect(onPlayerAdded)
ユーザーインターフェイスデザインカリキュラムの完了おめでとうございます!アートスタイルを作成し、レイアウトをワイヤーフレーム化し、スタジオでデザインを始めから終わりまで実装する経験を得たので、プロジェクトを新しいUIや機能で拡張したり、サンプルレーザータグ体験の一般的な整理と重要な実装の詳細について学ぶGameplay Scripting Curriculumなどの追加のチュートリアルカリキュラムに従うことができます。楽しい制作を!