實現您的設計 是在 Studio 中使用內建和自定義 UI 元件以及可根據上下文觸發的腳本來創建線框的過程。這個教程的這個令人興奮的步驟是您可以看到所有設計和努力結合在一起,形成一組完整且準備好讓玩家互動的工作流程。
使用 範例雷射標籤體驗 .rbxl 文件作為參考,這部分的用戶界面設計課程將向您展示如何使您的 UI 計劃變為現實,包括以下指導:
- 從 UI 資產庫中檢索資產 ID,以便能夠重建範例雷射標籤體驗的 UI 元件。
- 在 Studio 中模擬各種設備,查看您的 UI 在不同屏幕和長寬比下的顯示情況。
在您回顧本節的技術後,您可以將其應用於自己的項目,以製作令人興奮的 UI 元件,幫助玩家在您的體驗中導航。
獲取資產庫
資產庫是您可以添加到您的庫存中以便輕鬆訪問和重用的資產集合。您將在 創作者商店 中為您的項目使用的資產庫包括九個 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
要從您的庫存中將資產庫添加到您的體驗中:
將資產庫添加到您的庫存。
- 瀏覽到創作者商店的資產庫的 詳細頁面。
- 在右上角,單擊 獲取模型 按鈕。該資產庫現在在您的庫存中,您可以在平台上的任何項目中重用這些資產。
在 Studio 中,導航到 主頁 標籤,然後單擊 工具箱 按鈕。工具箱 窗口打開。

在 工具箱 窗口中,單擊 庫存 標籤。顯示 我的模型 排序。

單擊下拉菜單,然後選擇 我的包 排序。
單擊 最終屏幕 UI 元件 瓦片,然後在 Explorer 窗口中選擇 完成的元件,然後將它們拖到 StarterGui 服務中。您現在可以啟用任何最終元件以引用其設計。
模擬設備
Studio 的 設備模擬器 允許您測試玩家將如何在各種設備上查看和互動您的 UI。此工具是實施過程的重要組成部分,因為您在 Studio 中的視口的長寬比未必反映玩家使用的設備的長寬比,因此您的 UI 在每個設備上都必須既易讀又易用。
例如,如果您不在各種屏幕尺寸上測試您的 UI,擁有大型屏幕的玩家可能無法閱讀您的文本或解釋您的圖標,而擁有小屏幕的玩家可能無法看到 3D 空間,因為您的 UI 元件佔用了顯示器的過多空間。
要在各種屏幕尺寸上模擬您的 UI:
在 Studio 的 測試 菜單中,切換打開 設備模擬器。
在解析度下拉菜單中,選擇 實際解析度。這樣您就可以看到您要模擬的設備上 UI 元件的真實解析度。

在設備下拉菜單中,選擇至少一個設備,位於 電話、平板電腦、桌面 和 控制台 部分。

創建 ScreenGui 物件
要在每個玩家的屏幕上顯示 UI 元件,您可以在 StarterGui 服務中創建 ScreenGui 物件。ScreenGui 物件是屏幕上 UI 的主要容器,並且 StarterGui 服務在玩家進入體驗時會將其內容複製到每個玩家的 PlayerGui 容器中。
您可以創建多個 ScreenGui 物件以在遊玩過程中有條理地組織和顯示 UI 元件的分組。例如,範例雷射標籤體驗包括五個分開的 ScreenGui 物件,這些物件在玩家在主要的 用戶流 中滿足不同條件之前最初是禁用的:
- HUDGui - 在玩家在回合中活躍時顯示有關體驗玩法的關鍵信息,例如目標和每個隊伍的總分。
- PickABlasterGui - 在玩家開始或重新加入回合時顯示所有爆破器選擇。
- ForceFieldGui - 當玩家選擇爆破器並在暫時無敵期間顯示六邊形網格。
- OutStateGui - 當玩家被標記出局時,在屏幕周圍顯示深色邊框。
- RoundResultsGui - 在屏幕上方顯示深色覆蓋層,顯示哪個隊伍贏得了回合的信息。
在您創建了 ScreenGui 物件後,您可以根據每個容器的目的創建和自定義其子 GuiObjects。為了演示,接下來的幾個部分將教您如何實現玩家在範例雷射標籤體驗中需要了解的 三種類型信息 的 UI 元素。您可以調整過程的任何部分以滿足自己體驗的規範。
要創建 ScreenGui 物件:
在 Explorer 窗口中,將鼠標懸停在 StarterGui 服務上,然後單擊 ⊕ 圖標。顯示上下文菜單。
插入一個 ScreenGui。

