HUD (Heads-Up Display) ในประสบการณ์ของคุณมักจะแสดงองค์ประกอบ UI ที่ไม่โต้ตอบเช่นมิเตอร์สุขภาพที่แสดงใน สร้างมิเตอร์ HUD นอกจากนี้ แทบทุกประสบการณ์ต้องการ UI เชิงโต้ตอบ เช่นปุ่มที่ตอบสนองต่อการกระตุ้นของผู้เล่น มีการเคลื่อนไหวเมื่อเปิดใช้งาน แอนิเมชั่นเมนูที่ไล่เข้า/ออกพร้อมกับการควบคุมเชิงโต้ตอบอื่น ๆ เป็นต้น

ใช้ UI Fundamentals - HUD Meter เป็นจุดเริ่มต้นและ UI Fundamentals - Interactivity เป็นเอกสารอ้างอิงที่เสร็จสิ้นบทช่วยสอนนี้แสดงให้เห็นถึง:
- วิธีการจัดตำแหน่งปุ่มตั้งค่าที่ขอบด้านบนของหน้าจอ
- การออกแบบเมนูตั้งค่าที่มีตัวเลื่อนที่สามารถลากได้แบบเชิงโต้ตอบ
- การใช้งาน ModuleScripts เพื่อสร้างโมดูล "ตัวควบคุม" สำหรับการควบคุม UI ที่สามารถขยายได้ด้วยการประกาศสถานะ
- วิธีเชื่อมต่อปุ่มกับการกระตุ้นของผู้เล่นเพื่อเปิด/ปิดเมนูตั้งค่า
- วิธีเชื่อมต่อ UI sliders ที่ลากได้เพื่อตั้งค่าระดับเสียงของเอฟเฟกต์เสียงและบรรยากาศพื้นหลังแยกจากกัน
เปิดใช้งานตัวจำลองอุปกรณ์
ตามที่กล่าวไว้ใน สร้างมิเตอร์ HUD โทรศัพท์และแท็บเล็ตมีพื้นที่หน้าจอที่น้อยที่สุด ดังนั้นจึงเป็นสิ่งสำคัญที่องค์ประกอบ UI ของคุณจะต้องพอดีกับหน้าจอขนาดเล็กกว่าและเห็นได้ชัดเจนสำหรับผู้เล่น หากคุณยังไม่ได้ทำ โปรดเปิดใช้งาน Device Emulator ใน Studio:
เปิดเทมเพลต UI Fundamentals - HUD Meter ใน Studio.
จากเมนู Test ของ Studio ให้เปิด Device Emulator.
จากแถบโดยตรงด้านบนมุมมองหลักให้เลือกอีมูเลเตอร์โทรศัพท์ เช่น iPhone X หรือ Samsung Galaxy A51 จากนั้นตั้งค่าขนาดมุมมองเป็น Fit to Window เพื่อใช้พื้นที่สูงสุดใน Studio.

สร้างปุ่มตั้งค่า
GuiButtons เป็นองค์ประกอบอินเทอร์เฟซผู้ใช้ที่มีฟังก์ชันการทำงานในตัว เช่น เหตุการณ์ Activated แบบหลายแพลตฟอร์มซึ่งจะทำงานเมื่อมีการคลิกหรือแตะปุ่ม GuiButton ชนิดมีก 2 รูปแบบ TextButton และ ImageButton โดยบทช่วยสอนนี้ใช้ ImageButton รูปทรง "เกียร์" เพื่อเปิดหรือปิดเมนูตั้งค่า

ในการสร้างปุ่มตั้งค่า:
ในหน้าต่าง Explorer ให้ค้นหา HUDContainer ภายใน StarterGui.

เมื่อเลือกปุ่มใหม่แล้วให้ตั้งค่าในหน้าต่าง Properties ดังนี้:
- AnchorPoint = 0.5, 0.25 (กลางทางด้านขวาและด้านแนวตั้งอันดับที่หนึ่ง)
- BackgroundTransparency = 1 (โปร่งใสเต็มที่)
- Position = 0.5, 0, 0, 0 (จัดตำแหน่งกลางด้านบน)
- Size = 0.1, 0, 0.1, 0 (10% ของความสูงหน้าจอเมื่อจำกัดอัตราส่วน)
- Image = rbxassetid://104919049969988 (ID ของทรัพย์สินสัญลักษณ์ "เกียร์")
แทรก UIAspectRatioConstraint ลงในปุ่มด้วยค่าเริ่มต้น (อัตราส่วน 1:1 ความกว้างต่อความสูง).

