Pertanyaan Mengapa Persatuan mengabaikan nilai yang diinisialisasi dari bidang publik non-statis?


saya menggunakan InvokeRepeating() untuk memanggil metode dalam game. Saya menelepon InvokeRepeating() dalam Start() metode salah satu dari GameObject  kelas. Untuk mengatur repeatRate parameter untuk InvokeRepeating(), Saya melewati bidang publik yang disebut secondsBetweenBombDrops.

Kesatuan mengabaikan nilai yang saya tetapkan secondsBetweenBombDrops dalam kode dan sebagai gantinya menggunakan beberapa nilai default (yaitu 1) saat secondsBetweenBombDrops dideklarasikan tanpa pengubah statis:

public float secondsBetweenBombDrops = 10f;
void Start() {
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}

Namun, begitu saya menambahkan static pengubah menjadi secondsBetweenBombDrops, kode berperilaku seperti yang diharapkan dan nilai 10 yang benar digunakan:

public static float secondsBetweenBombDrops = 10f;
void Start() {
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}

Mengapa bidang ini memerlukan static pengubah untuk menggunakan nilai yang sesuai?

Di inspektur Unity, komponen skrip menunjukkan itu secondsBetweenBombDrops adalah 1. Nilai default 1 ini ada terlepas apakah saya menginisialisasi prefab pada permulaan game atau membuat instance pabrikan saat game berjalan.


32
2018-03-02 10:23


asal


Jawaban:


Pedang serialisasi bermata dua

Kesatuan ingin membuat segalanya lebih mudah untuk semua orang, termasuk orang-orang dengan pengetahuan pengkodean terbatas (pemula, desainer).

Untuk membantu mereka, Unity menampilkan data di inspektur. Hal ini memungkinkan coder untuk mengkodekan dan perancang merancang dengan mengubah nilai-nilai tanpa membuka MonoDevelop / sebuah IDE.

Ada dua cara untuk menampilkan nilai dalam inspektur:

public int myVar = 10;
[SerializeField] private int myOtherVar = 0; // Can also be protected

Yang kedua lebih baik karena sesuai dengan prinsip enkapsulasi (variabel bersifat pribadi / dilindungi dan dimodifikasi melalui metode atau properti).

Saat Anda menampilkan variabel di Editor, nilai yang diberikan dalam skrip hanya digunakan saat menyeret skrip. Kesatuan kemudian serializes nilai-nilai dan tidak peduli tentang modifikasi skrip lagi. Ini dapat menyebabkan kebingungan jika, misalnya, myVar diatur ke 20 di dalam skrip setelah fakta, itu tidak akan digunakan. Serialisasi ditulis dalam file adegan.

Dua baris dalam contoh ini bekerja dengan cara yang sama.

Solusi yang memungkinkan

Adalah mungkin untuk membuat Persatuan mempertimbangkan nilai baru dalam skrip dengan menekan Reset pada roda pengaturan komponen skrip. Itu juga akan mengatur ulang semua variabel lain dari komponen, jadi hanya lakukan ini jika itu dimaksudkan.

Membuat variabel bersifat pribadi dan menghilangkan atribut [SerializeField] akan menonaktifkan proses serialisasi, jadi Unity tidak akan lagi melihat dalam file adegan untuk nilai yang ditampilkan - sebagai gantinya, nilai akan dibuat saat runtime oleh skrip.

Saat menambahkan komponen ke Unity, objek baru dari jenis komponen dibuat. Nilai-nilai yang ditampilkan adalah nilai serial dari objek itu. Untuk alasan ini, hanya nilai-nilai anggota dapat ditampilkan dan variabel statis tidak, karena mereka tidak dapat diseragamkan. (Ini adalah spesifikasi .NET, tidak sepenuhnya spesifik untuk Unity.) Karena Kesatuan tidak berstatus bidang statis, inilah mengapa menambahkan static modifikator tampaknya memecahkan masalah.

Menjelaskan OP

Dalam kasus OP, berdasarkan komentar, bidang publik Anda menunjukkan nilai 1 di editor. Anda pikir nilai ini adalah nilai default, padahal sebenarnya nilai yang paling mungkin Anda berikan ke lapangan ketika awalnya menyatakannya. Setelah Anda menambahkan skrip sebagai komponen, Anda membuat nilai 10 dan mengira itu buggy karena masih menggunakan nilai 1. Anda sekarang harus mengerti bahwa itu berfungsi dengan baik, seperti yang dirancang.

Apa yang diserukan Unity?

Secara default, Unity akan membuat serial dan menampilkan jenis nilai (int, float, enum dan sebagainya) serta string, array, List, dan MonoBehaviour. (Dimungkinkan untuk memodifikasi penampilan mereka dengan skrip Editor, tetapi ini di luar topik.)

Pengikut:

public class NonMonoBehaviourClass{
   public int myVar;
}

tidak diserialkan secara default. Di sini sekali lagi, ini adalah spesifikasi NET. Kesatuan serialisasi MonoBehaviour secara default sebagai bagian dari persyaratan mesin (ini akan menyimpan konten ke file adegan). Jika Anda ingin menampilkan kelas "klasik" di editor, cukup katakan:

[System.Serializable]
public class NonMonoBehaviourClass{
   public int myVar = 10;
}

Tentunya, Anda tidak dapat menambahkannya ke objek permainan sehingga Anda perlu menggunakan MonoBehaviour:

public class MyScript:MonoBehaviour{
     public NonMonoBehaviourClass obj = new NonMonoBehaviourClass();
}

ini akan menampilkan objek di inspektur dan memungkinkan modifikasi pada myVar variabel dalam contoh NonMonoBehaviourClass. Dan lagi, setiap perubahan myVar dalam skrip tidak akan dipertimbangkan setelah nilai diserialkan dan disimpan ke TKP.

Tips tambahan untuk menampilkan barang-barang di inspektur

Untuk menyelesaikan, antarmuka tidak ditampilkan di inspektur baik karena mereka tidak mengandung variabel - hanya metode dan properti. Dalam mode debug, properti tidak ditampilkan secara default. Anda dapat mengubah mode ini menggunakan tombol dengan tiga garis di sudut kanan atas Inspektur. Dua pengaturan pertama adalah Normal / Debug. Yang pertama adalah yang standar, yang kedua juga akan menampilkan variabel pribadi. Ini berguna untuk melihat nilainya tetapi tidak dapat diubah dari editor.

Jadi, jika Anda membutuhkan antarmuka untuk ditampilkan, Anda harus mempertimbangkan kelas abstrak karena menawarkan fungsi yang serupa (kecuali untuk multi-warisan) tetapi dapat menjadi MonoBehaviour.

Referensi:

http://docs.unity3d.com/ScriptReference/SerializeField.html

http://docs.unity3d.com/Manual/script-Serialization.html

https://www.youtube.com/watch?v=9gscwiS3xsU

https://www.youtube.com/watch?v=MmUT0ljrHNc


32
2018-03-02 20:10