Di Unity, mengapa menambahkan Vector2 dan Vector3 ambigu tetapi menugaskan tidak?

11

Diberikan dua vektor berikut:

Vector3 v3 = Vector3.one;
Vector2 v2 = Vector2.one;

Baris ini ambigu:

v3 += v2; // Unity reports dimension ambiguity

sementara tugas ini bukan:

v3 = v2; // Unity assigns despite different dimensions

Kenapa ini?

SteakOverflow
sumber
Jadi, terima kasih banyak untuk Anko dan Xavi Montero untuk jawaban yang bagus. Mencoba mereproduksi masalah saya menyadari pertanyaan saya harus diubah. Fakta ini terjadi ketika menugaskan Vector2 untuk mentransformasikan posisi sehingga transform.posisi = a + b; di mana KEDUA a dan b adalah kompilasi Vector2 dengan benar dan itu menetapkan x dan y! Sebaliknya, itu tidak berfungsi ketika saya mengubah baris untuk mentransformasikan.posisi + = a; // atau b Saya menggunakan Unity 5.0.0f dan skrip dilampirkan ke elemen UI (Gambar) yang tidak mempengaruhi kompiler tetapi mungkin informasi penting bagi Anda untuk mereproduksi skenario.
SteakOverflow
Jadi kalian katakan padaku apa yang harus dilakukan. Haruskah kita mengubah pertanyaan dan jawaban Anda sesuai atau akankah kita memulai yang baru?
SteakOverflow
Vector3 + Vector2 dan Vector3 + = Vector2 tidak akan pernah berfungsi apa pun yang Anda inginkan karena keduanya dapat secara implisit dikonversi ke yang lain dan Anda perlu secara eksplisit melemparkan sesuai dengan apa yang ingin Anda lakukan. Vector3 = Vector2 berfungsi karena tidak ada ambiguitas. Saya tidak melihat perlunya mengubah atau memposting pertanyaan baru.
Saya mengatakan untuk mengubah pertanyaan karena case sedikit berbeda dari apa yang saya jelaskan, yang mungkin mengerem aliran jawaban Anda.
SteakOverflow
Nah jangan khawatir, tidak ada yang rusak.

Jawaban:

12

Pesan masalah lengkap:

kesalahan CS0121: Panggilan ini ambigu antara metode atau properti berikut: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

Unity menyediakan cara untuk secara implisit mengkonversi a Vector3ke Vector2dan sebaliknya. Ini menyebabkan ambiguitas dalam kasus Anda karena + operator dapat diterapkan.

Keluarkan Anda Vector2ke secara Vector3eksplisit dalam operasi itu, sehingga kompiler tahu untuk menggunakannya UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Jika Anda penasaran, dokumen Microsoft untuk kesalahan khusus itu ada di sini .


Edit setelah edit Anda:

Vec3 += Vec2ambigu karena alasan yang sama yang dijelaskan di atas. Bayangkan Vec3 += Vec2menjadi kenyataan Vec3 = Vec3 + Vec2. Vec3 + Vec2dapat menghasilkan keduanya Vector2dan Vector3sebagai jawaban karena konversi tersirat, itu sebabnya Anda harus menentukan apa yang Anda inginkan.

Vec3 = Vec2tidak ambigu karena Vec2 secara implisit dikonversi menjadi Vector3dan kemudian ditugaskan ke Vec3 awal. Jadi seluruh operasi benar Vector3 = Vector3- benar tanpa Anda harus menggunakan Vec2 ke Vector3manual.


sumber
Jadi Unity mengasumsikan saya ingin x dan y Vector3 saya ditugaskan dari x dan y Vector2 saya dan z saya set ke 0f. Baik?
SteakOverflow
Ya, bayangkan Vec3 = Vec2 setara dengan Vec3 = (Vector3) Vec2. Anda tidak perlu melakukan casting secara manual karena itu tidak bisa apa-apa selain itu dalam kasus itu.
Ya, sebenarnya pertanyaan saya bisa berjudul "Mengapa saya tidak perlu menggunakan Vector3 saat menetapkan Vector2". Saya bukan yang terbaik dalam pemberian judul dan menyusun pertanyaan sempurna: / Terima kasih Alex. Keingintahuan saya telah (lebih) puas.
SteakOverflow
3

Biarkan saya mengganti nama vars (untuk kejelasan):

Vector3 pos3d = new Vector3 (1f, 2f, 3f);
Vector2 pos2d = new Vector2 (1f, 2f);

Menjawab

Itu karena bagian pos3d + pos2ddari garis. Bagian ini sangat ambigu sedangkan yang +=tidak. Biarkan saya menjelaskan mengapa yang satu dan mengapa yang lain.

Analisis 1

Di baris ini

transform.position = pos3d + pos2d;

kompiler pertama kali mencoba untuk mengevaluasi ekspresi pos3d + pos2dsebelum melanjutkan, terlepas dari di mana hasilnya akan ditempatkan.

Untuk melakukannya, sistem pertama-tama mencoba menemukan fungsi statis publik yang menambahkan Vector3 plus Vector2, misalnya tanda tangan yang mungkin ini:

public static Vector3 operator +(Vector3 a, Vector2 b);