สร้างเมนูตั้งค่า
ปุ่ม ตั้งค่า ใหม่จะต้องมีการเขียนสคริปต์เพื่อเป็นการเปิดและปิดเมนูตั้งค่า ซึ่งจะให้ผู้เล่นเข้าถึงการตั้งค่าหรือข้อมูลอื่นๆ ได้ตามที่ต้องการ ในบทช่วยสอนนี้ เมนูจะมีตัวเลื่อนแบบอินเทอร์แอกทีฟเพื่อตั้งค่าระดับเสียงของเสียงพื้นหลังและเอฟเฟกต์เสียงโดยแยกกัน

สร้างกรอบหลัก
ตามที่ได้กล่าวไว้ใน สร้างมิเตอร์ HUD Frame ทำหน้าที่เป็นตัวเก็บสำหรับวัตถุ UI อื่น ๆ เมนูตั้งค่าทั้งหมดจะถูกสร้างขึ้นจากกรอบหลักเดียว ทำให้จัดการได้ง่ายในฐานะวัตถุที่มีสถานะซึ่งตอบสนองต่อการป้อนข้อมูลแตกต่างกันไปตามสถานะปัจจุบัน
แทรก Frame ลงใน HUDContainer และเปลี่ยนชื่อเป็น SettingsMenu.

เมื่อเลือก SettingsMenu แล้วให้ตั้งค่าให้เป็นไปตามนี้:
- AnchorPoint = 0.5 (จุดยึดกลาง)
- BackgroundColor3 = 30, 30, 60 (สีน้ำเงินเข้ม)
- BackgroundTransparency = 0.25 (โปร่งใส 75%)
- Position = 0.5, 0, 0.5, 0 (กลางของหน้าจอ)
- Size = 0.75, 0, 0.75, 0 (75% ของความกว้าง/ความสูงของพื้นที่หน้าจอที่ตัดออก)

แทรก UIAspectRatioConstraint ลงใน SettingsMenu และตั้งค่า AspectRatio เป็น 2.5. (อัตราส่วนกว้างต่อสูง 2.5:1).


แทรกตัวปรับแต่ง UICorner ลงใน SettingsMenu และตั้งค่า CornerRadius เป็น 0.1, 0.


เพื่อจำกัดความกว้างและความสูงพิกเซลของ SettingsMenu ให้แทรก UISizeConstraint ตั้งค่า MaxSize เป็น 800, inf และ MinSize เป็น 350, 0.



สร้างตัวเลื่อน
เพื่อให้ผู้เล่นสามารถปรับระดับเสียงได้ เมนูตั้งค่าจะมีตัวเลื่อน slider widgets ที่สามารถลากได้ โดยใช้ UIDragDetector ซึ่งเป็นวัตถุที่สะดวกในการทำให้เกิดการโต้ตอบกับองค์ประกอบ UI 2D
ในการสร้างตัวเก็บสำหรับตัวเลื่อนแรก:
แทรก Frame ใหม่ลงใน SettingsMenu และเปลี่ยนชื่อเป็น EffectsVolumeSlider.

เมื่อเลือกกรอบ EffectsVolumeSlider แล้วให้ตั้งค่าให้เป็นไปตามนี้:
- AnchorPoint = 0.5 (จุดยึดกลาง)
- BackgroundTransparency = 1 (โปร่งใสเต็มที่)
- Position = 0.5, 0, 0.35, 0 (กลางระยะทางแนวนอนและ 35% จากด้านบนของตัวเก็บ)
- Size = 0.8, 0, 0.1, 0 (80% ของความกว้างของตัวเก็บและ 10% ของความสูง)

แทรก UIListLayout ใหม่ลงใน EffectsVolumeSlider ตัวปรับเลย์เอาต์นี้เป็นวิธีที่มีประสิทธิภาพในการเรียงลำดับ GuiObjects ที่เป็นพี่น้องกันไปในแถวแนวนอนหรือคอลัมน์แนวตั้งในตัวเก็บหลักของพวกเขา รวมทั้งความสามารถในการใช้แนวคิด flex.

ตั้งค่าคุณสมบัติต่อไปนี้สำหรับ UIListLayout ใหม่:
- Padding = 0.06, 0 (ช่องว่างระหว่างองค์ประกอบในรายการ 6%)
- FillDirection = Horizontal (การจัดเรียงองค์ประกอบจากซ้ายไปขวา)
- HorizontalFlex = Fill (ปรับขนาดองค์ประกอบให้กว้างขึ้นเพื่อเติมเต็มตัวเก็บหลักทั้งหมด โดยยกเลิกความกว้างที่กำหนด)
- VerticalAlignment = Center (จัดเรียงองค์ประกอบตามแนวกลางของแต่ละแนวตั้ง)
ไอคอนตัวเลื่อน
ไอคอนที่เรียบง่ายรวมถึงโน้ตเสียงและสัญลักษณ์ "ระเบิด" ช่วยให้ผู้เล่นระบุถึงวัตถุประสงค์ของตัวเลื่อนเมื่อเปิดเมนูการตั้งค่า

