디자인 구현하기는 스튜디오에서 내장 UI 요소와 사용자 정의 UI 요소를 사용하여 와이어프레임을 만드는 과정입니다. 이 흥미로운 튜토리얼 단계에서는 모든 디자인과 수고가 결합되어 플레이어 상호작용을 위해 완전하고 준비된 일관된 워크플로 세트를 볼 수 있습니다.
샘플 레이저 태그 게임 .rbxl 파일을 참조하여, 이 사용자 인터페이스 디자인 커리큘럼의 이 섹션에서는 UI 계획을 실현하는 방법을 보여줍니다. 여기에는 다음에 대한 안내가 포함됩니다:
- UI 자산 라이브러리에서 자산 ID를 검색하여 샘플 레이저 태그 게임의 UI 구성 요소를 재현할 수 있습니다.
- 스튜디오에서 다양한 장치를 직접 에뮬레이트하여 UI가 다양한 화면과 화면 비율에서 어떻게 표시되는지 확인합니다.
이 섹션의 기술을 검토한 후, 자신의 프로젝트에 적용하여 플레이어가 게임 내에서 할 수 있는 일을 탐색하는 데 도움이 되는 흥미로운 UI 구성 요소를 만들 수 있습니다.
자산 라이브러리 가져오기
자산 라이브러리는 쉽게 접근하고 재사용할 수 있도록 인벤토리에 추가할 수 있는 자산 모음입니다. Creator Store에서 프로젝트에 사용할 자산 라이브러리에는 2D 개별 UI 요소 자산 9개와 이 튜토리얼 섹션에서 생성하는 목표, 블래스터 선택기 및 플레이어 정보 구성 요소의 최종 버전이 포함되어 있습니다.

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 요소의 실제 해상도를 볼 수 있습니다.

장치 드롭다운에서 전화, 태블릿, 데스크탑, 및 콘솔 섹션 내에서 최소한 하나의 장치를 선택합니다.

ScreenGui 객체 만들기
모든 플레이어의 화면에 UI 요소를 표시하려면 ScreenGui 객체를 StarterGui 서비스에 생성할 수 있습니다. ScreenGui 객체는 화면 UI의 주요 컨테이너이며, StarterGui 서비스는 게임에 들어갈 때 각 플레이어의 PlayerGui 컨테이너에 내용을 복사합니다.
여러 개의 ScreenGui 객체를 생성하여 게임 플레이 중에 UI 요소 그룹을 맥락에 맞게 구성하고 표시할 수 있습니다. 예를 들어, 샘플 레이저 태그 게임에는 플레이어가 게임의 주요 사용자 흐름 중에 다양한 조건을 충족할 때까지 처음에는 비활성화된 다섯 개의 개별 ScreenGui 객체가 포함되어 있습니다:
- HUDGui - 플레이어가 라운드에서 활동할 때 게임 플레이에 대한 주요 정보를 표시합니다. 예를 들어 목표 및 각 팀의 총 점수입니다.
- PickABlasterGui - 플레이어가 라운드를 시작하거나 재참여할 때 모든 블래스터 선택을 표시합니다.
- ForceFieldGui - 플레이어가 블래스터를 선택할 때 육각형 그리드를 표시하며, 일시적으로 무적 상태일 때도 표시됩니다.
- OutStateGui - 플레이어가 태그 아웃되었을 때 화면 주위에 어두운 테두리를 표시합니다.
- RoundResultsGui - 라운드에서 어떤 팀이 승리했는지에 대한 정보를 포함하여 화면 위에 어두운 오버레이를 표시합니다.
ScreenGui 객체를 생성한 후, 각 컨테이너의 목적에 따라 자식 GuiObjects를 생성하고 사용자 정의할 수 있습니다. 다음 섹션에서는 플레이어가 샘플 레이저 태그 게임에서 성공하기 위해 알아야 할 세 가지 정보 범주용 UI 요소를 구현하는 방법을 배웁니다. 프로세스의 어떤 부분도 자신의 게임 사양에 맞게 조정할 수 있습니다.
ScreenGui 객체를 생성하려면:
탐색기 창에서 StarterGui 서비스 위에 마우스를 올리고 ⊕ 아이콘을 클릭합니다. 컨텍스트 메뉴가 표시됩니다.
ScreenGui를 삽입합니다.

