Mengembangkan permainan di Unity, saya memanfaatkan secara liberal [RequireComponent(typeof(%ComponentType%))]
untuk memastikan semua komponen telah terpenuhi.
Saya sekarang menerapkan sistem tutorial yang menyoroti berbagai objek UI. Untuk melakukan penyorotan, saya mengambil referensi ke GameObject
dalam adegan, lalu saya mengkloningnya dengan Instantiate () dan kemudian menghapus semua komponen yang tidak diperlukan untuk ditampilkan secara rekursif. Masalahnya adalah bahwa dengan penggunaan liberal RequireComponent
dalam komponen-komponen ini, banyak yang tidak dapat dihapus begitu saja dalam urutan apa pun, karena mereka bergantung pada komponen lain, yang belum dihapus.
Pertanyaan saya adalah: Apakah ada cara untuk menentukan apakah Component
dapat dihapus dari yang GameObject
saat ini dilampirkan.
Kode yang saya posting secara teknis berfungsi, namun ia melempar kesalahan Unity (tidak tertangkap di blok try-catch, seperti yang terlihat pada gambar
Berikut kodenya:
public void StripFunctionality(RectTransform rt)
{
if (rt == null)
{
return;
}
int componentCount = rt.gameObject.GetComponents<Component>().Length;
int safety = 10;
int allowedComponents = 0;
while (componentCount > allowedComponents && safety > 0)
{
Debug.Log("ITERATION ON "+rt.gameObject.name);
safety--;
allowedComponents = 0;
foreach (Component c in rt.gameObject.GetComponents<Component>())
{
//Disable clicking on graphics
if (c is Graphic)
{
((Graphic)c).raycastTarget = false;
}
//Remove components we don't want
if (
!(c is Image) &&
!(c is TextMeshProUGUI) &&
!(c is RectTransform) &&
!(c is CanvasRenderer)
)
{
try
{
DestroyImmediate(c);
}
catch
{
//NoOp
}
}
else
{
allowedComponents++;
}
}
componentCount = rt.gameObject.GetComponents<Component>().Length;
}
//Recursive call to children
foreach (RectTransform childRT in rt)
{
StripFunctionality(childRT);
}
}
Jadi cara kode ini menghasilkan tiga baris terakhir dari log debug di atas adalah sebagai berikut: Dibutuhkan sebagai input GameObject
dengan dua komponen: Button
dan PopupOpener
. PopupOpener
meminta agar suatu Button
komponen hadir dalam GameObject yang sama dengan:
[RequireComponent(typeof(Button))]
public class PopupOpener : MonoBehaviour
{
...
}
Iterasi pertama dari loop sementara (dilambangkan oleh teks "ITERATION ON Button Invite (clone)") berusaha untuk menghapus yang Button
pertama, tetapi tidak bisa karena tergantung pada PopupOpener
komponen. ini menimbulkan kesalahan. Kemudian ia mencoba untuk menghapus PopupOpener
komponen, yang ia lakukan, karena tidak bergantung pada hal lain. Dalam iterasi berikutnya (Ditandai oleh teks kedua "ITERATION ON Button Invite (clone)"), itu berusaha untuk menghapus Button
komponen yang tersisa , yang sekarang bisa dilakukan, karena PopupOpener
telah dihapus dalam iterasi pertama (setelah kesalahan).
Jadi pertanyaan saya adalah apakah mungkin untuk memeriksa sebelumnya apakah komponen tertentu dapat dihapus dari saat ini GameObject
, tanpa meminta Destroy()
atau DestroyImmediate()
. Terima kasih.
Destroy
menghapus komponen di akhir frame (sebagai lawanImmediate
ly).DestroyImmediate
dianggap gaya yang buruk, tapi saya pikir beralih keDestroy
sebenarnya dapat menghilangkan kesalahan ini.Jawaban:
Ini memang mungkin, tetapi membutuhkan kerja keras yang cukup banyak: Anda dapat memeriksa apakah ada
Component
lampiranGameObject
yang memilikiAttribute
tipeRequireComponent
yang memiliki salah satum_Type#
bidang yang dapat ditugaskan ke tipe komponen yang akan Anda hapus. Semua dibungkus dengan metode ekstensi:setelah menjatuhkan
GameObjectExtensions
di mana saja dalam proyek (atau sebagai metode biasa pada skrip), Anda dapat memeriksa apakah komponen dapat dihapus, misalnya:Namun ada cara lain untuk membuat objek GUI yang tidak interaktif - misalnya, menjadikannya tekstur, melapisinya dengan panel yang hampir transparan yang akan mencegat klik atau menonaktifkan (alih-alih menghancurkan) semua
Component
yang berasal dariMonoBehaviour
atauIPointerClickHandler
.sumber
catch
, log, lanjutkan) daripada mencegah kesalahan (yaituif
mungkin, kemudian). Namun demikian, tidak banyak gaya C # (seperti yang ada dalam jawaban ini). Pada akhirnya kode asli Anda mungkin lebih dekat dengan bagaimana hal-hal biasanya dilakukan ... dan praktik terbaik adalah masalah preferensi pribadi.Alih-alih menghapus komponen pada klon, Anda bisa menonaktifkannya dengan mengaturnya
.enabled = false
. Ini tidak akan memicu pemeriksaan dependensi, karena komponen tidak perlu diaktifkan untuk memenuhi dependensi.Update
metodenya.sumber