แทรก ImageLabel ลงในกรอบ EffectsVolumeSlider และเปลี่ยนชื่อเป็น Icon ไอคอนนี้จะช่วยให้ผู้เล่นเข้าใจว่าวัตถุประสงค์ในประสบการณ์ใดที่ตัวเลื่อนควบคุม.

เมื่อเลือก Icon ให้ตั้งค่าดังนี้:
- BackgroundTransparency = 1 (โปร่งใสเต็มที่)
- Size = 2.5, 0, 2.5, 0 (250% สูงของกรอบหลักเมื่อจำกัดอัตราส่วน)
- Image = rbxassetid://90019827067389 (ID ของทรัพย์สินโน้ตเสียงและสัญลักษณ์ "ระเบิด")
แทรก UIAspectRatioConstraint ลงใน Icon และปล่อยให้คุณสมบัติเป็นค่าเริ่มต้น (1:1 ความกว้างต่อความสูง).


กรอบช่วง
โดยตรงทางด้านขวาของ ไอคอน ส่วนที่โต้ตอบของตัวเลื่อนควรถูกเก็บภายใน Frame อื่น

แทรก Frame ใหม่ลงในกรอบ EffectsVolumeSlider และเปลี่ยนชื่อเป็น SliderFrame โดยต้องเป็น ผู้พี่น้อง โดยตรงของ UIListLayout ตัวปรับเลย์เอาต์

เมื่อเลือก SliderFrame ให้ตั้งค่าดังนี้:
- BackgroundColor3 = 0 (สีดำ)
- BackgroundTransparency = 0.75 (โปร่งใส 25%)
- LayoutOrder = 1
- Size = 1, 0, 1, 0 (100% ความกว้าง/ความสูงของกรอบหลัก)
แทรกตัวปรับแต่งต่อไปนี้ลงใน SliderFrame:
- UIStroke โดยมีคุณสมบัติ Color ตั้งค่าเป็น 0, Thickness เป็น 3 และ Transparency เป็น 0.25 (โปร่งใส 75% สีดำ)

ตัวจัดการโต้ตอบ
ด้วย ตัวเก็บตัวเลื่อน ที่สร้างขึ้นแล้ว คุณสามารถสร้าง ด้ามจับที่ลากได้ สำหรับผู้เล่นเพื่อทำการโต้ตอบในระหว่างการเล่นเกม

แทรก Frame ใหม่ลงในตัวเก็บ SliderFrame และเปลี่ยนชื่อเป็น Handle.

เมื่อเลือก Handle ให้ตั้งค่าดังนี้:
- AnchorPoint = 0.5 (จุดยึดกลาง)
- Position = 0.5, 0, 0.5, 0 (ตรงกลางในแนวนอนและแนวตั้งของกรอบหลัก)
- Size = 1.2, 0, 1.2, 0 (120% สูงของกรอบหลักเมื่อจำกัดอัตราส่วน)
- ZIndex = 3 (การจัดเรียงด้ามจับให้เลเยอร์อยู่ข้างหน้าองค์ประกอบของตัวเลื่อนอื่น ๆ)
แทรกโมดูลต่อไปนี้ลงใน Handle:
- UIAspectRatioConstraint โดยมีคุณสมบัติเริ่มต้น (1:1 ความกว้างต่อความสูง)
แทรกวัตถุ UIDragDetector ลงใน Handle วัตถุที่สะดวกนี้ช่วยให้เกิดการโต้ตอบและกระตุ้นการโต้ตอบกับองค์ประกอบ UI 2D

ตั้งค่าคุณสมบัติเหล่านี้สำหรับ UIDragDetector ใหม่:
- ResponseStyle = Scale (เคลื่อนที่ด้วยค่าอัตราส่วนของตำแหน่งของผู้ตรวจจับที่อยู่ในพ่อของมัน)
เพื่อให้แน่ใจว่าช่วงการลากเชิงเส้นของดรัมจับถูกจำกัดให้กับตัวเก็บของมัน ให้เชื่อมโยงคุณสมบัติ BoundingUI เข้ากับตัวเก็บ SliderFrame:
- เลือก UIDragDetector.
- คลิกที่คุณสมบัติ BoundingUI ในหน้าต่าง Properties.
- กลับไปที่หน้าต่าง Explorer คลิกที่ SliderFrame ซึ่งเป็นพ่อของดรัมจับ