자식 UI 요소의 맥락에 따라 ScreenGui의 이름을 바꿉니다.
모든 플레이어의 화면에 표시해야 하는 각 UI 요소 그룹에 대해 이 프로세스를 반복합니다.

목표 UI
와이어프레임 레이아웃에서 시각적 계층 구조 모범 사례를 따르면서, 이 섹션에서는 게임의 목표와 관련된 모든 화면 UI 요소를 구현하는 방법을 가르칩니다. 이 UI 요소 그룹은 화면 상단에 가까이 위치하며, 목표와 각 팀의 점수가 게임에서 승리하는 방법에 가장 큰 중요성을 가지기 때문입니다.

예를 들어, 샘플은 플레이어가 라운드에서 성공하기 위해 무엇을 해야 하는지 알기 위해 참조하는 목표 UI 구성 요소를 제공합니다. 플레이어가 적 팀원을 태그 아웃하고 점수를 얻을 때, 이 구성 요소는 헤더의 프롬프트 내에서 전체 목표에 대한 각 팀의 점수를 추적합니다. 모든 클라이언트 및 서버 스크립트가 함께 작동하여 점수를 추적하는 방법에 대한 높은 수준의 검토는 게임 플레이 스크립팅 커리큘럼의 점수 추적을 참조하십시오.

샘플 레이저 태그 게임 내에서 목표 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.LocalPlayer
local 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 요소는 1인칭 슈팅 게임의 필수 게임 플레이 요구 사항입니다. 플레이어는 블래스터를 정확하게 조준하고 적 팀원을 태그 아웃할 수 있어야 합니다.
대부분의 1인칭 슈팅 게임과 마찬가지로 샘플 레이저 태그 게임은 조준경을 화면 중앙에 배치하여 플레이어가 아바타가 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 요소는 플레이어가 상대를 태그 아웃하는 데 성공했을 때 시각적 피드백을 제공하기 때문에 1인칭 슈팅 게임의 필수 게임 플레이 요구 사항입니다.

샘플 레이저 태그 게임 내에서 히트 마커를 정확하게 재현하려면:
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로 설정하여 히트 마커를 완전히 투명하게 만듭니다. 다음 단계의 스크립트는 플레이어의 발사가 적 팀의 다른 플레이어에 충격을 줄 때마다 투명도를 다시 0으로 설정합니다.
샘플 레이저 태그 장소 파일 내에서 발사가 적 팀의 플레이어에 충격을 줄 때 히트 마커를 프로그래밍적으로 표시하는 다음 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.LocalPlayer
local 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 인스턴스를 생성하여 블래스터 선택기 내에서 개별 버튼을 생성할 필요 없이 자동으로 올바르게 표시할 수 있습니다.

