Unity katman maskelerinin neden bit kaydırma kullanması gerekir?


10

Sonunda, yer çarpışma kodum için katman maskelerimin neden çalışmadığını anladım. NameToLayer()İhtiyacım olan katmanı almak için kullanıyordum , ancak katman maskeleri katman katmanı değerini gerçekten ayarlamak için bit kaydırmayı kullanıyor. Bu son derece alışılmadık bir durum ve bunun arkasındaki kodda ele alınmaması için hiçbir neden göremiyorum. Neden böyle bir kod kullanmalıyız:

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

böyle bir şey olduğunda:

mask = LayerMask.NameToLayer("Default");

daha sezgisel bir anlam ifade eder ve Unity API'sının geri kalanına benzer şekilde çalışır?


2
Dize sürümünü kullanmak daha fazla işlem gücü gerektirir. Dize, dahili olarak bir referans türü olan ve çöp toplayıcısına eklenen bir dizidir.
Krythic

Yanıtlar:


3

Bu son derece performanslıdır. Her şey var - açık örnek 10 olarak dizeleri karşılaştırmak 10 kat daha yavaştır. Ve fizik hesaplamaları çok optimize edilmelidir, bu yüzden neler olduğunu bilen birinin bunu bu şekilde yazması iyidir.

Bu yüzden açık olan takip sorusu - bu neden dönüştürme ve bit kaydırmayı ele almak için yardımcı bir yönteme sarılmıyor. Bence hiç kimse buna erişemedi - kendi şık yardımcı programımı hazırladım ve bu yaygın bir uygulamadır.


1
Unity ekibi tarafından doğru tasarım seçimi, bir tamsayı dizgi yerine dizinleyici olarak kullanmak olurdu. Çöp toplayıcısının dize dizisi tahsislerinden bahsetmemekle birlikte, mevcut uygulamalarıyla ne kadar çılgın olduğunu düşündüğümde küfrediyorum.
Krythic

1
Kesinlikle - herhangi bir diziye en iyi tamsayılar tarafından referans verilir. Tamsayılar basit bir numaralandırma ile kolayca insanca okunabilir hale gelebilir.
Jordan Georgiev

Hızlı ve kirli bir uygulama işe yarar, ancak daha büyük projeler için [Type Safe] kullanıyorum ( assettore.unity3d.com/en/#!/content/35903 ).
Jordan Georgiev

20

Bit kaydırma özelliğini kullanmak, bir fizik işleminde birden çok katmanı dikkate almanızı sağlar:

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

Biraz kayma olmadan, tek bir katmanda ve sadece bir katmanda raycast yapmanıza izin verilir. Bit kaydırma ile, birden fazla belirli katmanda raycast yapabilirsiniz:

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

Belirli katmanlar dışında her katmanda da raycast yapabilirsiniz :

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

Unity'deki "Katman yöneticisi" ne bakarsanız , katmanlar basit bir boyutlu dizinin endeksleri olarak görülebilir .


EDIT: Ben daha önce hiç görmedim, ama LayerMasksınıf katman isimleri verilen "hesaplanan" katman maskesi almak için bir yardımcı program işlevi vardır:

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

Varsayalım UserLayerAve UserLayerBonuncu ve onbirinci katmanlar. Bunların Kullanıcı Katmanı değerleri 10 ve 11 olacaktır. Katman maskesi değerlerini elde etmek için adları GetMask'a aktarılabilir. Bağımsız değişken, adlarının bir listesi veya adlarını depolayan bir dizeler dizisi olabilir. Bu durumda dönüş değeri 2 ^ 10 + 2 ^ 11 = 3072 olacaktır.

Belgelere bağlantı: https://docs.unity3d.com/ScriptReference/LayerMask.GetMask.html


2
Maskeler birleşirken |tamsayı ekleme yerine bitsel VEYA kullanmalısınız; tamsayı ekleme +beklenmedik davranışlara neden olabilir.
wondra

1
Ama sonra tekrar, onlar içten, bitmiş ve benzeri bir yöntem temin olabilirdiLayerMask.NamesToLayers(params string[] layerNames)
QBrute

İyi nokta @wondra! ;) - Evet, bu QBrute'u yapmış olabilirler, ancak katman maskesini dinamik olarak değiştirmek istiyorsanız (katman ekleme, çıkarma, ters çevirme, ...)
Hellium

Bitsel işlemler de son derece hızlıdır. Büyük ikili verileri birleştirmek için mükemmel bir yoldur.
Gusdor

Bu, yöntemin neden sadece düz bir katman numarası yerine bir katman maskesi döndürmediği sorusuna cevap vermiyor.
Kübik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.