Warum ist in Unity das Hinzufügen eines Vector2 und eines Vector3 nicht eindeutig, das Zuweisen jedoch nicht?

11

Gegeben sind die folgenden zwei Vektoren:

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

Diese Zeile ist nicht eindeutig:

v3 += v2; // Unity reports dimension ambiguity

während diese Aufgabe nicht ist:

v3 = v2; // Unity assigns despite different dimensions

Warum ist das?

SteakOverflow
quelle
Vielen Dank an Anko und Xavi Montero für die tollen Antworten. Beim Versuch, das Problem zu reproduzieren, wurde mir klar, dass meine Frage geändert werden sollte. Die Tatsache passiert, wenn ein Vektor2 der transform.position zugewiesen wird, so dass transform.position = a + b; wobei BEIDE a und b Vektor2 sind, wird korrekt kompiliert und x und y zugewiesen! Stattdessen funktioniert es nicht, wenn ich die Zeile in transform.position + = a ändere. // oder b Ich verwende Unity 5.0.0f und das Skript ist an ein UI-Element (Image) angehängt, das den Compiler nicht beeinflusst, aber möglicherweise wichtige Informationen für die Reproduktion des Szenarios darstellt.
SteakOverflow
Ihr sagt mir also, was ich tun soll. Sollen wir die Frage und Ihre Antworten entsprechend ändern oder eine neue beginnen?
SteakOverflow
Vector3 + Vector2 und Vector3 + = Vector2 funktionieren niemals, egal was Sie wollen, da beide implizit in den anderen konvertiert werden können und Sie explizit entsprechend Ihren Wünschen umwandeln müssen. Vector3 = Vector2 funktioniert, weil es keine Mehrdeutigkeit gibt. Ich sehe keine Notwendigkeit, eine neue Frage zu ändern oder zu posten.
Ich sage, die Frage zu ändern, weil der Fall etwas anders ist als der, den ich beschrieben habe, was den Fluss Ihrer Antwort bremsen könnte.
SteakOverflow
Nein, mach dir keine Sorgen, nichts bricht.

Antworten:

12

Vollständige Problemmeldung:

Fehler CS0121: Der Aufruf ist zwischen den folgenden Methoden oder Eigenschaften nicht UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andeindeutig : UnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

Einheit vorgesehen , um eine Art und Weise , um implizit eine umwandeln Vector3zu a Vector2und umgekehrt. Dies führt in Ihrem Fall zu einer Mehrdeutigkeit, da beide + Operatoren angewendet werden können.

Werfen Sie Ihre Vector2zu einem Vector3explizit in dieser Operation, so dass der Compiler zu verwenden weiß UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Wenn Sie neugierig sind, Microsofts docs für diesen speziellen Fehler sind hier .


Nach der Bearbeitung bearbeiten:

Vec3 += Vec2ist aus dem oben beschriebenen Grund nicht eindeutig. Stellen Sie sich Vec3 += Vec2vor, Sie wären tatsächlich Vec3 = Vec3 + Vec2. Vec3 + Vec2kann beides ergeben Vector2und Vector3als Antwort aufgrund impliziter Konvertierungen müssen Sie angeben, was Sie wollen.

Vec3 = Vec2ist nicht mehrdeutig, da Vec2 implizit in a konvertiert Vector3und dann dem anfänglichen Vec3 zugewiesen wird. Der gesamte Vorgang ist also wirklich Vector3 = Vector3ohne dass Sie Vec2 Vector3manuell in einen übertragen müssen.


quelle
Daher geht Unity davon aus, dass ich möchte, dass x und y meines Vector3 von x und y meines Vector2 zugewiesen werden und mein z auf 0f gesetzt wird. Richtig?
SteakOverflow
Ja, stellen Sie sich vor, Vec3 = Vec2 entspricht Vec3 = (Vector3) Vec2. Sie müssen nicht manuell wirken, da es in diesem Fall nichts anderes sein kann.
Ja, eigentlich könnte meine Frage so etwas wie "Warum muss ich beim Zuweisen eines Vektors2 nicht auf Vector3 umwandeln" lauten. Ich bin nicht der Beste, wenn es darum geht, perfekte Fragen zu benennen und zu basteln: / Danke Alex. Meine Neugier war (über) befriedigt.
SteakOverflow
3

Lassen Sie mich die Vars umbenennen (der Klarheit halber):

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

Antworten

Es liegt am Abschnitt pos3d + pos2dder Linie. Dieser Teil ist wirklich mehrdeutig, während das +=nicht ist. Lassen Sie mich erklären, warum einer und warum der andere.

Analyse 1

In dieser Zeile

transform.position = pos3d + pos2d;

Der Compiler versucht zunächst, den Ausdruck auszuwerten, pos3d + pos2dbevor er fortfährt, unabhängig davon, wo das Ergebnis platziert werden soll.

