W Unity dlaczego dodawanie Vector2 i Vector3 jest niejednoznaczne, ale przypisywanie nie jest?

11

Biorąc pod uwagę następujące dwa wektory:

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

Ta linia jest niejednoznaczna:

v3 += v2; // Unity reports dimension ambiguity

podczas gdy to zadanie nie jest:

v3 = v2; // Unity assigns despite different dimensions

Dlaczego to?

SteakOverflow
źródło
Dziękuję bardzo Anko i Xavi Montero za wspaniałe odpowiedzi. Próbując odtworzyć problem, zdałem sobie sprawę, że moje pytanie powinno zostać zmienione. Dzieje się tak, gdy przypisujemy Vector2 do transform.position, aby transform.position = a + b; gdzie BOTH a i b są kompilacjami Vector2 poprawnie i przypisuje xiy! Zamiast tego nie działa, gdy zmienię wiersz na transform.position + = a; // lub b Używam Unity 5.0.0f, a skrypt jest dołączony do elementu interfejsu użytkownika (Image), który nie wpływa na kompilator, ale może być ważną informacją dla odtworzenia scenariusza.
SteakOverflow
Więc powiedzcie mi, co mam robić. Czy powinniśmy odpowiednio zmienić pytanie i twoje odpowiedzi, czy możemy rozpocząć nowe?
SteakOverflow
Vector3 + Vector2 i Vector3 + = Vector2 nigdy nie będzie działać bez względu na to, czego chcesz, ponieważ oba mogą być niejawnie przekonwertowane na inne i musisz jawnie rzutować zgodnie z tym, co chcesz zrobić. Vector3 = Vector2 działa, ponieważ nie ma dwuznaczności. Nie widzę potrzeby zmiany ani opublikowania nowego pytania.
Mówię o zmianie pytania, ponieważ sprawa różni się nieco od tego, co opisałem, co może zahamować przepływ twojej odpowiedzi.
SteakOverflow 21.04.2015
Nie martw się, nic się nie psuje.

Odpowiedzi:

12

Pełny komunikat o problemie:

błąd CS0121: Wywołanie jest niejednoznaczne między następującymi metodami lub właściwościami: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

Unity umożliwił niejawną konwersję a Vector3na Vector2vice versa. Powoduje to niejednoznaczność w twoim przypadku, ponieważ można zastosować oba operatory +.

W tej operacji możesz przesłać swoje Vector2polecenie Vector3jawnie, aby kompilator wiedział, jak go używać UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Jeśli jesteś ciekawy, dokumenty Microsoft dotyczące tego konkretnego błędu są tutaj .


Edytuj po edycji:

Vec3 += Vec2jest niejednoznaczny z tego samego powodu opisanego powyżej. Wyobraź sobie, Vec3 += Vec2że tak naprawdę jest Vec3 = Vec3 + Vec2. Vec3 + Vec2może dać jedno Vector2i Vector3jako odpowiedź z powodu niejawnych konwersji, dlatego musisz określić, co chcesz.

Vec3 = Vec2nie jest niejednoznaczny, ponieważ Vec2 jest domyślnie konwertowany na a, Vector3a następnie przypisywany do początkowej Vec3. Tak więc cała operacja jest naprawdę Vector3 = Vector3bez konieczności Vector3ręcznego przesyłania Vec2 .


źródło
Tak więc Unity zakłada, że ​​chcę, aby x i y mojego Vector3 zostały przypisane z x iy mojego Vector2, a mój z ustawiony na 0f. Dobrze?
SteakOverflow
Tak, wyobraź sobie, że Vec3 = Vec2 jest równoważne Vec3 = (Vector3) Vec2. Nie musisz rzucać ręcznie, ponieważ w tym przypadku nie może to być nic innego.
Tak, właściwie moje pytanie może być zatytułowane: „Dlaczego nie muszę przesyłać do Vector3 podczas przypisywania Vector2”. Nie jestem najlepszy w tytułowaniu i tworzeniu idealnych pytań: / Dziękuję Alex. Moja ciekawość została (nadmiernie) zaspokojona.
SteakOverflow 21.04.15
3

Pozwól mi zmienić nazwę vars (dla jasności):

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

Odpowiedź

Jest to spowodowane odcinkiem pos3d + pos2dlinii. Ta część jest naprawdę dwuznaczna, podczas gdy +=nie jest. Pozwól mi wyjaśnić, dlaczego jedno i dlaczego drugie.

Analiza 1

W tej linii

transform.position = pos3d + pos2d;

