ทำไม Unity layer masks จำเป็นต้องใช้การเลื่อนบิต?


10

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

mask = 1 << LayerMask.NameToLayer("Default");

เมื่อสิ่งนี้:

mask = LayerMask.NameToLayer("Default");

ใช้งานได้ง่ายขึ้นและทำงานคล้ายกับส่วนที่เหลือของ Unity API หรือไม่


2
การใช้เวอร์ชั่นสตริงต้องใช้กำลังการประมวลผลมากขึ้น ไม่ต้องพูดถึงสตริงภายในอาร์เรย์ซึ่งเป็นประเภทการอ้างอิงและได้รับการเพิ่มลงในตัวรวบรวมขยะ
Krythic

คำตอบ:


3

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

ดังนั้นคำถามที่ตามมาอย่างชัดเจนก็คือ - ทำไมจึงไม่ใช้วิธีการแบบตัวช่วยในการจัดการการแปลงและการเลื่อนบิต ฉันคิดว่าไม่มีใครได้รับจริง - ฉันได้สะสมยูทิลิตี้ผู้ช่วยที่ดีของฉันเอง


1
ตัวเลือกการออกแบบที่ถูกต้องโดยทีม Unity จะต้องใช้จำนวนเต็มเป็นตัวสร้างดัชนีแทนที่จะเป็นสตริง ฉันประจบประแจงเมื่อฉันคิดว่านักสะสมขยะน่าจะไปกับการใช้งานในปัจจุบันอย่างไรไม่ต้องพูดถึงการจัดสรรอาร์เรย์สตริง
Krythic

1
อย่างแน่นอน - อาร์เรย์ใด ๆ ที่อ้างอิงดีที่สุดโดยจำนวนเต็ม จำนวนเต็มสามารถอ่านได้อย่างง่ายดายโดยมนุษย์ enum
Jordan Georgiev

การใช้งานที่รวดเร็วและสกปรก แต่สำหรับโครงการขนาดใหญ่ฉันใช้ [Type Safe] ( assetstore.unity3d.com/th/#!/content/35903 )
Jordan Georgiev

20

การใช้การเลื่อนบิตช่วยให้คุณสามารถพิจารณาหลายเลเยอร์ในการดำเนินการทางฟิสิกส์เดียว:

 Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerMask )

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

layerMask = (1 << LayerMask.NameToLayer("MyLayer1")) | (1 << LayerMask.NameToLayer("MyLayer2")) ;

คุณสามารถ raycast ในทุกชั้นยกเว้นชั้นที่เฉพาะเจาะจง:

layerMask = (1 << LayerMask.NameToLayer("MyLayer1")) | (1 << LayerMask.NameToLayer("MyLayer2")) ;
layerMask = ~layerMask;

ถ้าคุณมองไปที่"ผู้จัดการชั้น" ในความสามัคคีชั้นสามารถมองเห็นเป็นดัชนีของง่ายๆอาร์เรย์หนึ่งมิติ


แก้ไข: ฉันไม่เคยเห็นมาก่อน แต่LayerMaskคลาสมีฟังก์ชันยูทิลิตี้เพื่อรับเลเยอร์ "คำนวณ" ที่กำหนดชื่อเลเยอร์:

Debug.Log( LayerMask.GetMask("UserLayerA", "UserLayerB") ) ;

สมมติUserLayerAและUserLayerBเป็นชั้นที่สิบและสิบเอ็ด สิ่งเหล่านี้จะมีค่าเลเยอร์ผู้ใช้ที่ 10 และ 11 เพื่อให้ได้มาส์กค่าเลเยอร์ของพวกเขา อาร์กิวเมนต์สามารถเป็นรายการชื่อหรืออาเรย์ของสตริงที่จัดเก็บชื่อ ในกรณีนี้ค่าส่งคืนจะเป็น 2 ^ 10 + 2 ^ 11 = 3072

ลิงก์ไปที่เอกสาร: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html


2
คุณควรใช้บิตหรือ|แทนการเพิ่มจำนวนเต็ม+เมื่อทำการรวมกันของมาสก์การเพิ่มจำนวนเต็มอาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด
wondra

1
แต่แล้วอีกครั้งพวกเขาสามารถทำสิ่งนั้นได้ภายในและให้วิธีการเช่นLayerMask.NamesToLayers(params string[] layerNames)
QBrute

จุดดี @wondra! ;) - ใช่พวกเขาจะได้ทำ QBrute นี้ แต่มันไกลมีความยืดหยุ่นมากขึ้นในการใช้งานบิต shiffting การดำเนินการถ้าคุณต้องการที่จะเปลี่ยนหน้ากากชั้น (เพิ่ม, ลบชั้น inverting, ... )
Hellium

การทำงานของ Bitwise นั้นเร็วมากเช่นกัน พวกเขาเป็นวิธีที่ดีในการประกอบข้อมูลไบนารีขนาดใหญ่
Gusdor

นี่ไม่ได้ตอบคำถามที่ว่าทำไมวิธีการไม่เพียงแค่ส่งคืนเลเยอร์มาสก์แทนที่จะส่งกลับมาเป็นจำนวนเลเยอร์
ลูกบาศก์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.