根據其子 UI 元件的上下文重命名 ScreenGui。
對於您需要在每個玩家屏幕上顯示的每組 UI 元件重複此過程。

目標 UI
根據 為您的佈局製作線框 的可視層級最佳實踐,本節將教您如何實現所有與體驗的目標相關的屏幕上的 UI 元件。這組 UI 元件位於屏幕的頂部附近,因為目標和每個隊伍的分數對於贏得比賽具有最大的意義。

例如,該範例提供了一個目標 UI 元件,供玩家參考以了解他們需要做什麼才能在回合中取得成功。當玩家標記敵隊成員並獲得分數時,此元件保持追蹤每個隊伍的得分,並在標題的提示中顯示相對於整體目標的得分。要高級回顧所有協同追蹤分數的客戶端和服務器腳本,請參閱 追蹤分數 在遊戲玩法腳本課程中。

要在範例 雷射標籤 體驗中準確重建目標 UI:
為整個元件創建容器。
在 HUDGui ScreenGui 物件中插入一個 Frame。
- 在 Explorer 窗口中,導航到 StarterGui 服務。
- 將鼠標懸停在其子 HUDGui 物件上,然後單擊 ⊕ 圖標。顯示上下文菜單。
- 從上下文菜單中插入一個 Frame。

選擇新的 Frame,然後在 Properties 窗口中,
- 將 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,然後在 Properties 窗口中,
- 將 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,然後在 Properties 窗口中,
- 將 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,以顯示標題。
選擇新的標籤,然後在 Properties 窗口中,
- 將 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,然後在 Properties 窗口中,
- 將 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,以顯示提示。
選擇新標籤,然後在 Properties 窗口中,
- 將 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,然後在 Properties 窗口中,
- 將 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 物件,然後在 Properties 窗口,
- 將 Padding 設置為 0.025, 0,以在未來的隊伍計數器之間提供空間。
- 將 FillDirection 設置為 Horizontal,以便每個隊伍計數器並排顯示。
- 將 HorizontalAlignment 設置為 Center,以便每個隊伍計數器彼此對齊中間。
創建綠隊計數器元素。
在 TeamPointCounter 中插入一個 ImageLabel。
選擇 ImageLabel,然後在 Properties 窗口,
- 將 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,將圖像染成薄荷綠色。

配置自定義屬性以追蹤此標籤是針對綠隊的。
- 在 Properties 窗口中,導航到 Attributes 部分,然後單擊加號圖標。彈出對話框顯示。
- 在 Name 字段中,輸入 teamColor。
- 在 Type 下拉菜單中,選擇 BrickColor。
- 單擊 保存 按鈕。
- 將新的 teamColor 屬性設置為 Mint。
在 TeamACounter 中插入一個 TextLabel,以顯示提示。
選擇新的標籤,然後在 Properties 窗口,
- 將 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 物件,然後在 Properties 窗口中將 Color 設置為 8, 78, 52,以用深綠色描邊斜線。

創建粉紅隊計數器元素。
複製 TeamAICounter 及其子物件。
選擇複製的 TeamACounter,然後在 Properties 窗口中,
- 將 Name 設置為 TeamBCounter。
- 將 Image 設置為 rbxassetid://14305849451,以顯示朝相反方向的淡出效果。
- 將 ImageColor3 設置為 255, 170, 255,將圖像染成肉桂粉紅色。
- 將 teamColor 屬性設置為 Carnation Pink。
選擇複製的 TextLabel 子物件,然後在 Properties 窗口中,
- 將 AnchorPoint 設置為 0, 0.5,將新的標籤的原點設置在其左側中間(距離標籤的左側 0%,距離標籤的頂部 50%)。
- 將 Position 設置為 {0.05, 0},{0.5, 0},將標籤移動到其母標籤的左側(距離母標籤的左側 5%,距離母標籤的頂部 50%)。
- 將 TextXAlignment 設置為 Left。
選擇複製的 UIStroke 子物件,然後在 Properties 窗口中,將 Color 設置為 158, 18, 94,以用深粉紅色描邊斜線。