kompilator najpierw próbuje ocenić wyrażenie pos3d + pos2dprzed kontynuowaniem, niezależnie od tego, gdzie wynik ma zostać umieszczony.

Aby to zrobić, system najpierw próbuje znaleźć dowolną publiczną funkcję statyczną, która dodaje Vector3 i Vector2, na przykład tę możliwą sygnaturę:

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

lub na przykład ten możliwy podpis:

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

Niemniej jednak w interfejsie API nie ma żadnych tych podpisów, więc kompilator próbuje „rzutować” parametry na znane podpisy.

Następnie kompilator znajduje te dwa potencjalne podpisy:

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

Są one udokumentowane tutaj: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html i tutaj: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Istnieją więc dwie możliwości:

Aby oba castingi były możliwe, pos2d można rzutować na Vector3, a pos3d jest castabale na Vector2, kompilator następnie znajduje możliwe sposoby na skompilowanie tego samego kodu źródłowego (pod warunkiem, że automatyczne ukryte castingi są na miejscu).

Możliwe jest albo rzutowanie pos3d na Vector2 i przejście do drugiego podpisu, albo albo rzutowanie pos2d na Vector3 i przejście do pierwszego podpisu.

Gdy wyrażenie pos3d + pos2djest oceniane najpierw, zanim weźmie się pod uwagę „gdzie zostanie zastosowany wynik”, kompilator nie wie, jaką obsadę - jak programista - wykona.

Jeśli chcesz przejść do 3D, możesz napisać to:

transform.position = pos3d + ( Vector3 )pos2d;

problem zniknął, ponieważ teraz jest jasne: najpierw przenieś pos2d do innego obiektu typu Vector3, a następnie wykonaj sumę Vector3 + Vector3. Pod warunkiem, że istnieje ten podpis statyczny

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

dostępne, ten będzie używany bez żadnych dwuznaczności.

Analiza 2

Z drugiej strony, kiedy to zrobisz

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

nie ma dwuznaczności: pierwsza linia przypisuje Vector3 do Vector3 (bez wątpliwości).

Druga linia odpowiada

transform.position = transform.position + pos2d;

ze szczególnym uwzględnieniem transform.position jest oceniany tylko raz, dlatego też brany jest pod uwagę typ, jak można zobaczyć na tej stronie Microsoft o +=operatorze:

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

Ponadto napisano: „Operatora + = nie można bezpośrednio przeciążać, ale typy zdefiniowane przez użytkownika mogą przeciążać operatora + (patrz operator)”. więc powinniśmy myśleć Vector3„s +=operator działa w sposób opisany przez Microsoft, gdzie jest napisane:

x += y

jest równa

x = x + y

z wyjątkiem tego, że x jest obliczany tylko raz. Znaczenie operatora + zależy od typów xiy (dodawanie dla operandów numerycznych, konkatenacja dla operandów łańcuchowych i tak dalej).

więc możemy być pewni, że drugie podejście wywołuje operand + Vector3klasy, który ma podpis:

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

więc nie ma innego sposobu na osiągnięcie tego niż konwersja pos2d w Vector3 dzięki ukrytej obsadzie ukrytej, która nie może mieć innej formy.

Mam nadzieję na pomoc !!


Edytować

W Unity 5.0.1f1 Personalz MonoDevelop-Unit 4.0.1, jak mówi Alex M., linie:

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

wciąż rzucam błąd "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)'"

tak naprawdę + = używa obu podpisów

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

bez względu na to, że już wiem „gdzie” wynik powinien zostać umieszczony (chyba dlatego, że wypisanie Vector2 jest możliwe do rzucenia do miejsca docelowego (Vector3) i jeśli prawdopodobnie nie byłoby to możliwe, kompilator wybrałby ten z właściwym Typ wyjścia).

Dzięki za punkt Alex M.

Xavi Montero
źródło
+=też nie działa, to wciąż Vector3+ Vector2. Zobacz moją odpowiedź.
Racja, wasze głosowanie, będzie edytować moje.
Xavi Montero,
Właśnie edytowane, aby dołączyć komentarz.
Xavi Montero,
transform.position + = pos2d się kompiluje. Będę bardziej precyzyjny jutro (może to być tylko błąd wersji)
SteakOverflow
Po zmianach zgubiłem się w sekwencji ... więc ... pos3d += pos2d(zgodnie z edytowanym pytaniem) kończy się niepowodzeniem, ale transform.position += pos2dkompiluje (zgodnie z komentarzem powyżej)? Wydawałoby się dziwne, jakie .positionjest Vector3- Nie mogę wyraźnie zobaczyć, czy o to ci chodzi.
Xavi Montero