ตัวตรวจจับลาก 3D

*เนื้อหานี้แปลโดยใช้ AI (เวอร์ชัน Beta) และอาจมีข้อผิดพลาด หากต้องการดูหน้านี้เป็นภาษาอังกฤษ ให้คลิกที่นี่

ตัวอย่าง DragDetector ช่วยอำนวยความสะดวกและส่งเสริมการโต้ตอบกับวัตถุ 3D ในประสบการณ์ เช่น เปิดประตูและลิ้นชัก เลื่อนชิ้นส่วนไปรอบๆ คว้าและโยนลูกบอลโบว์ล ดึงกลับและยิงปืนพก และอื่นๆ อีกมากมายคุณสมบัติสําคัญรวมถึง:

ทำให้วัตถุเป็นรูปแบบลากได้

เพื่อทำให้ส่วนหรือโมเดลใดก็ได้เป็นแบบลากได้ เพียงเพิ่ม DragDetector เป็นลูกหลานโดยตรง

  1. ในหน้าต่าง สํารวจ เลื่อนเมาส์ไปเหนือ Part , MeshPart หรือ Model และคลิกปุ่ม ⊕ จะปรากฏเมนูบริบท

  2. จากเมนูใส่ DragDetector

  3. โดยค่าเริ่มต้น ตอนนี้วัตถุจะสามารถลากได้ในแผ่นดิน แต่คุณสามารถปรับแต่ง DragStyle ของมันได้ว่าจะตอบสนองต่อการเคลื่อนไหวอย่างไร และสามารถใช้ ขีดจํากัดแกนหรือการเคลื่อนที่ได้ตามต้องการ

ปรับแต่งตัวตรวจจับการลาก

ลากสไตล์

DragDetectors เคลื่อนเคอร์เซอร์แผนที่ไปยังเส้นและแผนการเสมือนเพื่อคำนวณการเคลื่อนไหว 3D ที่เสนอผ่านคุณสมบัติ DragStyle คุณสามารถเลือกจากแผนที่ต่างๆ เพื่อตอบสนองความต้องการของคุณตัวอย่างเช่น TranslatePlane ผลิตการแปลในเครื่องบินเสมือนในขณะที่ RotateAxis ผลิตการหมุนเกี่ยวกับเครื่องบินเสมือน

การตั้งค่าคําอธิบาย
TranslateLineการเคลื่อนไหว 1D ตามแนวนักตรวจจับ Axis โดยค่าเริ่มต้นคือแกนโลก Y
TranslatePlaneการเคลื่อนไหว 2D ในเครื่องบินที่ตั้งฉากกับเครื่องตรวจจับ Axis โดยปกติจะเป็นเครื่องบิน XZ ของโลก
TranslatePlaneOrLineการเคลื่อนไหว 2D ในเครื่องบินตั้งฉากกับตัวตรวจจับ Axis และเมื่อ modifier ใช้งานอยู่ การเคลื่อนไหว 1D ตามเส้นตรวจจับ Axis
TranslateLineOrPlaneการเคลื่อนไหว 1D ตามแนวนอนของเครื่องตรวจจับ Axis และเมื่อ modifier ใช้งานอยู่ การเคลื่อนไหว 2D ในแนวนอนตรงข้ามกับเครื่องตรวจจับ Axis
TranslateViewPlaneการเคลื่อนไหว 2D ในเครื่องบินที่ตั้งฉากกับมุมมองของกล้องในโหมดนี้เครื่องบินจะได้รับการอัปเดตอย่างต่อเนื่องแม้ในขณะที่ลากและจะเผชิญกับมุมมองปัจจุบันของกล้องเสมอ
RotateAxisการหมุนรอบเซนเซอร์ของ Axis โดยค่าเริ่มต้นคือแกนโลก Y
RotateTrackballการหมุนลูกศรติดตามต่อไปโดยการปรับแต่งเพิ่มเติมผ่านคุณสมบัติ TrackballRadialPullFactor และ TrackballRollFactor
BestForDevice แปลเครื่องบินหรือเส้น สำหรับเมาส์และเกมแพด; แปลเครื่องบิน สำหรับการสัมผัส; 6DOF สำหรับ VR
Scriptableคำนวณการเคลื่อนไหวที่ต้องการผ่านฟังก์ชันที่กําหนดเองที่ให้ผ่านทาง SetDragStyleFunction()

ลากทิศทาง

โดยค่าเริ่มต้น การเคลื่อนไหว 3D และแผนที่ที่เกี่ยวข้อง DragStyle ไปยังพื้นที่โลกอย่างไรก็ตาม คุณอาจต้องการเปลี่ยน ReferenceInstance , Orientation หรือ Axis ตัวอย่างเช่นเมื่อสร้างตัวตรวจจับลากไปยัง โมเดลที่สามารถปรับได้