샘플 레이저 태그 게임 내에서 블래스터 선택기를 정확하게 재현하려면:
전체 구성 요소를 위한 컨테이너를 생성합니다.
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 구성 요소가 컨테이너의 3/4를 차지하도록 합니다 (부모 프레임의 수평으로 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로 설정하여 헤더를 반투명하게 만듭니다.

- 선택 사항Header에 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을 삽입합니다.
새 레이블을 선택한 다음 속성 창에서,
- 기본 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 객체를 삽입합니다.
- 새 코너 객체를 선택한 다음 속성 창에서 CornerRadius를 0.075, 0으로 설정하여 모서리를 둥글게 만듭니다.

블래스터 버튼을 위한 컨테이너를 생성합니다.
- 레이블에 Frame을 삽입합니다.
- 새 프레임을 선택한 다음 속성 창에서,1. 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 객체를 정리하기 위한 폴더 구조를 만듭니다. 샘플에서는 Instances 폴더와 그 하위에 Guis 폴더를 사용합니다.
- 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으로 설정합니다.
샘플 Laser Tag 장소 파일 내에서 다음 ReplicatedStorage 스크립트를 참조하여 각 블래스터에 대한 버튼을 프로그래밍 방식으로 표시하고, 플레이어가 포커스가 아닌 버튼을 선택할 때 버튼의 크기를 조정하며, 플레이어의 블래스터 선택을 아바타에 연결합니다.
다음 스크립트는 블래스터 선택기를 생성하기 위해 함께 작동하는 스크립트 세트를 필요로 합니다. 플레이어가 게임에 참여하거나 건강이 0에 도달한 후 라운드에 다시 스폰할 때, 이 스크립트는 플레이어가 선택을 할 때까지 블래스터 선택기의 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.LocalPlayer
local 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 스크립트를 참조하여 플레이어가 터치 입력을 사용하는 장치에서 블래스터 버튼을 프로그래밍 방식으로 표시합니다.
다음 스크립트는 setupTouchButtonAsync를 포함하여 주요 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.LocalPlayer
local 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 게임 내에서 플레이어 표시기 구성 요소를 정확하게 재현하려면:
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 스크립트를 참조하여 플레이어가 라운드에서 활성 상태일 때 적절한 팀 색상과 아이콘으로 플레이어 표시기를 프로그래밍 방식으로 표시합니다.
다음 스크립트는 startSyncingTeamColor, setPlayerName, 및 setPlayerPortrait를 포함하여 주요 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.LocalPlayer
local 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 게임 내에서 포스 필드 화면을 정확하게 재현하려면:
ForceFieldGui ScreenGui 객체에 ImageLabel을 삽입합니다.
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를 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

1. ImageLabel를 2단계에서 복제합니다.
복제된 레이블 내의 UIGradient 객체를 선택한 다음, 속성 창에서,
회전을 -45로 설정하여 이미지를 뒤집어 Y축을 따라 거의 서로를 반사하도록 합니다.

투명도를 수정하여 반짝임이 더 자연스럽게 보이도록 합니다.
- 투명도 속성을 클릭한 다음, ⋯ 버튼을 클릭합니다. 숫자 시퀀스 팝업이 표시됩니다.
- 세 번째 키프레임을 선택한 다음, 삭제 버튼을 클릭합니다.

샘플 Laser Tag 장소 파일 내의 ReplicatedStorage 스크립트를 참조하여 플레이어가 라운드에 참여하거나 재참여할 때 힘의 장 화면을 프로그래밍 방식으로 표시합니다.
다음 ReplicatedStorage.ForceFieldClientVisuals 클라이언트 스크립트는 기본 ForceField 시각적 요소를 StarterGui.ForceFieldGui로 대체합니다. 플레이어가 게임에 로드되고 Duration 속성이 0보다 큰 SpawnLocation에서 스폰할 때, 모든 게임에서 기본 동작은 그들의 아바타에 건강을 잃는 것을 잠시 방지하는 보호 파란색 구체를 제공합니다.
이 스크립트는 ForceField가 캐릭터에 추가될 때를 듣고, 기본 1인칭 힘의 장 시각적 요소를 비활성화한 다음, ForceFieldGui ScreenGui 객체를 활성화합니다. 이는 플레이어가 다른 플레이어가 게임에 다시 스폰하는 것을 볼 때 3인칭 시각적 요소에는 영향을 미치지 않습니다.


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 요소는 플레이어가 태그 아웃되었음을 처리하고, 활성 라운드에 다시 참여하기 전에 다음 움직임을 전략적으로 계획할 수 있는 시간을 제공합니다.
샘플 레이저 태그 게임에서 사용자 정의 리스폰 동작에 대한 자세한 내용은 Respawn Characters에서 확인하세요.

샘플 Laser Tag 게임 내에서 리스폰 화면을 정확하게 재현하려면:
중앙 정보 배너를 만듭니다.
OutStateGui ScreenGui 객체에 ImageLabel을 삽입합니다.
Explorer 창에서 StarterGui 서비스를 탐색합니다.
자식 OutStateGui 객체 위에 마우스를 올리고 ⊕ 아이콘을 클릭합니다. 컨텍스트 메뉴가 표시됩니다.
컨텍스트 메뉴에서 ImageLabel을 삽입합니다.

새 레이블을 선택한 다음, 속성 창에서,
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로 설정하여 이미지를 사다리꼴로 만듭니다.
ImageColor를 0,0,0으로 설정하여 사다리꼴을 검은색으로 만듭니다.
ImageTransparency를 0.3으로 설정하여 레이블의 불투명도를 30% 줄이고 게임 내 모든 검은색 UI 요소와 일치시킵니다.

Block에 UIAspectRatioConstraint를 삽입하여 레이블과 그 자식 UI 요소의 종횡비가 플레이어의 화면 크기에 관계없이 동일하게 유지되도록 합니다.
새 제약 조건을 선택한 다음, 속성 창에서 AspectRatio를 13.78로 설정합니다.
Block에 정보 텍스트를 위한 TextLabel을 삽입합니다.
새 레이블을 선택한 다음, 속성 창에서,
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을 삽입합니다.
새 레이블을 선택한 다음, 속성 창에서,
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을 삽입합니다.
새 레이블을 선택한 다음, 속성 창에서,
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을 삽입합니다.
- 새 레이블을 선택한 다음, 속성 창에서,
- 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 스크립트를 참조하여 플레이어의 건강이 0에 도달하고 팀의 스폰 존으로 다시 리스폰하는 과정에서 리스폰 화면을 프로그래밍 방식으로 표시합니다.
다음 ReplicatedStorage.PlayerStateHandler 클라이언트 스크립트는 playerState 속성에 따라 다양한 유형의 동작을 트리거하는 함수를 포함합니다. 모든 이벤트 응답은 플레이어 제어, 카메라 이동 및 어떤 UI 레이어가 표시되는지의 유사한 동작을 요구하기 때문에 이 스크립트에서 논리적으로 그룹화되어 있습니다.
플레이어의 건강이 0에 도달하면, 그들의 playerState는 TaggedOut이 되어 onTaggedOut() 함수가 트리거됩니다. onTaggedOut()은 즉시 다음 동작을 트리거합니다:
- 플레이어는 아레나에서 이동할 수 없습니다.
- 플레이어는 카메라를 이동할 수 없습니다.
- 플레이어는 블래스터를 사용할 수 없습니다.
- StarterGui.OutStateGui가 독점적으로 활성화됩니다.
플레이어가 리스폰할 때, 그들의 playerState는 SelectingBlaster가 되어 onSelectingBlaster() 함수가 트리거됩니다. onSelectingBlaster()는 StarterGui.PickABlasterGui를 독점적으로 활성화하여 리스폰 화면을 자동으로 비활성화합니다. 이러한 조건에 대한 자세한 내용은 Handle Client State에서 확인하세요.
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를 표시하고 각 개별 플레이어의 스크립팅 논리에 반응하도록 하려면, SurfaceGui 객체를 표시할 부품에 부모로 설정할 수 있습니다. 이 기술은 UI와 그 스크립팅 논리가 서버와 각 플레이어의 클라이언트 모두에서 사용 가능하도록 보장합니다.
SurfaceGui 객체는 3D 공간의 부품 표면에 표시되는 모든 GuiObjects를 포함합니다. 샘플 레이저 태그 게임에는 각 플레이어의 블래스터 위에 표시되는 쿨다운 미터라는 SurfaceGui 객체의 인스턴스가 하나만 포함되어 있습니다. 이 객체는 각 플레이어의 입력에 적극적으로 반응하고, 그들이 다시 블래스터를 발사할 수 있는 시점을 시각적으로 피드백하기 때문에 모든 플레이어에 대한 스크립팅 논리가 필요합니다.
SurfaceGui 객체를 만들려면:
- Explorer 창에서 ReplicatedStorage 서비스 위에 마우스를 올리고 ⊕ 아이콘을 클릭합니다. 컨텍스트 메뉴가 표시됩니다.
- 컨텍스트 메뉴에서 Part 객체를 삽입합니다.
- 부품에 ScreenGui 객체를 삽입합니다.
- 자식 UI 요소의 맥락에 따라 SurfaceGui의 이름을 바꿉니다.
- 3D 공간의 부품 표면에 표시해야 하는 모든 UI 요소에 대해 이 프로세스를 반복합니다.

쿨다운 미터
쿨다운 미터는 플레이어가 다시 블래스터를 발사할 수 있기까지 얼마나 기다려야 하는지를 알려주는 UI 구성 요소입니다. 이 약간의 지연은 플레이어가 클릭하거나 버튼을 누를 수 있는 속도로 발사할 수 없도록 하여 레이저 태그 게임 플레이에 비현실적이지 않도록 합니다.
샘플 Laser Tag 게임 내에서 쿨다운 미터를 정확하게 재현하려면:
SurfaceGui 객체를 보유할 부품을 만듭니다.
- Explorer 창에서 Workspace 위에 마우스를 올리고 ⊕ 아이콘을 클릭합니다. 컨텍스트 메뉴가 표시됩니다.
- 컨텍스트 메뉴에서 블록 부품을 삽입합니다. 이는 프로세스의 각 단계에서 변경 사항을 시각화할 수 있도록 부품의 임시 위치입니다.
부품을 플레이어의 캐릭터가 블래스터를 잡을 위치에 맞게 배치하고 방향을 조정한 다음, 속성 창에서,
투명도를 1로 설정하여 부품을 완전히 투명하게 만듭니다.
이름을 CooldownBarPrefab으로 설정합니다.
크기를 0.169, 0.027, 2.537로 설정하여 부품을 블래스터의 길이 정도로 조정합니다.
CanCollide와 CanQuery를 비활성화합니다.

CooldownBarPrefab에 SurfaceGui를 삽입합니다.
새 SurfaceGui를 선택한 다음, 속성 창에서,
Face를 Top으로 설정하여 UI가 위를 향하도록 합니다.
LightInfluence와 MaxDistance를 0으로 설정합니다.
PixelsPerStud를 200으로 설정합니다.

검은색 바를 만듭니다.
SurfaceGui에 ImageLabel을 삽입합니다.
새 레이블을 선택한 다음, 속성 창에서,
- 기본 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% 수직).
- 이름을 Container로 설정합니다.