Zu diesem Zweck versucht das System zunächst, eine öffentliche statische Funktion zu finden, die einen Vector3 plus einen Vector2 hinzufügt, beispielsweise diese mögliche Signatur:

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

oder zum Beispiel diese mögliche Signatur:

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

Da die API jedoch keine dieser Signaturen enthält, versucht der Compiler, Parameter in bekannte Signaturen umzuwandeln.

Dann findet der Compiler diese beiden möglichen Signaturen:

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

Diese sind hier dokumentiert: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html und hier: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Es gibt also zwei Möglichkeiten:

Da beide Castings möglich sind, kann pos2d in einen Vector3 umgewandelt werden und pos3d wird in einen Vector2 umgewandelt. Der Compiler sucht dann nach Möglichkeiten, denselben Quellcode zu kompilieren (vorausgesetzt, automatische versteckte Castings sind vorhanden).

Es ist entweder möglich, pos3d in Vector2 umzuwandeln und mit der zweiten Signatur fortzufahren, oder pos2d in Vector3 umzuwandeln und mit der ersten Signatur fortzufahren.

Da der Ausdruck pos3d + pos2dzuerst ausgewertet wird, bevor er berücksichtigt, "wo das Ergebnis angewendet wird", weiß der Compiler nicht, welche Umwandlung Sie als Codierer ausführen möchten.

Wenn Sie sich in Richtung 3D bewegen möchten, können Sie Folgendes schreiben:

transform.position = pos3d + ( Vector3 )pos2d;

und das Problem ist weg, wie jetzt klar ist: Verschieben Sie zuerst pos2d in ein anderes Objekt vom Typ Vector3 und dann die Summe von Vector3 + Vector3. Vorausgesetzt, es gibt diese statische Signatur

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

verfügbar, dass eine ohne Mehrdeutigkeit verwendet wird.

Analyse 2

Auf der anderen Seite, wenn Sie es tun

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

Es gibt keine Mehrdeutigkeit: In der ersten Zeile wird ein Vektor3 einem Vektor3 zugewiesen (keine Zweifel).

Die zweite Zeile entspricht

transform.position = transform.position + pos2d;

Mit der Besonderheit wird die transform.position nur einmal ausgewertet, und daher wird der Typ berücksichtigt, wie Sie auf dieser Microsoft-Seite über den +=Operator sehen können:

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

Außerdem heißt es: "Der Operator + = kann nicht direkt überladen werden, aber benutzerdefinierte Typen können den Operator + überladen (siehe Operator)." so sollten wir denken , das Vector3ist +=Betreiber wie von Microsoft beschrieben wirkt , wo es heißt:

x += y

ist äquivalent zu

x = x + y

außer dass x nur einmal ausgewertet wird. Die Bedeutung des Operators + hängt von den Typen von x und y ab (Addition für numerische Operanden, Verkettung für Zeichenfolgenoperanden usw.).

Wir können also sicher sein, dass der zweite Ansatz den Operanden + der Vector3Klasse aufruft , der die Signatur hat:

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

Es gibt also keinen anderen Weg, dies zu erreichen, als die pos2d dank einer impliziten versteckten Besetzung, die keine andere Form haben kann, in einen Vector3 umzuwandeln.

Hoffe zu helfen !!


Bearbeiten

In Unity 5.0.1f1 Personalmit MonoDevelop-Unit 4.0.1, wie Alex M. sagt, die Linien:

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

Wirf immer noch den Fehler "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)'"

Das + = verwendet also wirklich beide Signaturen

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

Unabhängig von der Tatsache, dass bereits bekannt ist, "wo" das Ergebnis platziert werden soll (ich denke, weil die Ausgabe eines Vector2 an das Ziel (Vector3) umgewandelt werden kann und wenn diese Umwandlung wahrscheinlich nicht möglich wäre, würde der Compiler wahrscheinlich den mit dem richtigen auswählen Ausgabetyp).

Danke für den Punkt Alex M.

Xavi Montero
quelle
+=funktioniert auch nicht, es ist immer noch ein Vector3+ Vector2. Siehe meine Antwort.
Richtig, deine positiv bewertet, soll meine bearbeiten.
Xavi Montero
Nur bearbeitet, um Ihren Kommentar aufzunehmen.
Xavi Montero
transform.position + = pos2d wird kompiliert. Ich werde morgen genauer sein (könnte nur ein Versionsfehler sein)
SteakOverflow
Nach den Änderungen habe ich mich in der Sequenz verlaufen ... also ... pos3d += pos2d(gemäß Ihrer bearbeiteten Frage) schlägt fehl, wird aber transform.position += pos2dkompiliert (gemäß Ihrem Kommentar oben)? Würde seltsam erscheinen wie es .positionist Vector3- Ich kann nicht klar erkennen, ob Sie das meinen.
Xavi Montero