參考以下 ReplicatedStorage 腳本,這些腳本位於範例 雷射標籤 的位置文件內,以程式化地更新目標提示和追蹤隊伍得分。
以下腳本需要一組模組腳本,它們共同工作以設置主的面板 (HUD),包括 setObjective 和 startSyncingTeamPoints。在玩家加入回合並選擇爆破器後,此腳本確保所有 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 元件,用於告知玩家他們將在哪裡對目標進行攻擊。這個 UI 元件對於第一人稱射擊體驗來說是至關重要的,因為玩家需要能夠準確瞄準他們的爆破器並標記敵隊成員。
與大多數其他第一人稱射擊類型的體驗類似,範例雷射標籤體驗將十字準星放置在屏幕的中心,讓玩家在他們的化身穿過 3D 空間時有一個靜態目標可以專注於。除此之外,此位置還有助於減少暈動症,並使十字準星在環境中可辨。

要在範例 雷射標籤 體驗中準確重建十字準星:
在 HUDGui ScreenGui 物件中插入一個 ImageLabel。
在 Explorer 窗口中,導航到 StarterGui 服務。
將鼠標懸停在其子 HUDGui 物件上,然後單擊 ⊕ 圖標。顯示上下文菜單。
從上下文菜單中插入一個 ImageLabel。

選擇新的 ImageLabel,然後在 Properties 窗口,
- 將 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。
在 Explorer 窗口中,導航到 StarterGui 服務。
將鼠標懸停在其子 Crosshair 物件上,然後單擊 ⊕ 圖標。顯示上下文菜單。
從上下文菜單中插入一個 ImageLabel。

選擇新的 ImageLabel,然後在 Properties 窗口,
- 將 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,使擊中標記完全透明。接下來步驟中的腳本會在玩家的爆破攻擊觸及敵隊玩家時,將透明度恢復為 0。
參考以下 ReplicatedStorage 腳本,這些腳本位於範例 雷射標籤 的位置文件內,以程式化顯示擊中標記,當爆破擊中敵隊玩家時。
以下腳本需要一組模組腳本,它們共同工作以設置主的面板 (HUD),包括 setupHitmarker。在玩家加入回合並選擇爆破器後,此腳本確保所有 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 元素分組創建幾個容器、一個帶提示的標題、導航和選擇按鈕,以及一個爆破器按鈕預製件。整體元件的腳本邏輯根據表示每種爆破器類型的 Configuration 實例,將不同的視覺特徵填充到爆破器按鈕預製件中。
此設置還允許您為更多的爆破器類型創建額外的 Configuration 實例,這些實例自動在爆破器選擇器中正確顯示,而無需在 StarterGui.PickABlasterGui 中創建單獨的按鈕。

要在範例 雷射標籤 體驗中準確重建爆破器選擇器:
為整個元件創建容器。
在 PickABlaster ScreenGui 物件中插入一個 Frame。
- 在 Explorer 窗口中,導航到 StarterGui 服務。
- 將鼠標懸停在其子 PickABlaster 物件上,然後單擊 ⊕ 圖標。顯示上下文菜單。
- 從上下文菜單中插入一個 Frame。

選擇新的框,然後在 Properties 窗口中,
- 將 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。
選擇新的框,然後在 Properties 窗口中,
- 將 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 元件占據容器的 3/4(父框的 100% 水平和 75% 垂直)。
- 將 Name 設置為 SelectionFrame。

為爆破器選擇器創建提示。
在 SelectionFrame 中插入一個 ImageLabel。
選擇新的標籤,然後在 Properties 窗口,
- 將 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,以顯示提示。
選擇新的標籤,然後在 Properties 窗口,
- 將 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。
選擇新的標籤,然後在 Properties 窗口,
- 刪除默認的 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 物件插入按鈕中。
- 選擇新的圓角物件,然後在 屬性 視窗中,將 CornerRadius 設定為 0.1, 0 以圓化角落。

將 ImageLabel 物件插入按鈕中。
選擇新的標籤,然後在 屬性 視窗中,
- 將 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。
選擇複製的按鈕,然後在 屬性 視窗中,
- 將 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 按鈕。
將 ImageButton 插入 Component 中。注意這個過程如何將選擇按鈕與 SelectionFrame 分開,以便可以在主部分與選擇按鈕之間添加邊距。
選擇新的按鈕,然後在 屬性 視窗中,
- 移除預設的 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 物件插入按鈕中。
- 選擇新的圓角物件,然後在 屬性 視窗中,將 CornerRadius 設定為 0.2, 0 以圓化角落。