컨테이너의 모서리를 둥글게 만듭니다.
Container에 UICorner 객체를 삽입합니다.
UICorner를 선택한 다음, 속성 창에서 CornerRadius를 0.15, 0으로 설정하여 모서리를 약간 둥글게 만듭니다.

빨간색 바를 만듭니다.
- Container에 ImageLabel을 삽입합니다.
- 새 레이블을 선택한 다음, 속성 창에서,
- 기본 Image 값을 제거합니다.
- AnchorPoint를 1, 0.5로 설정하여 레이블의 원점이 레이블의 오른쪽 중간에 위치하도록 합니다 (레이블의 왼쪽에서 오른쪽으로 100%, 위에서 아래로 50%).
- BackgroundColor3를 172, 13, 13으로 설정하여 레이블의 배경 색상을 어두운 빨간색으로 설정합니다.
- BackgroundTransparency를 0.2로 설정하여 레이블의 배경을 약간 투명하게 만듭니다.
- 이름을 Bar로 설정합니다.
- Position을 {1, 0},{0.5, 0}로 설정하여 레이블을 컨테이너의 오른쪽 중간에 배치합니다 (부모 레이블의 왼쪽에서 오른쪽으로 100%, 위에서 아래로 50%).
- Size를 {0, 0},{1, 0}로 설정하여 레이블을 부모 레이블의 상단으로 늘립니다 (부모 레이블의 0% 수평 및 100% 수직). 이 단계는 또한 8단계의 스크립트에서 발생하는 트윈 동작에 유용합니다.
레이블의 모서리를 둥글게 만듭니다.
- Bar에 UICorner 객체를 삽입합니다.
- UICorner를 선택한 다음, 속성 창에서 CornerRadius를 0.15, 0으로 설정하여 모서리를 약간 둥글게 만듭니다.
CooldownBarPrefab을 ReplicatedStorage로 이동합니다.
UI 객체를 정리하기 위해 폴더 구조를 만듭니다. 샘플은 Instances 폴더와 자식 Guis 폴더를 사용합니다.