การเชื่อมโยงของ BoundingUI จะสะท้อนตัวเก็บ SliderFrame:

หากคุณทดสอบการเล่นประสบการณ์ในขณะนี้ คุณจะสามารถลากด้ามจับไปทางซ้ายและขวาภายในตัวเก็บของมัน:
การเติมด้านใน
เพื่อบ่งบอกให้ชัดเจนยิ่งขึ้นว่าตัวเลื่อนควบคุมช่วง 0% ถึง 100% คุณสามารถเพิ่ม การเติมด้านใน ทางด้านซ้ายของตัวเก็บซึ่งจะซิงค์กับตำแหน่งที่แตกต่างของด้ามจับ

แทรก Frame ใหม่ลงในตัวเก็บ SliderFrame และเปลี่ยนชื่อเป็น InnerFill.

ตั้งค่าคุณสมบัติสำหรับกรอบ InnerFill ดังนี้:
- AnchorPoint = 0, 0.5 (ขอบซ้ายและแนวกลาง)
- BackgroundColor3 = [0, 150, 255] (สีน้ำเงินที่เข้ากับด้ามจับของตัวเลื่อน)
- BackgroundTransparency = 0.35 (โปร่งใส 65%)
- Position = 0, 0, 0.5, 0
- Size = 0.5, 0, 1, 0 (ความกว้าง 50% และความสูง 100% ของกรอบหลัก)
- ZIndex = 2 (เลเยอร์อยู่ข้างหน้าเลเยอร์แม่ของตัวเก็บ/ขอบ)
เพื่อให้ตรงกับรูปทรง "พิล" ของตัวเก็บหลัก SliderFrame ให้แทรกตัวปรับ UICorner และตั้งค่า CornerRadius เป็น 0.5, 0.



ทำซ้ำตัวเลื่อน
ด้วย ตัวเลื่อนแรก ที่สร้างขึ้นแล้ว คุณสามารถทำซ้ำได้ง่าย ๆ และเปลี่ยนแปลงบางด้านการมองเพื่อลดนัยยะใหม่ ในกรณีนี้คือตัวระดับเสียงของเสียงพื้นหลังที่มีสัญลักษณ์เป็นโน้ตเพลง

เลือก EffectsVolumeSlider ที่สมบูรณ์

ทำการทำซ้ำ (CtrlD หรือ ⌘D) จากนั้นเปลี่ยนชื่อซ้ำเป็น BackgroundVolumeSlider.

เปลี่ยนตำแหน่งของตัวเลื่อนใหม่ให้เป็น Position เป็น 0.5, 0, 0.7, 0 เพื่อย้ายมันไปด้านล่างของตัวเลื่อนแรก.

ขยายสาขาระดับบนสุดของ BackgroundVolumeSlider เลือก Icon label ภาพและเปลี่ยนคุณสมบัติ Image เป็น rbxassetid://101125859760167 (ID ของสัญลักษณ์โน้ตเพลง).



เลือกกรอบ InnerFill ภายใน SliderFrame และเปลี่ยนคุณสมบัติ BackgroundColor3 เป็นสีม่วงเดียวกัน ([255, 0, 125]).



สร้างปุ่มปิด
องค์ประกอบสุดท้ายของเมนูตั้งค่าสคือ ปุ่มปิด ซึ่งให้ผู้เล่นมีการป้อนข้อมูลเพิ่มเติมในการปิดเมนู (ปุ่ม SettingsButton ที่อยู่กลางด้านบนจะทำหน้าที่เดียวกัน)