คุณสมบัติคําอธิบายค่าเริ่มต้น
ReferenceInstanceตัวอย่างที่สามารถให้เฟรมอ้างอิง สำหรับตัวตรวจจับแรงดึง สำหรับตัวตรวจจับแรงดึงThe DragFrame ถูกแสดงเป็นค่าสัมพันธ์กับกรอบอ้างอิงนี้ซึ่งสามารถดึงได้ผ่าน GetReferenceFrame()หากกรอบอ้างอิงเป็น nil การแปลจะอยู่ในทิศทางของ (หรือในแนวตั้งฉากกับ) คุณสมบัติ Axis ในพื้นที่โลกnil
Orientationระบุการหมุน YXZ ของแกนการเคลื่อนที่เมื่อเทียบกับกรอบอ้างอิง (ไม่เปลี่ยนทิศทางของกรอบอ้างอิงเอง)การแปลเชิงเส้นและการหมุนแบบเขวี้ยงจะอยู่บนแกนหมุนเชิงเส้นนี้ Y และการแปลแบบเรียบในแพลน XZ การเปลี่ยนค่านี้โดยอัตโนมัติจะอัปเดต Axis และกลับกัน(0, 0, 0)
Axisแกนหลักของการเคลื่อนไหวที่แสดงเป็นค่าเปรียบเทียบกับกรอบอ้างอิง การเปลี่ยนค่านี้จะอัปเดตอัตโนมัติ Orientation และกลับกัน(0, 1, 0)

การตอบสนองต่อการเคลื่อนไหว

คุณสมบัติ ResponseStyle กำหนดวิธีที่วัตถุตอบสนองต่อการเคลื่อนไหวที่เสนอขึ้น ขึ้นอยู่กับว่าวัตถุเป็น Anchored หรือไม่

การตั้งค่าพฤติกรรมที่ติดตั้งอยู่พฤติกรรมที่ไม่ได้รับการยึดถือ
Geometricทั้งภายในประสบการณ์การทำงานและในโหมดการแก้ไขสตูดิโอ ตำแหน่ง/ทิศทางของวัตถุที่ติดตั้งจะได้รับการอัปเดตเพื่อสะท้อนการเคลื่อนไหวที่เสนอได้อย่างถูกต้องสำหรับวัตถุที่ไม่ได้ติดตั้ง พฤติกรรมจะเหมือนกับวัตถุที่ติดตั้งอย่างไรก็ตามในประสบการณ์ที่กําลังดําเนินอยู่วัตถุจะถูกยึดที่จุดเริ่มต้นของการลากและฟื้นฟูกลับเป็นค่าที่ไม่ได้ยึดเมื่อปล่อยการลาก
Physicalวัตถุที่ถูกยึดจะเริ่มต้นด้วยพฤติกรรมทางเรขาคณิต เนื่องจากไม่ได้รับผลกระทบจากแรงวัตถุที่ไม่ได้ติดตั้งจะถูกย้ายโดย แรงข้อจํากัด ที่พยายามนําไปสู่ตําแหน่งและ/หรือทิศทางที่ต้องการโดยการเคลื่อนไหวที่เสนอ
Customวัตถุจะไม่เคลื่อนที่เลย แต่ DragFrame จะยังคงได้รับการอัปเดตและคุณสามารถ ตอบสนองต่อการจัดการลากได้ อย่างที่คุณต้องการ(เหมือนกับที่ถูกยึด)

ขีดจํากัดแกนและการเคลื่อนที่

โดยค่าเริ่มต้นจะไม่มีข้อจํากัดสำหรับการเคลื่อนไหว 3D เกินข้อจํากัดที่มีอยู่แล้วของ DragStyleหากจำเป็น คุณสามารถใช้ขีดจํากัดขั้นต่ําและสูงสุดสำหรับทั้งการแปลและการหมุนหมายเหตุ, อย่างไรก็ตาม, ข้อจํากัดเหล่านี้ไม่ใช่ข้อจํากัด; พวกเขาเพียงแค่ขัดขวางความพยายามของเครื่องตรวจจับการเคลื่อนไหวในการสร้างการเคลื่อนไหวเพื่ออยู่ภายในขอบเขต

คุณสมบัติคําอธิบายค่าเริ่มต้น
Class.DragDetector.MinDragTranslation|MinDragTranslation``Class.DragDetector.MaxDragTranslation|MaxDragTranslationข้อจํากัดในการลากแปลในแต่ละมิติ หาก MaxDragTranslation มากกว่า MinDragTranslation การแปลจะถูกขัดขวางภายในช่วงนั้น(0, 0, 0)
Class.DragDetector.MinDragAngle|MinDragAngle``Class.DragDetector.MaxDragAngle|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)

การตอบสนองทางฟิสิกส์