CooldownBarPrefab을 Guis로 이동합니다.
샘플 Laser Tag 장소 파일 내의 ReplicatedStorage 스크립트를 참조하여 플레이어의 블래스터에 쿨다운 미터를 프로그래밍 방식으로 연결한 다음, 플레이어가 블래스터를 발사한 후 빨간색 바를 애니메이션합니다.
다음 ReplicatedStorage.FirstPersonBlasterVisuals 클라이언트 스크립트는 플레이어의 1인칭 블래스터에 대한 모든 시각적 논리를 처리합니다. 이는 레이저 태그 게임 플레이에 더 현실감 있는 블래스터 시각적 요소를 설정하기 위해 함께 작동하는 모듈 스크립트 세트를 요구합니다. 여기에는 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()
-- 1인칭 리그 추가
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
-- 발사가 발생할 때 1인칭 시각적 효과 실행
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 요소를 표시하고 스크립팅 논리에 반응하며 각 플레이어의 카메라를 항상 바라보도록 하려면, BasePart 또는 Attachment의 자식으로 BillboardGui 객체를 생성할 수 있습니다. 이는 플레이어 이름이나 지도 마커와 같은 요소에 유용합니다.
샘플 레이저 태그 게임에는 ReplicatedStorage 서비스 내에 두 개의 별도 BillboardGui 객체가 포함되어 있습니다:
- OtherPlayerIndicatorGuiPrefab - 라운드에서 활성화된 각 플레이어의 머리 위에 분홍색 또는 녹색 원을 표시합니다.
- TaggedOutIndicatorGuiPrefab - 플레이어가 라운드에서 태그 아웃되었을 때 머리 위에 표시됩니다.
BillboardGui 객체를 생성한 후, 각 컨테이너의 목적에 따라 자식 GuiObjects를 생성하고 사용자 정의할 수 있습니다. 다음 섹션에서는 샘플 레이저 태그 게임 내에서 두 가지 인디케이터 유형에 대한 UI 요소를 구현하는 방법을 배웁니다. 자신의 게임 사양에 맞게 프로세스의 어떤 부분도 조정할 수 있습니다.
BillboardGui 객체를 만들려면:
- 컨텍스트 메뉴에서 BillboardGui 객체를 삽입합니다.
- 자식 UI 요소의 맥락에 따라 BillboardGui의 이름을 바꿉니다.
- 플레이어 머리 위에 맥락적으로 표시해야 하는 모든 UI 요소에 대해 이 프로세스를 반복합니다.
팀 인디케이터
팀 인디케이터는 플레이어에게 라운드에서 다른 플레이어가 어떤 팀에 속하는지를 알려주는 UI 요소로, 동맹과 적 팀원을 쉽게 구별할 수 있도록 합니다. 이 정보는 1인칭 슈팅 게임의 게임 플레이에서 플레이어가 전투 지역에서 태그 아웃되지 않고 경기를 잃지 않도록 빠른 전략적 결정을 내리는 데 중요합니다.