เมื่อเลือก CloseButton แล้วให้ตั้งค่าดังนี้:
- AnchorPoint = 1, 0 (มุมบนขวา)
- BackgroundTransparency = 1 (โปร่งใสเต็มที่)
- Position = 1, -10, 0, 10 (100 พิกเซลที่ยื่นออกจากมุมบนขวา)
- Size = 0.15, 0, 0.15, 0 (15% ของความสูงของกรอบเมื่อจำกัดอัตราส่วน)
- Image = rbxassetid://5577404210 (ID ของสัญลักษณ์ปิด)
- ImageTransparency = 0.25 (โปร่งใส 75%)
สร้างโมดูลควบคุม
โครงสร้าง โมดูลควบคุม ที่สามารถขยายได้ช่วยให้การจัดการ UI อินเทอร์แอคทีฟมีความลื่นไหลมากขึ้นกว่าเมื่อมีสคริปต์รายตัวที่วางอยู่ในแต่ละวัตถุ ModuleScripts จะทำให้ฟังก์ชันนี้ขยายได้ง่ายโดยให้คุณใช้โค้ดซ้ำระหว่างสคริปต์ในแต่ละด้านของพรมแดนหลัก/ลูกค้าหรือใกล้เคียง
ตัวควบคุมวัตถุที่มีสถานะ
โมดูลตัวควบคุมวัตถุที่มีสถานะนี้ช่วยให้คุณเพิ่มพฤติกรรมให้กับวัตถุ UI เช่น SettingsButton และ SettingsMenu และสลับ/ไล่ระดับระหว่างสถานะต่าง ๆ ได้อย่างง่ายดาย ในการสร้างโมดูล:

วางโค้ดต่อไปนี้ภายในโมดูล:
StatefulObjectControllerlocal TweenService = game:GetService("TweenService")local StatefulObjectController = {}StatefulObjectController.__index = StatefulObjectControllerexport type StateName = stringexport type State = {transition: TweenInfo,properties: { [string]: any },}function StatefulObjectController.hydrate(props: {object: Instance,states: { [StateName]: State },initialStateName: StateName})local object, states, initialStateName = props.object, props.states, props.initialStateNamelocal self = setmetatable({states = states,currentStateName = initialStateName,tweens = {},}, StatefulObjectController)-- Create tweens for reuse to avoid making new tweens every time state is changedfor stateName, state in states doself.tweens[stateName] = TweenService:Create(object, state.transition, state.properties)endself:setState(self.currentStateName)return selfendfunction StatefulObjectController:setState(stateName: StateName)local stateTween: Tween = self.tweens[stateName]if not stateTween thenwarn(string.format("Attempted to set %s to unknown state '%s'", self.object:GetFullName(), stateName))returnendself.currentStateName = stateName-- Make sure other tweens aren't conflictingfor _, tween in self.tweens dotween:Cancel()endstateTween:Play()endreturn StatefulObjectControllerคำอธิบายโค้ดสาย วัตถุประสงค์ 6‑10 กำหนดและส่งออกประเภท Luau เพื่อปรับปรุงการทำงานอัตโนมัติและการตรวจสอบข้อผิดพลาดเมื่อใช้โมดูลนี้. 12‑33 ฟังก์ชันที่ใช้ในการเริ่มต้นและเพิ่มพฤติกรรมให้กับวัตถุ UI ที่มีสถานะ โดยรับ GuiObject เป็น object ตารางของสถานะและข้อมูลที่เกี่ยวข้อง TweenInfo และชื่อสถานะแรก ภายในฟังก์ชันนี้ สาย 26‑28 สร้าง Tweens สำหรับแต่ละสถานะ และสาย 30 จะเรียกฟังก์ชัน setState() ของโมดูลเพื่อตั้งค่าวัตถุให้เป็นสถานะแรก. 35‑50 ฟังก์ชันที่ใช้ในการตั้งค่า/เปลี่ยนสถานะของวัตถุที่มีสถานะ ภายในฟังก์ชันนี้ สาย 42 ตั้งค่า currentStateName ของวัตถุให้เป็นสถานะที่จะตั้งค่า สาย 45‑47 ยกเลิก tweens ที่กำลังดำเนินการอยู่เพื่อป้องกันความขัดแย้ง และสาย 49 ทำให้ tween(s) ของสถานะทำงาน.
ตัวควบคุมตัวเลื่อน
โมดูลเพิ่มเติมในการเริ่มต้นและควบคุมตัวเลื่อนเสียงสองตัวนี้ ยังอนุญาตให้คุณเชื่อมต่อฟังก์ชันคืนค่ากับแต่ละตัวเลื่อนเพื่อตรวจจับการเข้าใช้งานของผู้เล่นกับตัวเลื่อนและปรับเปลี่ยนตามที่ต้องการในประสบการณ์
แทรก ModuleScript ลงในตัวเก็บ ReplicatedStorage และเปลี่ยนชื่อเป็น SliderController.