將 TextLabel 物件插入按鈕中,以便顯示呼籲行動的文本。
選擇新的標籤,然後在 屬性 視窗中,
- 將 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 資料夾。
- 將 ImageButton 物件插入 Guis 資料夾中。
- 選擇新的按鈕,然後在 屬性 視窗中,
- 移除預設的 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 以使圖像完全透明。
- 將 UIAspectRatioConstraint 插入 BlasterButtonPrefab 以確保按鈕的比例在玩家屏幕大小上保持一致。
- 圓角按鈕。
- 將 UICorner 物件插入 BlasterButtonPrefab。
- 選擇 UICorner,然後在 屬性 視窗中,將 CornerRadius 設定為 0.05, 0 以圓化角落。
- 將 ImageLabel 插入 BlasterButtonPrefab。
- 選擇新的標籤,然後在 屬性 視窗中,
- 移除 Image 屬性中的佔位符資產 ID。第 7 步中的腳本將程序化地將玩家的肖像插入圖像標籤中。
- 將 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 體驗中完全重建爆炸按鈕:
將 ImageButton 插入 HUDGui ScreenGui 物件。
在 Explorer 窗口中,導航到 StarterGui 服務。
將滑鼠懸停到其子 HUDGui 物件上,然後點擊 ⊕ 圖示。顯示出上下文菜單。
在上下文菜單中,插入 ImageButton。

在視口中,將按鈕移動到玩家的拇指自然放置的位置,以便你能獲得按鈕在玩家設備上的視覺感受,然後在 屬性 視窗中,
- 將 Image 設定為 rbxassetid://18308375035 以顯示爆炸按鈕圖標。
- 將 PressedImage 設定為 rbxassetid://18308372558 以在玩家按下按鈕時顯示爆炸按鈕圖標的反向版本。
- 將 BackgroundTransparency 設定為 1 以使標籤的背景完全透明。
- 將 Name 設定為 BlastButton。
- 將 ScaleType 設定為 Fit 使圖像適合其容器內,並不在不同屏幕尺寸上拉伸。
- 將 ImageTransparency 設定為 0.3 以減少標籤的不透明度,使其與體驗中的所有黑色 UI 元素匹配。
將 UIAspectRatioConstraint 插入 BlastButton 以確保按鈕的比例在玩家屏幕大小上保持一致。
參考以下 ReplicatedStorage 腳本,在範例 Laser Tag 地方文件中程序化顯示當玩家在支持觸控的設備上使用觸摸輸入時的爆炸按鈕。
以下腳本需要一組模組腳本協同工作,以設置主顯示屏(HUD),包括 setupTouchButtonAsync。當玩家加入一個回合並選擇他們的噴射器時,該腳本確保所有 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
根據 Wireframe Your Layouts 的視覺層次最佳實踐,本節教你如何實施與玩家狀態相關的所有屏幕上 UI 元素。這組 UI 元素位於屏幕的邊側,因為玩家可以在不轉移注意力的情況下理解這些周邊信息。

玩家指示器
玩家指示器是一個 UI 元件,玩家可以參考它快速識別他們所屬的隊伍,當他們一進入團隊的重生區域後。示例激光標籤體驗提供了兩個版本的玩家指示器,取決於玩家是屬於 綠色 還是 粉紅色 團隊。


根據 Select a Color Theme 的指導,這兩個版本的玩家指示器將隊伍顏色與獨特的簡單圖示結合在一起,盡可能少的細節,以保持在小屏幕上清晰可見。提供兩種形式的視覺反饋很重要,因為這有助於使設計變得對有色盲的玩家可訪問。

要在範例 Laser Tag 體驗中完全重建玩家指示器元件:
將 Frame 插入 HUDGui ScreenGui 物件。
- 在 Explorer 窗口中,導航到 StarterGui 服務。
- 將滑鼠懸停到其子 HUDGui 物件上,然後點擊 ⊕ 圖示。顯示出上下文菜單。
- 在上下文菜單中,插入 Frame。
選擇新的 Frame,然後在 屬性 視窗中,
將 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。