샘플 Laser Tag 게임 내에서 팀 인디케이터를 정확하게 재현하려면:
임시 리그에 BillboardGui 객체를 삽입합니다.
툴바의 홈 또는 아바타 탭에서 캐릭터를 클릭합니다.
사용 가능한 옵션 중에서 선택합니다. 샘플은 R15 리그 유형, 여성 몸체 형태 및 Rthro 아바타를 사용합니다. 리그는 3D 뷰포트와 Explorer 창에서 Rig라는 이름으로 표시됩니다.
Explorer 창에서 리그의 자식 Head 메쉬로 이동한 다음, ⊕ 아이콘을 클릭합니다. 컨텍스트 메뉴가 표시됩니다.
컨텍스트 메뉴에서 BillboardGui를 삽입합니다.

새 BillboardGui를 선택한 다음, 속성 창에서,
LightInfluence를 0으로 설정하여 환경 조명이 인디케이터의 색상에 영향을 미치지 않도록 합니다.
이름을 OtherPlayerIndicatorPrefab으로 설정합니다.
크기를 {0, 10},{0, 10}으로 설정하여 레이블을 상당히 작게 만듭니다.
StudsOffsetWorldSpace를 0, 4, 0으로 설정하여 리그의 머리 위에 위치시킵니다.