atau misalnya tanda tangan ini:

public static Vector2 operator +(Vector3 a, Vector2 b);

Namun demikian, tidak ada tanda tangan di API sehingga kompiler mencoba untuk "membuang" parameter ke tanda tangan yang dikenal.

Kemudian kompiler menemukan dua tanda tangan potensial:

public static Vector3 operator +(Vector3 a, Vector3 b);
public static Vector2 operator +(Vector2 a, Vector2 b);

Ini didokumentasikan di sini: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html dan di sini: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Jadi ada dua kemungkinan:

Jadi karena kedua coran dimungkinkan, pos2d dapat dilemparkan ke Vector3 dan pos3d dilemparkan ke dalam Vector2, kompiler kemudian menemukan cara yang memungkinkan untuk mengkompilasi kode sumber yang sama (asalkan coran tersembunyi otomatis tersedia).

Entah mungkin untuk memasukkan pos3d ke Vector2 dan melanjutkan dengan tanda tangan kedua, atau melemparkan pos2d ke Vector3 dan melanjutkan dengan tanda tangan pertama.

Ketika ekspresi pos3d + pos2ddievaluasi terlebih dahulu, sebelum mempertimbangkan "di mana hasilnya akan diterapkan" maka kompiler tidak tahu apa yang akan dilemparkan oleh Anda - sebagai pembuat kode - seperti yang ingin dilakukan.

Jika Anda ingin beralih ke 3D, Anda dapat menulis ini:

transform.position = pos3d + ( Vector3 )pos2d;

dan masalahnya hilang, seperti sekarang jelas: pertama pindahkan pos2d ke objek lain dari tipe Vector3, kemudian lakukan penjumlahan dari Vector3 + Vector3. Asalkan ada tanda tangan statis ini

public static Vector3 operator +(Vector3 a, Vector3 b);

tersedia, yang akan digunakan tanpa ambiguitas sama sekali.

Analisis 2

Di sisi lain, ketika Anda melakukannya

transform.position = pos3d;
transform.position += pos2d; 

tidak ada ambiguitas: Baris pertama menetapkan Vector3 menjadi Vector3 (tidak ada keraguan).

Baris kedua setara dengan

transform.position = transform.position + pos2d;

dengan kekhasan transform.posisi hanya dievaluasi sekali, dan oleh karena itu jenisnya dipertimbangkan, seperti yang Anda lihat di halaman Microsoft ini tentang +=operator:

https://msdn.microsoft.com/en-us/library/sa7629ew.aspx

Selain itu tertulis "Operator + = tidak dapat kelebihan beban secara langsung, tetapi tipe yang ditentukan pengguna dapat membebani operator + (lihat operator)." jadi kita harus berpikir Vector3's +=Operator bertindak seperti yang dijelaskan oleh microsoft yang mengatakan:

x += y

setara dengan

x = x + y

kecuali bahwa x hanya dievaluasi satu kali. Arti dari operator + tergantung pada jenis x dan y (penambahan untuk operan numerik, penggabungan untuk operan string, dan sebagainya).

jadi kita bisa yakin bahwa pendekatan kedua memanggil + operan Vector3kelas, yang memiliki tanda tangan:

public static Vector3 operator +(Vector3 a, Vector3 b);

jadi tidak ada cara lain untuk mencapai ini selain mengubah pos2d menjadi Vector3 berkat gips tersembunyi tersirat yang tidak bisa dari bentuk lain.

Berharap untuk membantu !!


Edit

Dalam Unity 5.0.1f1 Personaldengan MonoDevelop-Unit 4.0.1, seperti kata Alex M., baris:

transform.position = pos3d;
transform.position += pos2d;

masih melakukan kesalahan "Assets/Scripts/CubeScript.cs(15,27): error CS0121: The call is ambiguous between the following methods or properties: 'UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' and 'UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3)'"

jadi sebenarnya + = menggunakan kedua tanda tangan

public static Vector3 operator +(Vector3 a, Vector3 b);
public static Vector2 operator +(Vector2 a, Vector2 b);

terlepas dari fakta sudah tahu "di mana" hasilnya akan ditempatkan (saya kira karena mengeluarkan Vector2 dapat dicast ke tujuan (Vector3) dan jika pemeran itu tidak mungkin mungkin, mungkin, kompiler akan memilih yang dengan tepat tipe keluaran).

Terima kasih untuk poinnya Alex M.

Xavi Montero
sumber
+=tidak bekerja juga, itu masih Vector3+ Vector2. Lihat jawaban saya.
Benar, milik Anda yang ter-upgrade, akan mengedit milik saya.
Xavi Montero
Baru diedit untuk memasukkan komentar Anda.
Xavi Montero
transform.position + = pos2d sedang dikompilasi. Saya akan lebih tepat besok (mungkin hanya bug versi)
SteakOverflow
Setelah pengeditan saya tersesat dalam urutan ... jadi ... pos3d += pos2d(sesuai pertanyaan Anda yang diedit) gagal tetapi transform.position += pos2dmengkompilasi (sesuai komentar Anda di atas) ?? Akan tampak aneh apa .positionadanya Vector3- Tidak dapat melihat dengan jelas apakah itu yang Anda maksudkan.
Xavi Montero