創建多邊形形狀。
將 ImageLabel 插入 PlayerDisplay。
選擇新的標籤,然後在 屬性 視窗中,
- 將 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 使圖像適合其容器內,並不在不同屏幕尺寸上拉伸。

- 將 UIAspectRatioConstraint 插入 Block 以確保標籤及其子 UI 元件的比例在玩家屏幕大小上保持一致。
- 選擇新的約束,然後在 屬性 視窗中,將 AspectRatio 設定為 13.78。
創建玩家肖像的盒子。
將 ImageLabel 插入 PlayerDisplay。
選擇新的標籤,然後在 屬性 視窗中,
- 移除 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 使圖像適合其容器內,並不在不同屏幕尺寸上拉伸。

- 將 UIAspectRatioConstraint 插入 PlayerPortrait 以確保標籤及其子 UI 元件的比例在玩家屏幕大小上保持一致。
- 將 UICorner 插入 PlayerPortrait,然後在 屬性 視窗中,將 CornerRadius 設定為 0.05, 0 以略微圓化角落。

創建玩家名稱的文本標籤。
將 TextLabel 物件插入 PlayerDisplay。
選擇新的標籤,然後在 屬性 視窗中,
- 將 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。

創建顯示在玩家肖像左側的團隊圖標和顏色。
將 Folder 插入 PlayerDisplay,然後將其重命名為 TeamIcons。
創建 綠色 團隊圖標和顏色。
- 將 ImageLabel 插入 TeamIcons。
- 選擇新的標籤,然後在 屬性 視窗中,
- 將 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 步中的腳本非常重要。
- 在 屬性 視窗中,導航至 Attributes 部分,然後點擊加號圖示。彈出對話框將顯示。
- 在 Name 欄位中,輸入 teamColor。
- 在 Type 下拉菜單中,選擇 BrickColor。
- 點擊 Save 按鈕。
- 將新的 teamColor 屬性設置為 Mint。
- 將 UIAspectRatioConstraint 插入 TeamAIcon 以確保標籤及其子 UI 元件的比例在玩家屏幕大小上保持一致。
- 創建圖標。
- 將 ImageLabel 插入 TeamAIcon。
- 選擇新的標籤,然後在 屬性 視窗中,
- 將 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,然後在 屬性 視窗中,
- 將 BackgroundColor3 設定為 255, 170, 255 以將標籤的背景顏色設置為肉色粉紅。
- 將 Name 設定為 TeamBIcon。
- 將 teamColor 屬性設置為 Carnation Pink。
- 選擇複製 TeamBIcon 的 子圖標,然後在 屬性 視窗中,將 Image 設定為 rbxassetid://14309678549 以顯示粉紅色團隊圖標。

參考以下 ReplicatedStorage 腳本,在範例 Laser Tag 地方文件中程序化顯示玩家指示器,使用適當的隊伍顏色和圖標,當玩家在回合中活躍時。
以下腳本需要一組模組腳本協同工作,以設置主顯示屏(HUD),包括 startSyncingTeamColor、setPlayerName 和 setPlayerPortrait。當玩家加入回合並選擇他們的噴射器時,這個腳本確保所有 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 元素,覆蓋視口以告訴玩家他們在加入或重新加入回合時不會受到敵方的攻擊。在 Choose an Art Style 中跟隨圖標的美學指導,示例激光標籤體驗利用半透明的六邊形圖案來象徵力場。這一設計決策不僅增強了所有 UI 的未來主義藝術風格,還在沒有任何文本或額外指導的情況下傳達了玩家的狀態。

要在範例 Laser Tag 體驗中完全重建力場屏幕:
將 ImageLabel 插入 ForceFieldGui ScreenGui 物件。
在 Explorer 窗口中,導航到 StarterGui 服務。
將滑鼠懸停到其子 ForceFieldGui 物件上,然後點擊 ⊕ 圖示。顯示出上下文菜單。
在上下文菜單中,插入 ImageLabel。

選擇新的標籤,然後在 屬性 視窗中,
將 Image 設定為 rbxassetid://14462567888。
將 BackgroundTransparency 設定為 0.8,以使力場半透明。
將 Size 設定為 {1, 0},{1, 0} 以使圖像填滿整個屏幕(父 ScreenGui 的 100% 水平和 100% 垂直)。
將 ScaleType 設定為 Tile,以使六邊形塗叠整個屏幕。
將 TileSize 設定為 {0, 104},{0, 180}。

