อินสแตนซ์ DragDetector ช่วยอำนวยความสะดวกและกระตุ้นการโต้ตอบกับวัตถุ 3D ในเกม เช่น การเปิดประตูและลิ้นชัก การเลื่อนชิ้นส่วนไปรอบ ๆ การจับและโยนลูกโบว์ลิ่ง การดึงกลับและยิงหนังสติ๊ก และอื่น ๆ อีกมากมาย คุณสมบัติหลักประกอบด้วย:
วาง DragDetector ไว้ใต้ BasePart หรือ Model ใด ๆ เพื่อ ทำให้มันลากได้ ผ่านการป้อนข้อมูลทั้งหมด (เมาส์, การสัมผัส, เกมแพด, และ VR) โดยไม่ต้องเขียนโค้ดแม้แต่บรรทัดเดียว
เลือกจากหลาย สไตล์การลาก กำหนดวิธีที่วัตถุ ตอบสนองต่อการเคลื่อนไหว และเลือกที่จะใช้ ขีดจำกัดแกนหรือการเคลื่อนไหว
สคริปต์สามารถ ตอบสนองต่อการจัดการวัตถุที่ถูกลาก เพื่อขับเคลื่อน UI หรือทำการตัดสินใจเชิงตรรกะ เช่น การปรับระดับแสงในห้องตามสวิตช์ผนังที่เลื่อน
ผู้เล่นสามารถจัดการชิ้นส่วนหรือโมเดลที่ยึดติดและมันจะอยู่ในตำแหน่งที่คุณวางไว้เมื่อปล่อย
DragDetectors ทำงานใน Studio ตราบใดที่คุณ ไม่ ใช้เครื่องมือ เลือก, ย้าย, ปรับขนาด, หรือ หมุน ทำให้การทดสอบและปรับวัตถุที่ลากได้ง่ายขึ้นในขณะแก้ไข
ทำให้วัตถุสามารถลากได้
เพื่อทำให้ชิ้นส่วนหรือโมเดลใด ๆ สามารถลากได้ เพียงแค่เพิ่ม DragDetector เป็นลูกหลานโดยตรง
จากเมนู ให้แทรก DragDetector