OtherPlayerIndicatorPrefab에 Frame 객체를 삽입합니다.
새 프레임을 선택한 다음, 속성 창에서,
AnchorPoint를 0.5, 0.5로 설정하여 프레임의 원점이 프레임의 중간에 위치하도록 합니다 (프레임의 왼쪽에서 오른쪽으로 50%, 위에서 아래로 50%).
BackgroundColor3를 255, 3, 0으로 설정하여 프레임의 배경 색상을 빨간색으로 설정합니다 (플레이스홀더 색상).
Position을 {0.5, 0},{0.5, 0}로 설정하여 프레임을 부모 BillboardGui의 중앙에 배치합니다 (부모 BillboardGui의 왼쪽에서 오른쪽으로 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 요소입니다. 이 정보는 1인칭 슈팅 게임의 게임 플레이에서 플레이어가 태그 아웃된 플레이어를 태그한 후 다음 목표로 이동해야 하므로 중요합니다. 너무 오랫동안 같은 위치에서 플레이하면 취약해질 수 있습니다.

샘플 Laser Tag 게임 내에서 태그 아웃 인디케이터를 정확하게 재현하려면:
임시 리그에 BillboardGui 객체를 삽입하여 각 단계에서 변경 사항을 시각화합니다.
툴바의 홈 또는 아바타 탭에서 캐릭터를 클릭합니다.
사용 가능한 옵션 중에서 선택합니다. 샘플은 R15 리그 유형, 남성 몸체 형태 및 Rthro 아바타를 사용합니다. 리그는 3D 뷰포트와 Explorer 창에서 Rig라는 이름으로 표시됩니다.
Explorer 창에서 리그의 자식 Head 메쉬로 이동한 다음, ⊕ 아이콘을 클릭합니다. 컨텍스트 메뉴가 표시됩니다.
컨텍스트 메뉴에서 BillboardGui를 삽입합니다.

새 BillboardGui를 선택한 다음, 속성 창에서,
LightInfluence를 0으로 설정하여 환경 조명이 인디케이터의 색상에 영향을 미치지 않도록 합니다.
이름을 TaggedOutIndicatorGuiPrefab으로 설정합니다.
크기를 {3, 0},{0.5, 0}으로 설정하여 레이블을 위한 공간을 넓힙니다.
StudsOffset를 0, 3.25, 0으로 설정하여 플레이어의 머리 위에 위치시킵니다.

TaggedOutIndicatorGuiPrefab에 ImageLabel 객체를 삽입합니다.
새 레이블을 선택한 다음, 속성 창에서,
- AnchorPoint를 0.5, 0.5로 설정하여 레이블의 원점이 레이블의 중간에 위치하도록 합니다 (레이블의 왼쪽에서 오른쪽으로 50%, 위에서 아래로 50%).
- BackgroundTransparency를 1로 설정하여 레이블의 배경을 완전히 투명하게 만듭니다.
- 이름을 Frame으로 설정합니다.
- Position을 {0.5, 0},{0.5, 0}로 설정하여 레이블을 부모 BillboardGui의 중앙에 배치합니다 (부모 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로 설정하여 레이블의 배경을 완전히 투명하게 만듭니다.
이름을 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와 같은 추가 튜토리얼 커리큘럼을 따를 수 있습니다. 창작을 즐기세요!