วางโค้ดต่อไปนี้ภายในโมดูล:
SliderControllerlocal SliderController = {}SliderController.__index = SliderControllerexport type Value = numberexport type OnChanged = (Value) -> ()function SliderController.hydrate(props: {object: Instance,onChanged: OnChanged,initialValue: Value?})local object, onChanged, initialValue = props.object, props.onChanged, props.initialValuelocal handle = object:FindFirstChild("Handle", true)if not handle thenwarn(string.format("Attempted to hydrate slider %s but couldn't find Handle", object:GetFullName()))endlocal innerFill = object:FindFirstChild("InnerFill", true)if not innerFill thenwarn(string.format("Attempted to hydrate slider %s but couldn't find InnerFill", object:GetFullName()))endlocal dragDetector = handle:FindFirstChildWhichIsA("UIDragDetector")if not dragDetector thenwarn(string.format("Attempted to hydrate slider %s but couldn't find UIDragDetector", object:GetFullName()))endlocal self = setmetatable({handle = handle,innerFill = innerFill,dragDetector = dragDetector,value = initialValue or 0.5,onChanged = onChanged,}, SliderController)-- Set initial valueself:setValue(self.value)-- Connect detector to player manipulationself.dragConnection = dragDetector.DragContinue:Connect(function()self:setValue(handle.Position.X.Scale)end)return selfendfunction SliderController:setValue(value: Value)local clampedValue = math.clamp(value, 0, 1)self.value = clampedValue-- Update the handle position and inner frame size to matchself.handle.Position = UDim2.fromScale(clampedValue, 0.5)self.innerFill.Size = UDim2.fromScale(clampedValue, 1)-- Run the user's callback with the latest valuelocal changeSuccess, changeResult = pcall(self.onChanged, clampedValue)if not changeSuccess thenwarn("Error in slider callback:", changeResult)endendreturn SliderControllerคำอธิบายโค้ดสาย วัตถุประสงค์ 7‑46 ฟังก์ชันการเริ่มต้นและเพิ่มพฤติกรรมให้กับองค์ประกอบตัวเลื่อน โดยรับ Frame ของตัวเลื่อนเป็น object ฟังก์ชันย้อนกลับ onChanged เพื่อดำเนินการเมื่อมีการเปลี่ยนแปลงตัวเลื่อน และค่าที่เริ่มต้นสำหรับตำแหน่งด้ามจับของตัวเลื่อน ภายในฟังก์ชัน สาย 14‑27 จะยืนยันว่ามีการควบคุม Handle, Inner fill, และ UIDragDetector มีอยู่ สาย 38 จะเรียกฟังก์ชัน setValue() ของโมดูลและสาย 41‑43 จะเชื่อมต่อเหตุการณ์ DragContinue ของตัวตรวจจับเข้ากับฟังก์ชัน setValue() ของโมดูล (ดูข้อมูลเพิ่มเติมได้ด้านล่าง). 48‑61 ฟังก์ชันที่ใช้ในการตั้งค่า/เปลี่ยนค่าให้กับตัวเลื่อน ภายในฟังก์ชัน สาย 53‑54 จะทำให้ตำแหน่งของด้ามจับและขนาดของกรอบด้านในซิงโครไนซ์ และสาย 57 จะส่งค่าที่เปลี่ยนให้กับฟังก์ชันย้อนกลับเพื่อให้คุณสามารถใช้ค่าดังกล่าวได้ตามต้องการ.
สร้างสคริปต์การตั้งค่า
ด้วย ปุ่มตั้งค่า และ เมนูตั้งค่า ที่เสร็จสมบูรณ์แล้ว คุณสามารถเชื่อมโยงทุกอย่างเข้าด้วยกันด้วยสคริปต์เดียวที่ใช้ โมดูลควบคุม.
แทรก LocalScript ใหม่ลงใน HUDContainer และเปลี่ยนชื่อเป็น SettingsScript เพื่อบรรยายถึงวัตถุประสงค์ของมัน โปรดทราบว่าสคริปต์นี้ควรอยู่ในระดับเดียวกัน (ผู้พี่น้อง) กับ SettingsMenu และ SettingsButton ซึ่งเป็นวัตถุ UI ระดับบนที่มันจะจัดการ.