將 UIGradient 物件插入標籤中。
選擇新的漸變物件,然後在 屬性 視窗中,
將 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 物件,然後在 屬性 視窗中,
將 Rotation 設定為 -45 以翻轉圖像,使其幾乎在 Y 軸上互相鏡像。

修改 Transparency 以使閃爍看起來更自然。
- 點擊 Transparency 屬性,然後點擊 ⋯ 按鈕。顯示數字序列彈出視窗。
- 選擇第三關鍵幀,然後點擊 Delete 按鈕。

參考以下 ReplicatedStorage 腳本,在範例 Laser Tag 地方文件中程序化顯示力場屏幕,當玩家加入或重新加入回合時。
以下的 ReplicatedStorage.ForceFieldClientVisuals 客戶端腳本將預設的 ForceField 視覺效果替換為 StarterGui.ForceFieldGui。當玩家進入體驗並在 SpawnLocation 上重生,且其 Duration 屬性大於 0 時,每個體驗中的預設行為是為他們的化身提供一個保護的藍色球體,並短暫地防止他們失去健康。
此腳本首先監聽 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
-- 如果玩家在禁用 ForceField 的重生點重生
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 元素很重要,因為它給予玩家時間來處理他們已被標記出的事實,並在重新加入活動回合之前計劃他們的下一步行動。
有關此示例激光標籤體驗中的自定義重生行為的更多資訊,請參閱 Respawn Characters 的 Gameplay Scripting 課程。