โดยค่าเริ่มต้น วัตถุจะสามารถลากได้ในระนาบพื้น แต่คุณสามารถปรับแต่ง DragStyle ของมัน กำหนดวิธีที่มัน ตอบสนองต่อการเคลื่อนไหว และเลือกที่จะใช้ ขีดจำกัดแกนหรือการเคลื่อนไหว
ปรับแต่งตัวตรวจจับการลาก
สไตล์การลาก
DragDetectors จะจับการเคลื่อนไหวของเคอร์เซอร์ไปยังเส้นและระนาบเสมือนเพื่อคำนวณการเคลื่อนไหว 3D ที่เสนอ ผ่านคุณสมบัติ DragStyle คุณสามารถเลือกจากการแมพที่แตกต่างกันเพื่อตอบสนองความต้องการของคุณ ตัวอย่างเช่น TranslatePlane จะผลิตการแปลในระนาบเสมือน ในขณะที่ RotateAxis จะผลิตการหมุนรอบแกนเสมือน
| การตั้งค่า | คำอธิบาย |
|---|---|
| TranslateLine | การเคลื่อนไหว 1D ตาม Axis ของตัวตรวจจับ โดยค่าเริ่มต้นคือแกน Y ของโลก |
| TranslatePlane | การเคลื่อนไหว 2D ในระนาบที่ตั้งฉากกับ Axis ของตัวตรวจจับ โดยค่าเริ่มต้นคือระนาบ XZ ของโลก |
| TranslatePlaneOrLine | การเคลื่อนไหว 2D ในระนาบที่ตั้งฉากกับ Axis ของตัวตรวจจับ และเมื่อ ตัวปรับ ถูกเปิดใช้งาน จะมีการเคลื่อนไหว 1D ตาม Axis ของตัวตรวจจับ |
| TranslateLineOrPlane | การเคลื่อนไหว 1D ตาม Axis ของตัวตรวจจับ และเมื่อ ตัวปรับ ถูกเปิดใช้งาน จะมีการเคลื่อนไหว 2D ในระนาบที่ตั้งฉากกับ Axis ของตัวตรวจจับ |
| TranslateViewPlane | การเคลื่อนไหว 2D ในระนาบที่ตั้งฉากกับมุมมองของกล้อง ในโหมดนี้ ระนาบจะถูกอัปเดตอย่างต่อเนื่อง แม้ในขณะที่ลาก และจะหันหน้าไปทางมุมมองปัจจุบันของกล้องเสมอ |
| RotateAxis | การหมุนรอบ Axis ของตัวตรวจจับ โดยค่าเริ่มต้นคือแกน Y ของโลก |
| RotateTrackball | การหมุนแบบ Trackball ซึ่งสามารถปรับแต่งเพิ่มเติมผ่านคุณสมบัติ TrackballRadialPullFactor และ TrackballRollFactor |
| BestForDevice | TranslatePlaneOrLine สำหรับเมาส์และเกมแพด; TranslatePlane สำหรับการสัมผัส; 6DOF สำหรับ VR |
| Scriptable | คำนวณการเคลื่อนไหวที่ต้องการผ่านฟังก์ชันที่กำหนดเองซึ่งจัดเตรียมผ่าน SetDragStyleFunction() |
ทิศทางการลาก
โดยค่าเริ่มต้น การเคลื่อนไหว 3D และ DragStyle ที่เกี่ยวข้องจะแมพไปยังพื้นที่โลก อย่างไรก็ตาม คุณอาจต้องการเปลี่ยน ReferenceInstance, Orientation, หรือ Axis เช่น เมื่อสร้างตัวตรวจจับการลากใน โมเดลที่มีชิ้นส่วนปรับได้
| คุณสมบัติ | คำอธิบาย | ค่าเริ่มต้น |
|---|---|---|
| ReferenceInstance | อินสแตนซ์ที่จุดหมุนให้ กรอบอ้างอิง สำหรับตัวตรวจจับการลาก DragFrame จะถูกแสดงตามกรอบอ้างอิงนี้ซึ่งสามารถเรียกคืนได้ผ่าน GetReferenceFrame() หากกรอบอ้างอิงเป็น nil การแปลจะอยู่ในทิศทางของ (หรือในระนาบที่ตั้งฉากกับ) คุณสมบัติ Axis ในพื้นที่โลก | nil |
| Orientation | ระบุการหมุน YXZ ของแกนการเคลื่อนไหวสัมพันธ์กับกรอบอ้างอิง (ไม่เปลี่ยนการวางแน่ของกรอบอ้างอิงเอง) การแปลเชิงเส้นและการหมุนแกนจะอยู่บนแกน Y ที่ปรับเปลี่ยนนี้ และการแปลในระนาบ XZ การเปลี่ยนแปลงค่าดังกล่าวจะอัปเดต Axis โดยอัตโนมัติและในทางกลับกัน | (0, 0, 0) |
| Axis | แกนหลักของการเคลื่อนไหวที่แสดงสัมพันธ์กับกรอบอ้างอิง การเปลี่ยนแปลงค่าดังกล่าวจะอัปเดต Orientation โดยอัตโนมัติและในทางกลับกัน | (0, 1, 0) |
การตอบสนองต่อการเคลื่อนไหว
คุณสมบัติ ResponseStyle ระบุว่าวัตถุจะตอบสนองต่อการเคลื่อนไหวที่เสนออย่างไร ขึ้นอยู่กับว่าวัตถุเป็น Anchored หรือไม่
| การตั้งค่า | พฤติกรรมที่ยึดติด | พฤติกรรมที่ไม่ยึดติด |
|---|---|---|
| Geometric | ทั้งในเกมที่กำลังทำงานและในโหมดแก้ไข Studio ตำแหน่ง/การวางแน่ของวัตถุที่ยึดติดจะถูกอัปเดตเพื่อสะท้อนการเคลื่อนไหวที่เสนออย่างแม่นยำ | สำหรับวัตถุที่ไม่ยึดติด พฤติกรรมจะเหมือนกับวัตถุที่ยึดติด อย่างไรก็ตาม ในเกมที่กำลังทำงาน วัตถุจะถูกยึดติดในตอนเริ่มการลากและจะถูกคืนสู่สถานะไม่ยึดติดเมื่อปล่อยการลาก |
| Physical | วัตถุที่ยึดติดจะมีพฤติกรรมเริ่มต้นเป็น Geometric เนื่องจากไม่ได้รับผลกระทบจากแรง | วัตถุที่ไม่ยึดติดจะถูกเคลื่อนที่โดย แรงที่จำกัด ที่พยายามนำมันไปยังตำแหน่งและ/หรือการวางแน่ที่ต้องการตามการเคลื่อนไหวที่เสนอ |
| Custom | วัตถุจะไม่เคลื่อนที่เลย แต่ DragFrame จะยังคงถูกอัปเดตและคุณสามารถ ตอบสนองต่อการจัดการการลาก ได้ตามที่คุณต้องการ | (เหมือนกับที่ยึดติด) |
ขีดจำกัดแกนและการเคลื่อนไหว
โดยค่าเริ่มต้น ไม่มีขีดจำกัดในการเคลื่อนไหว 3D นอกเหนือจากข้อจำกัดที่มีอยู่ของ DragStyle หากจำเป็น คุณสามารถใช้ขีดจำกัดขั้นต่ำและสูงสุดสำหรับทั้งการแปลและการหมุน อย่างไรก็ตาม โปรดทราบว่าขีดจำกัดเหล่านี้ ไม่ใช่ ข้อจำกัด; มันเพียงแค่ขัดขวางความพยายามของตัวตรวจจับการลากในการสร้างการเคลื่อนไหวเพื่อให้ยังคงอยู่ภายในขีดจำกัด
| คุณสมบัติ | คำอธิบาย | ค่าเริ่มต้น |
|---|---|---|
| MinDragTranslation MaxDragTranslation | ขีดจำกัดการแปลการลากในแต่ละมิติ หาก MaxDragTranslation มากกว่า MinDragTranslation การแปลจะถูกจำกัดภายในช่วงนั้น | (0, 0, 0) |
| MinDragAngle MaxDragAngle | มีความเกี่ยวข้องเฉพาะเมื่อ DragStyle ถูกตั้งค่าเป็น RotateAxis หาก MaxDragAngle มากกว่า MinDragAngle การหมุนจะถูกจำกัดภายในช่วงนั้น | 0 |
สิทธิ์การลาก
สิทธิ์ของผู้เล่นในการโต้ตอบกับอินสแตนซ์ตัวตรวจจับการลากที่กำหนดสามารถระบุได้โดยคุณสมบัติ PermissionPolicy ซึ่งตั้งค่าเป็น Enum.DragDetectorPermissionPolicy.Everybody โดยค่าเริ่มต้น และสามารถเปลี่ยนเพื่อสนับสนุนการควบคุมสิทธิ์ที่เขียนสคริปต์ได้ตามที่แสดงในตัวอย่างโค้ด
| การตั้งค่า | คำอธิบาย |
|---|---|
| Nobody | ไม่มีผู้เล่นสามารถโต้ตอบกับ DragDetector ได้ |
| Everybody | ผู้เล่นทุกคนสามารถโต้ตอบกับ DragDetector ได้ |
| Scriptable | สิทธิ์การลากของผู้เล่นจะถูกกำหนดโดยฟังก์ชันที่ลงทะเบียนผ่าน SetPermissionPolicyFunction() ภายใต้การตั้งค่านี้ หากไม่สามารถลงทะเบียนฟังก์ชันหรือส่งคืนผลลัพธ์ที่ไม่ถูกต้อง จะป้องกันไม่ให้ผู้เล่นทุกคนลาก |
local dragDetector = script.Parent.DragDetector
dragDetector.PermissionPolicy = Enum.DragDetectorPermissionPolicy.Scriptable
dragDetector:SetPermissionPolicyFunction(function(player, part)
if player and player:GetAttribute("IsInTurn") then
return true
elseif part and not part:GetAttribute("IsDraggable") then
return false
else
return true
end
end)การตอบสนองทางฟิสิกส์
สมมติว่าสไตล์ การตอบสนอง ของตัวตรวจจับถูกตั้งค่าเป็น Physical และถูกนำไปใช้กับวัตถุที่ไม่ยึดติด วัตถุจะถูกเคลื่อนที่โดยแรงที่จำกัดซึ่งพยายามนำมันไปยังตำแหน่ง/การวางแน่ที่กำหนดโดยการเคลื่อนไหวที่เสนอ คุณสามารถปรับแต่งการตอบสนองทางฟิสิกส์เพิ่มเติมผ่านคุณสมบัติต่อไปนี้:
| คุณสมบัติ | คำอธิบาย | ค่าเริ่มต้น |
|---|---|---|
| ApplyAtCenterOfMass | เมื่อเป็น false แรงลากจะถูกใช้ที่จุดที่ผู้ใช้คลิก เมื่อเป็น true แรงจะถูกใช้ที่จุดศูนย์กลางของมวลของวัตถุ | false |
| MaxForce | แรงสูงสุดที่ใช้เพื่อให้วัตถุไปถึงเป้าหมาย | 10000000 |
| MaxTorque | แรงบิดสูงสุดที่ใช้เพื่อให้วัตถุไปถึงเป้าหมาย | 10000 |
| Responsiveness | ค่าที่สูงกว่าจะทำให้วัตถุไปถึงเป้าหมายได้เร็วขึ้น | 10 |
การป้อนข้อมูลตัวปรับ
โหมด DragStyle บางโหมดอนุญาตให้ผู้ใช้กดปุ่ม/คีย์ ตัวปรับ เพื่อจัดการวัตถุที่ถูกลากในวิธีที่แตกต่างกัน โดยค่าเริ่มต้น ตัวปรับคือ LeftControl บน PC, ButtonR1 บนเกมแพด, หรือ ButtonL2 บน VR คุณสามารถปรับแต่งตัวปรับเหล่านี้ผ่าน KeyboardModeSwitchKeyCode, GamepadModeSwitchKeyCode, หรือ VRSwitchKeyCode ของอินสแตนซ์ตัวตรวจจับการลาก
การทำซ้ำ
เมื่อคุณสมบัติ RunLocally เป็น false (ค่าเริ่มต้น) ไคลเอนต์จะตีความการป้อนข้อมูลทั้งหมดเพื่อผลิตข้อมูลที่ส่งไปยังเซิร์ฟเวอร์เพื่อทำการลาก ในโหมดนี้ สัญญาณเหตุการณ์ที่กำหนดเองทั้งหมดและฟังก์ชันที่ลงทะเบียนต้องอยู่ใน Scripts ของเซิร์ฟเวอร์
เมื่อคุณสมบัติ RunLocally เป็น true จะไม่มีเหตุการณ์ใด ๆ ถูกทำซ้ำไปยังเซิร์ฟเวอร์ สัญญาณเหตุการณ์ที่กำหนดเองทั้งหมดและฟังก์ชันที่ลงทะเบียนต้องอยู่ใน LocalScripts ของไคลเอนต์และคุณต้องใช้ เหตุการณ์ระยะไกล เพื่อแพร่กระจายการเปลี่ยนแปลงที่จำเป็นไปยังเซิร์ฟเวอร์
การตอบสนองของสคริปต์ต่อการคลิกและการลาก
ผ่าน สัญญาณเหตุการณ์, การเปลี่ยนแปลงคุณสมบัติ, สไตล์การลาก Scriptable, และฟังก์ชันที่กำหนดเอง สคริปต์สามารถตอบสนองต่อการจัดการวัตถุที่ถูกลากเพื่อขับเคลื่อน UI หรือทำการตัดสินใจเชิงตรรกะ เช่น การปรับระดับแสงในห้องตามสวิตช์ผนังที่เลื่อน
สัญญาณเหตุการณ์
ผ่านสัญญาณเหตุการณ์ต่อไปนี้ คุณสามารถตรวจจับเมื่อผู้ใช้เริ่มต้น ดำเนินการ และสิ้นสุดการลากวัตถุ
| เหตุการณ์ | คำอธิบาย |
|---|---|
| DragStart | เกิดขึ้นเมื่อผู้ใช้เริ่มลากวัตถุ |
| DragContinue | เกิดขึ้นเมื่อผู้ใช้ดำเนินการลากวัตถุต่อไปหลังจากที่ DragStart ถูกเริ่มต้น |
| DragEnd | เกิดขึ้นเมื่อผู้ใช้หยุดลากวัตถุ |
local dragDetector = script.Parent.DragDetector
local highlight = Instance.new("Highlight")
highlight.Enabled = false
highlight.Parent = script.Parent
dragDetector.DragStart:Connect(function()
highlight.Enabled = true
end)
dragDetector.DragContinue:Connect(function()
end)
dragDetector.DragEnd:Connect(function()
highlight.Enabled = false
end)การเปลี่ยนแปลงกรอบการลาก
นอกจาก สัญญาณเหตุการณ์ แล้ว คุณยังสามารถตรวจสอบการเปลี่ยนแปลงใน DragFrame ของตัวตรวจจับได้โดยตรง
local dragDetector = script.Parent.DragDetector
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
local currentDragTranslation = dragDetector.DragFrame.Position
print(currentDragTranslation)
end)สไตล์การลากที่เขียนสคริปต์
หากคุณตั้งค่าสไตล์ DragStyle ของตัวตรวจจับเป็น Scriptable คุณสามารถจัดเตรียมฟังก์ชันของคุณเองที่รับ Ray และส่งคืน CFrame ในพื้นที่โลก ตัวตรวจจับจะเคลื่อนที่การเคลื่อนไหวเพื่อให้วัตถุที่ถูกลากไปยังตำแหน่ง/การวางแน่ที่กำหนดเองนั้น
local Workspace = game:GetService("Workspace")
local dragDetector = script.Parent.DragDetector
dragDetector.DragStyle = Enum.DragDetectorDragStyle.Scriptable
local cachedHitPoint = Vector3.zero
local cachedHitNormal = Vector3.yAxis
local function followTheCursor(cursorRay)
-- ยกเว้นวัตถุที่ถูกลากจากการตรวจจับ raycast
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {dragDetector.Parent}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local hitPoint = Vector3.zero
local hitNormal = Vector3.yAxis
local raycastResult = Workspace:Raycast(cursorRay.Origin, cursorRay.Direction, raycastParams)
if raycastResult then
hitPoint = raycastResult.Position
hitNormal = raycastResult.Normal.Unit
else
hitPoint = cachedHitPoint
hitNormal = cachedHitNormal
end
cachedHitPoint = hitPoint
cachedHitNormal = hitNormal
local lookDir1 = hitNormal:Cross(Vector3.xAxis)
local lookDir2 = hitNormal:Cross(Vector3.yAxis)
local lookDir = if lookDir1.Magnitude > lookDir2.Magnitude then lookDir1.Unit else lookDir2.Unit
return CFrame.lookAt(hitPoint, hitPoint + lookDir, hitNormal)
end
dragDetector:SetDragStyleFunction(followTheCursor)ฟังก์ชันข้อจำกัดที่กำหนดเอง
ตัวตรวจจับการลากไม่มีข้อกำหนดการเคลื่อนไหวในตัวเกี่ยวกับกริดและการติด แต่คุณสามารถลงทะเบียนฟังก์ชันข้อจำกัดที่กำหนดเองเพื่อแก้ไข DragFrame ของตัวตรวจจับก่อนที่จะนำไปใช้ ตัวอย่างเช่น คุณสามารถรักษาการเคลื่อนไหวบนกริดโดยการปัดตำแหน่งให้เป็นจำนวนที่เป็นทวีคูณของการเพิ่มกริด หรือจำลองเกมหมากรุกด้วยกฎการเคลื่อนไหวที่ถูกต้องตามกฎหมายสำหรับแต่ละชิ้น
local dragDetector = script.Parent.DragDetector
local startPartPosition = nil
local SNAP_INCREMENT = 4
dragDetector.DragStart:Connect(function()
startPartPosition = script.Parent.Position
end)
dragDetector.DragEnd:Connect(function()
startPartPosition = nil
end)
local function snapToWorldGrid(proposedMotion)
if startPartPosition == nil then
return proposedMotion
end
local snapIncrement = SNAP_INCREMENT // 1
if snapIncrement < 1 then
return proposedMotion
end
local newWorldPosition = startPartPosition + proposedMotion.Position
local roundedX = ((newWorldPosition.X / snapIncrement + 0.5) // 1) * snapIncrement
local roundedY = ((newWorldPosition.Y / snapIncrement + 0.5) // 1) * snapIncrement
local roundedZ = ((newWorldPosition.Z / snapIncrement + 0.5) // 1) * snapIncrement
local newRoundedWorldPosition = Vector3.new(roundedX, roundedY, roundedZ)
return proposedMotion.Rotation + (newRoundedWorldPosition - startPartPosition)
end
local connection = dragDetector:AddConstraintFunction(2, snapToWorldGrid)
-- เมื่อต้องการ ให้ลบฟังก์ชันข้อจำกัดโดยการเรียก connection:Disconnect()การใช้งานตัวอย่าง
วัตถุทางกายภาพที่ไม่ยึดติด
การใช้งานพื้นฐานของตัวตรวจจับการลากคือเกมทรงตัวที่ผู้เล่นต้องค่อย ๆ เอาชิ้นส่วนออกและพยายามรักษาโครงสร้างให้ตั้งตรง ในโครงสร้างหอคอยต่อไปนี้ ชิ้นส่วนแต่ละชิ้นมี DragDetector เป็นลูกหลานที่มี DragStyle เริ่มต้นเป็น TranslatePlane เพื่อให้ผู้เล่นสามารถดึงชิ้นส่วนออกไปข้างนอกได้ แต่ไม่สามารถดึงขึ้นหรือลงได้
โมเดลที่ยึดติดพร้อมชิ้นส่วนที่ปรับได้
คุณสามารถสร้างและแชร์โมเดลที่ยึดติดเป็นหลัก แต่มีชิ้นส่วน/โมเดลลูกหลานหนึ่งหรือมากกว่าที่ผู้เล่นสามารถลากได้ ตัวอย่างเช่น โต๊ะต่อไปนี้มีลิ้นชักสองลิ้นชักที่ผู้เล่นสามารถเปิดเพื่อดูสิ่งที่อยู่ข้างใน
ตัวตรวจจับการลากและข้อจำกัด
คุณสามารถรวมตัวตรวจจับการลากกับ Constraints เช่น หุ่นกระบอก ในการตั้งค่าต่อไปนี้ มือควบคุมจะถูกยึดติด ส่วนต่าง ๆ ของร่างกายจะไม่ยึดติด และข้อจำกัดจะยึดหุ่นกระบอกไว้ด้วยกัน การเคลื่อนที่ของมือด้วย DragStyle TranslateViewPlane ทำให้หุ่นกระบอกเต้นรำ และส่วนต่าง ๆ ของร่างกายยังสามารถเคลื่อนที่ได้ด้วยตัวตรวจจับการลาก ในขณะที่โมเดลยังคงรักษาความสมบูรณ์
อินเทอร์เฟซผู้ใช้ 3D
อินเทอร์เฟซผู้ใช้ 3D สามารถทำได้ง่าย ๆ ผ่านตัวตรวจจับการลาก เช่น การปรับความสว่างของ SpotLight ตามสวิตช์เลื่อนที่ปรับได้ คุณยังสามารถตรวจจับแกน X และ Z แยกกันเพื่อควบคุมสองแง่มุมที่แตกต่างกันของอินเทอร์เฟซผู้ใช้ 3D เช่น Size, Speed, และ Color ของ ParticleEmitter
local model = script.Parent
local slider = model.SliderPart
local originPart = model.OriginPart
local emitter = script.Parent.EmitterPart.ParticleEmitter
local dragDetector = slider.DragDetector
dragDetector.ReferenceInstance = originPart
dragDetector.MinDragTranslation = Vector3.zero
dragDetector.MaxDragTranslation = Vector3.new(10, 0, 10)
local dragRangeX = dragDetector.MaxDragTranslation.X - dragDetector.MinDragTranslation.X
local dragRangeZ = dragDetector.MaxDragTranslation.Z - dragDetector.MinDragTranslation.Z
local MIN_PARTICLE_SIZE = 1
local MAX_PARTICLE_SIZE = 1.5
local MIN_PARTICLE_SPEED = 2.5
local MAX_PARTICLE_SPEED = 5
local COLOR1 = Color3.fromRGB(255, 150, 0)
local COLOR2 = Color3.fromRGB(255, 0, 50)
local function updateParticles(emitter)
local dragFactorX = (dragDetector.DragFrame.Position.X - dragDetector.MinDragTranslation.X) / dragRangeX
local dragFactorZ = (dragDetector.DragFrame.Position.Z - dragDetector.MinDragTranslation.Z) / dragRangeZ
-- ปรับขนาดและความเร็วของอนุภาคตามปัจจัย X ของตัวตรวจจับการลาก
emitter.Size = NumberSequence.new{
NumberSequenceKeypoint.new(0, 0),
NumberSequenceKeypoint.new(0.1, MIN_PARTICLE_SIZE + ((MAX_PARTICLE_SIZE - MIN_PARTICLE_SIZE) * dragFactorX)),
NumberSequenceKeypoint.new(1, 0)
}
local speed = MIN_PARTICLE_SPEED + ((MAX_PARTICLE_SPEED - MIN_PARTICLE_SPEED) * dragFactorX)
emitter.Speed = NumberRange.new(speed, speed * 1.2)
-- ปรับสีของอนุภาคตามปัจจัย Z ของตัวตรวจจับการลาก
local color = COLOR2:Lerp(COLOR1, dragFactorZ)
emitter.Color = ColorSequence.new{
ColorSequenceKeypoint.new(0, color),
ColorSequenceKeypoint.new(1, color)
}
end
dragDetector:GetPropertyChangedSignal("DragFrame"):Connect(function()
updateParticles(emitter)
end)