วางโค้ดต่อไปนี้ภายในสคริปต์:
SettingsScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local SoundService = game:GetService("SoundService")local SliderController = require(ReplicatedStorage.SliderController)local StatefulObjectController = require(ReplicatedStorage.StatefulObjectController)local HUDContainer = script.Parent-- Initialize settings buttonlocal settingsButton = StatefulObjectController.hydrate({object = HUDContainer:FindFirstChild("SettingsButton"),states = {menuOpen = {transition = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),properties = {Rotation = 45,},},menuClosed = {transition = TweenInfo.new(0.5, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),properties = {Rotation = 0,},},},initialStateName = "menuClosed"})-- Initialize settings menu framelocal settingsMenu = StatefulObjectController.hydrate({object = HUDContainer:FindFirstChild("SettingsMenu"),states = {menuOpen = {transition = TweenInfo.new(0.5, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out),properties = {Position = UDim2.fromScale(0.5, 0.5),Visible = true,},},menuClosed = {transition = TweenInfo.new(0),properties = {Position = UDim2.fromScale(0.5, 0.4),Visible = false,},},},initialStateName = "menuClosed"})-- Initialize effects volume sliderlocal effectsAudio = SoundService:FindFirstChild("Effects")local effectsVolumeSlider = SliderController.hydrate({object = HUDContainer:FindFirstChild("EffectsVolumeSlider", true),initialValue = effectsAudio and effectsAudio.Volume or 0.5,onChanged = function(value: SliderController.Value)if effectsAudio theneffectsAudio.Volume = valueendend,})-- Initialize background volume sliderlocal backgroundAudio = SoundService:FindFirstChild("Background")local backgroundVolumeSlider = SliderController.hydrate({object = HUDContainer:FindFirstChild("BackgroundVolumeSlider", true),initialValue = backgroundAudio and backgroundAudio.Volume or 0.5,onChanged = function(value: SliderController.Value)if backgroundAudio thenbackgroundAudio.Volume = valueendend,})-- Connect buttons to player interactionHUDContainer:FindFirstChild("SettingsButton").Activated:Connect(function()local targetState = if settingsButton.currentStateName == "menuClosed"then "menuOpen"else "menuClosed"settingsButton:setState(targetState)settingsMenu:setState(targetState)end)HUDContainer:FindFirstChild("CloseButton", true).Activated:Connect(function()settingsButton:setState("menuClosed")settingsMenu:setState("menuClosed")end)อ้างอิงจากส่วนเหล่านี้เพื่อสำรวจว่าสคริปต์ใช้โมดูลควบคุมอย่างไร:
ปุ่มตั้งค่าสาย 10-27 เริ่มต้นและเพิ่มพฤติกรรมให้กับ ปุ่มตั้งค่า ดังนี้:
สาย วัตถุประสงค์ 10‑11 อ้างอิงในท้องถิ่น settingsButton ถูกประกาศและเติมน้ำด้วยฟังก์ชัน StatefulObjectController.hydrate() และปุ่ม SettingsButton ภายใน HUDContainer ถูกอ้างถึงเป็นวัตถุในการเติมน้ำ. 12‑25 มีการส่งผ่านตาราง states ที่มีสองสถานะที่ไม่ซ้ำกัน คือ menuOpen และ menuClosed สถานะแต่ละสถานะมีการเปลี่ยนแปลงที่แจ้งให้ทราบ (ผ่าน TweenInfo) ว่าสถานะเฉพาะจะไปถึงคุณสมบัติเป้าหมายอย่างไรที่กำหนดไว้ในตาราง properties ในกรณีนี้ menuOpen กำหนดการเปลี่ยนแปลงสถานะที่ 45° สำหรับ Rotation ของปุ่มพร้อมกับ Exponential tween เป็นเวลา ½ วินาที ในขณะที่ menuClosed จะคืนปุ่มไปยังการหมุนปกติที่ 0. 26 สถานะ เริ่มต้น ของปุ่มถูกตั้งค่าเป็น menuClosed (สามารถตั้งค่าได้ในชื่อสถานะใดๆ ที่อยู่ภายในตาราง states). ต่อไปในสคริปต์ (สาย 76-86) ปุ่มถูกเชื่อมต่อกับการโต้ตอบของผู้เล่นเพื่อกระตุ้นการเปลี่ยนแปลงสถานะ UI:
สาย วัตถุประสงค์ 76‑82 SettingsButton เชื่อมต่อกับเหตุการณ์ Activated ของ ชนิด GuiButton เพื่อเรียกฟังก์ชันที่ไม่ระบุชื่อ ภายในฟังก์ชันที่ไม่ระบุชื่อนี้ เส้น 77‑79 สลับค่าตัวแปร targetState ระหว่าง menuOpen และ menuClosed ต่อไปที่สาย 80 เรียกใช้ setState() เพื่อกำหนดสถานะให้กับปุ่มเป็น targetState และสาย 81 ก็ทำเช่นเดียวกันกับ SettingsMenu เพื่อให้เปิดหรือปิดด้วยการเปิดใช้งาน SettingsButton. 83‑86 CloseButton เชื่อมต่อกับเหตุการณ์ Activated เพื่อเรียกฟังก์ชันที่ไม่ระบุชื่อซึ่งตั้งค่าสถานะของทั้ง SettingsButton และ SettingsMenu เป็น menuClosed. เมนูตั้งค่าสาย 30-49 เริ่มต้นและเพิ่มพฤติกรรมให้กับ เมนูตั้งค่า ดังนี้:
บรรทัด วัตถุประสงค์ 30‑31 มีการประกาศอ้างอิงท้องถิ่น settingsMenu และมีการเติมข้อมูลด้วยฟังก์ชัน StatefulObjectController.hydrate() และมีการอ้างอิงเฟรม SettingsMenu ภายใน HUDContainer เป็นวัตถุที่ต้องการเติมข้อมูล 32‑46 คล้ายกับปุ่มตั้งค่า มีการส่งตาราง states ที่มีสถานะเฉพาะสองสถานะ คือ menuOpen และ menuClosed ที่นี่ menuOpen จะประกาศการเปลี่ยนแปลงสถานะเป็น UDim2.fromScale(0.5, 0.5) สำหรับ Position ของเฟรมพร้อมกับการ Tween สไตล์การเคลื่อนไหว Bounce เป็นระยะเวลา ½ วินาที ซึ่งยังมีสถานะ Visible เป็น true ในทางตรงกันข้าม menuClosed จะประกาศการเปลี่ยนแปลงสถานะตำแหน่งเป็น UDim2.fromScale(0.5, 0.4) และ Visible เป็น false แต่ TweenInfo ที่มีระยะเวลา 0 ในบรรทัด 41 จะทำให้การเปลี่ยนแปลงสถานะเกิดขึ้นทันที 48 สถานะเริ่มต้นของเฟรมถูกตั้งค่าเป็น menuClosed ในสคริปต์ (บรรทัด 76-86) เมนูการตั้งค่าจะเชื่อมโยงกับการโต้ตอบของผู้เล่น:
บรรทัด วัตถุประสงค์ 81 ตั้งค่า targetState เดียวกันสำหรับ SettingsMenu ให้อัพเดตเมื่อมีการเปิดใช้งาน SettingsButton 85 ตั้งสถานะของ SettingsMenu เป็น menuClosed เมื่อมีการเปิดใช้งาน CloseButton ตัวเลื่อนระดับเสียงบรรทัด 51-73 สร้างและแนบพฤติกรรมกับ EffectsVolumeSlider และ BackgroundVolumeSlider ดังนี้:
บรรทัด วัตถุประสงค์ 52 ตั้งค่าอ้างอิงท้องถิ่นไปยัง Effects SoundGroup ภายใน SoundService ซึ่ง SoundGroup ช่วยให้คุณเชื่อมโยงเสียงหลายๆ เสียง (Sounds) และควบคุมระดับเสียงของเสียงแต่ละเสียงในกลุ่มผ่านคุณสมบัติ Volume ของกลุ่ม 53‑54 มีการประกาศอ้างอิงท้องถิ่น effectsVolumeSlider และมีการเติมข้อมูลด้วยฟังก์ชัน SliderController.hydrate() โดยมีเฟรม EffectsVolumeSlider ภายใน HUDContainer ⟩ SettingsMenu เป็นวัตถุที่ต้องการเติมข้อมูล โปรดทราบว่าพารามิเตอร์ที่สองของ true สำหรับ FindFirstChild() จะแจ้งให้เมธอดมองหาแบบย้อนกลับในสาขา HUDContainer เพื่อตรวจหา EffectsVolumeSlider 55 ค่าตั้งต้นของตัวเลื่อนถูกตั้งค่าเป็น Volume ปัจจุบันของกลุ่มเสียง Effects หรือ 0.5 เป็นค่าเริ่มต้น 56‑60 สร้างฟังก์ชัน callback เพื่อนำการเปลี่ยนแปลงค่าตัวเลื่อนไปใช้กับระดับเสียงของกลุ่มเสียง Effects 64‑73 โดยพื้นฐานแล้วเหมือนกับบรรทัด 52-61 ยกเว้นการเติมข้อมูลเฟรม BackgroundVolumeSlider ภายใน HUDContainer ⟩ SettingsMenu และนำการเปลี่ยนแปลงค่าตัวเลื่อนไปใช้กับระดับเสียงของกลุ่มเสียง Background
ด้วย SettingsScript ที่อยู่ในสถานที่ ประสบการณ์ตอนนี้มี UI แบบโต้ตอบที่ทำงานได้อย่างสมบูรณ์ ซึ่งเชื่อมโยงชุดของวัตถุ UI ที่เกี่ยวข้องกับการโต้ตอบของผู้เล่น