คาดว่าสไตล์การตอบสนองของผู้ลากจูง จะถูกตั้งค่าเป็น กายภาพ และมันจะถูกนำไปใช้กับวัตถุที่ไม่ได้ติดตั้ง วัตถุนั้นจะถูกย้ายโดยแรงข้อจำกัดที่พยายามนํามันไปสู่ตําแหน่ง/ทิศทางที่กำหนดโดยการเคลื่อนไหวที่เสนอคุณสามารถปรับแต่งคำตอบทางกายภาพต่อไปผ่านคุณสมบัติต่อไปนี้:

คุณสมบัติคําอธิบายค่าเริ่มต้น
ApplyAtCenterOfMassเมื่อเท็จ, แรงลากจะถูกใช้ที่จุดที่ผู้ใช้คลิก เมื่อถูกต้อง, แรงจะถูกใช้ที่ศูนย์กลางของมวลของวัตถุปิด
MaxForceแรงสูงสุดที่ใช้กับวัตถุเพื่อให้บรรลุเป้าหมาย10000000
MaxTorqueแรงบิดสูงสุดที่ใช้กับวัตถุเพื่อให้บรรลุเป้าหมาย10000
Responsivenessมูลค่าที่สูงกว่าทำให้วัตถุบรรลุเป้าหมายได้เร็วขึ้น10

การปรับเปลี่ยนการใส่ข้อมูล

บางโหมด DragStyle ช่วยให้ผู้ใช้กดค้างปุ่ม แก้ไข ไว้เพื่อที่จะควบคุมวัตถุที่ลากไปในรูปแบบที่แตกต่างกันโดยค่าเริ่มต้น ตัวแก้ไขจะเป็น LeftControl บนพีซี ButtonR1 บนเกมแพด หรือ ButtonL2 บน VRคุณสามารถปรับแต่งตัวปรับเปลี่ยนเหล่านี้ผ่าน KeyboardModeSwitchKeyCode , GamepadModeSwitchKeyCode หรือ VRSwitchKeyCode คุณสมบัติของตัวระบุตําแหน่งลากได้

การเลียนแบบ

เมื่อคุณสมบัติ RunLocally เป็นเท็จ (ค่าเริ่มต้น) ไคลเอนต์จะตีความทั้งหมดของการใส่เพื่อผลิตข้อมูลที่ส่งไปยังเซิร์ฟเวอร์เพื่อดำเนินการลากในโหมดนี้ สัญญาณกิจกรรมและฟังก์ชันที่กําหนดเองทั้งหมดจะต้องอยู่ในเซิร์ฟเวอร์ Scripts

เมื่อคุณสมบัติ RunLocally เป็นจริงไม่มีการสําเนาอีเวนต์ไปยังเซิร์ฟเวอร์สัญญาณกิจกรรมที่กําหนดเองทั้งหมดและฟังก์ชันที่ลงทะเบียนต้องอยู่ในไคลเอนต์ 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 เป็น สามารถใช้งานได้ คุณสามารถให้ฟังก์ชันของคุณเองที่รับ 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)
-- ยกเลิกวัตถุที่ลากออกจากการตรวจจับรังสี
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)

ฟังก์ชันข้อจํากัดที่กําหนดเอง

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

ตรวจจับลาก - ฟังก์ชันข้อจำกัดที่กำหนดเอง

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)
-- When applicable, remove the constraint function by invoking connection:Disconnect()

การใช้งานตัวอย่าง

วัตถุทางกายภาพที่ไม่ได้ติดตั้งอยู่

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

โมเดลที่ติดตั้งอยู่ด้วยชิ้นส่วนที่ปรับได้

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

ลากตัวตรวจจับและข้อจำกัด

คุณสามารถรวมตัวตรวจจับการลากกับ Constraints ตัวอย่างเช่นหุ่นละครหุ่นในการตั้งค่าต่อไปนี้ การควบคุมจัดอยู่บนฐาน ส่วนของร่างกายไม่ได้รับการยึด และข้อจํากัดรักษามาริออนไว้ด้วยกันการย้ายจัดก้านด้วย TranslateViewPlane DragStyle ทำให้มาริออนเต้นรํา และส่วนตัวบอดี้แต่ละส่วนอาจถูกย้ายด้วยตัวตรวจจับลากทั้งหมดในขณะที่โมเดลยังคงรักษาความสมบูรณ์ไว้

อินเทอร์เฟซผู้ใช้ 3D

อินเทอร์เฟซผู้ใช้ 3D สามารถเข้าถึงได้ง่ายผ่านตัวตรวจจับการลาก เช่น ปรับความสว่างของ SpotLight ตามสวิตช์สไลเดอร์ที่เลื่อนคุณยังสามารถตรวจจับแกน X และ Z แยกต่างหากเพื่อควบคุมสองด้านที่แตกต่างกันของอินเทอร์เฟซผู้ใช้ 3D เช่น Size , Speed และ Color ของ ParticleEmitter

ตรวจจับ - อินเทอร์เฟซผู้ใช้ 3D

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)