要準確重建示例 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},以將標籤置於其容器的中心(50% 從左至右,和 50% 從上到下)。
將 Size 設置為 {0.48, 0},{0.06, 0},以增加標籤的寬度(在父 ScreenGui 中橫向佔 48%,縱向佔 6%)。
將 Name 設置為 Block。
將 Image 設置為 rbxassetid://14304827265,以使該圖像呈梯形。
將 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},以將標籤置於其容器的中心(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,這將自動禁用重生畫面。要了解有關這些條件的更多資訊,請參閱 Handle Client State 的 Gameplay Scripting 課程。
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 包含應設置為獨佔的 guis 列表。
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(`Invalid player state ({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,並對每個玩家的腳本邏輯進行回應,您可以將 SurfaceGui 物件附加到您想在 ReplicatedStorage 服務中顯示 UI 的部件上。這種技術確保了您的 UI 及其腳本邏輯對伺服器和每個玩家的客戶端都是可用的。
SurfaceGui 物件包含所有在 3D 空間中呈現在部件表面的 GuiObjects。示例激光標籤體驗僅包括一個 SurfaceGui 物件:顯示在每個玩家的光束上方的冷卻計。這個物件需要為每個玩家編寫腳本邏輯,因為它會對每位玩家的輸入做出實際回應,並提供視覺反饋,告訴玩家何時可以再次發射光束。
要創建 SurfaceGui 物件:
- 在 Explorer 窗口中,懸停在 ReplicatedStorage 服務上,然後單擊 ⊕ 圖標。將顯示上下文菜單。
- 從上下文菜單中插入一個 Part 物件。
- 在該部件中插入一個 ScreenGui 物件。
- 根據其子 UI 元素的上下文重新命名 SurfaceGui。
- 對您需要顯示在部件表面上的每個 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},以將標籤置於其容器的中心(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%)。這一步對於腳本中的過渡行為也很有幫助。
圓角標籤。
- 在 Bar 中插入一個 UICorner 物件。
- 選擇 UICorner,然後在 Properties 窗口中,將 CornerRadius 設置為 0.15, 0,以稍微圓角。
將 CooldownBarPrefab 移動到 ReplicatedStorage。
創建一個文件夾結構以組織您的 UI 物件。範例使用一個名為 Instances 的文件夾,內含一個名為 Guis 的子文件夾。

將 CooldownBarPrefab 移動到 Guis 中。
在範例 Laser Tag 體驗中的 ReplicatedStorage 腳本中引用以下腳本,該腳本以程式方式將冷卻計附加到玩家的光束,然後在玩家發射光束後動畫化紅色條。
以下的 ReplicatedStorage.FirstPersonBlasterVisuals 客戶端腳本處理玩家第一人稱光束的所有視覺邏輯。它需要一組模組腳本,這些腳本協同工作以設置光束的視覺效果,使其在激光標籤的遊戲玩法中感覺更真實,包括 FirstPersonBlasterVisuals.addCooldownBar 和 FirstPersonBlasterVisuals.runCooldownBarEffect。
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
-- 更新到模型的 CFrame,相對於相機的位置和 RIG_OFFSET_FROM_CAMERA
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 或存在於 3D 空間中的 Attachment 的子項。
示例激光標籤體驗包含兩個單獨的 BillboardGui 物件,位於 ReplicatedStorage 服務中:
- OtherPlayerIndicatorGuiPrefab - 在每位玩家的頭頂上方顯示粉紅色或綠色圓圈,當他們在回合中活動時。
- TaggedOutIndicatorGuiPrefab - 當玩家在回合中被標記出時,顯示在他們的頭頂上方。
在您創建 BillboardGui 物件後,您可以根據每個容器的用途創建並自定義其子 GuiObjects。在接下來的立即部分中,您將學習如何在示例激光標籤體驗中為這兩種類型的指示器實現 UI 元素。 您可以調整過程的任何部分以滿足您自己體驗的規範。
要創建 BillboardGui 物件:
- 從上下文菜單中插入一個 BillboardGui 物件。
- 根據其子 UI 元素的上下文重新命名 BillboardGui。
- 對您需要在玩家頭頂上方顯示的每個 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},以將框置於其容器的中心(50% 從左至右,和 50% 從上到下)。
將 Size 設置為 {1, -2},{1, -2},以縮短框至 BillboardGui 的表面區域。

在 Frame 中插入一個 UICorner 物件,以完全圓角。

在 Frame 中插入一個 UIStroke 物件,以為指示器的圓形輪廓。

將 OtherPlayerIndicatorPrefab 移動到 ReplicatedStorage。
在範例 Laser Tag 1A 體驗中的 ReplicatedStorage 腳本中引用以下腳本,該腳本程式性地顯示活動回合中每位玩家的團隊指示器,除非他們在敵方隊伍中並被遮擋。
以下的 ReplicatedStorage.OtherPlayerIndicatorGuiSetup 腳本在玩家進入活動回合的競技場時運行。它通過調用 addIndicatorToCharacter() 函數來附加隊伍指示器,該函數定位到每位參加回合的玩家角色的 Head 物件。如果他們尚未擁有隊伍指示器,該腳本會克隆並將 otherPlayerIndicatorPrefab UI 添加到角色的 Head 上,並將隊伍指示器顏色設置為其隊伍顏色。
如果其他玩家與同一隊伍,則隊伍指示器始終顯示,即便他們藏在 3D 空間中的物體後面;如果其他玩家是敵方隊伍中的成員,隊伍指示器僅在 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,以將其定位在玩家的頭上方。

在 TaggedOutIndicatorGuiPrefab 中插入一個 ImageLabel 物件。
選擇新的標籤,然後在 Properties 窗口中,
- 將 AnchorPoint 設置為 0.5, 0.5,以將標籤的原點設置在其中心(50% 從左至右,和 50% 從上到下)。
- 將 BackgroundTransparency 設置為 1,以使標籤的背景完全透明。
- 將 Name 設置為 Frame。
- 將 Position 設置為 {0.5, 0},{0.5, 0},以將標籤置於其容器的中心(50% 從左至右,和 50% 從上到下)。
- 將 Size 設置為 {1, 0},{1, 0},以擴展標籤至整個 BillboardGui(在父 BillboardGui 中橫向佔 100%,縱向佔 100%)。
- 將 Image 設置為 rbxassetid://14304826985,以使圖像呈現多方向的漸變。
- 將 ImageColor 設置為 245, 46, 46,以將標籤的顏色調整為紅色。

在 Frame 中插入一個 TextLabel 物件。
選擇新的標籤,然後在 Properties 窗口中,
將 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)
祝賀您完成了用戶介面設計課程!現在您已經擁有創造藝術風格、線框佈局和從頭到尾在 Studio 中實現設計的經驗,您可以通過新的 UI 和功能擴展項目,或跟隨其他教學課程,例如 Gameplay Scripting Curriculum,該課程教您有關示例激光標籤體驗的通用組織和關鍵實施細節。祝您創作愉快!