Dans Unity, pourquoi l'ajout d'un Vector2 et d'un Vector3 est-il ambigu alors que l'affectation ne l'est pas?

11

Étant donné les deux vecteurs suivants:

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

Cette ligne est ambiguë:

v3 += v2; // Unity reports dimension ambiguity

alors que cette mission n'est pas:

v3 = v2; // Unity assigns despite different dimensions

Pourquoi est-ce?

SteakOverflow
la source
Merci beaucoup à Anko et Xavi Montero pour les bonnes réponses. En essayant de reproduire le problème, j'ai réalisé que ma question devait être modifiée. Le fait se produit lors de l'attribution d'un Vector2 à transform.position de sorte que transform.position = a + b; où les deux a et b sont Vector2 se compile correctement et il affecte x et y! Au lieu de cela, cela ne fonctionne pas lorsque je change la ligne pour transformer.position + = a; // ou b J'utilise Unity 5.0.0f et le script est attaché à un élément d'interface utilisateur (Image) qui n'affecte pas le compilateur mais peut être une information importante pour vous de reproduire le scénario.
SteakOverflow
Alors, vous me dites quoi faire. Pouvons-nous changer la question et vos réponses en conséquence ou devons-nous en commencer une nouvelle?
SteakOverflow
Vector3 + Vector2 et Vector3 + = Vector2 ne fonctionnera jamais, peu importe ce que vous voulez, car les deux peuvent être implicitement convertis en l'autre et vous devez effectuer un cast explicite en fonction de ce que vous voulez faire. Vector3 = Vector2 fonctionne car il n'y a pas d'ambiguïté. Je ne vois pas la nécessité de changer ou de poster une nouvelle question.
Je dis de changer la question parce que le cas est légèrement différent de ce que j'ai décrit, ce qui pourrait freiner le flux de votre réponse.
SteakOverflow
Ne t'inquiète pas, rien ne se casse.

Réponses:

12

Message de problème complet:

erreur CS0121: l'appel est ambigu entre les méthodes ou propriétés suivantes: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

Unity a fourni un moyen de convertir implicitement a Vector3en a Vector2et vice-versa. Cela provoque une ambiguïté dans votre cas car les deux opérateurs + peuvent être appliqués.

Castez votre Vector2vers Vector3explicitement dans cette opération, afin que le compilateur sache comment l'utiliser UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Si vous êtes curieux, les documents de Microsoft pour cette erreur spécifique sont ici .


Modifier après votre modification:

Vec3 += Vec2est ambigu pour la même raison que celle décrite ci-dessus. Imaginez Vec3 += Vec2être en fait Vec3 = Vec3 + Vec2. Vec3 + Vec2peut donner les deux Vector2et Vector3comme réponse en raison de conversions implicites, c'est pourquoi vous devez spécifier ce que vous voulez.

Vec3 = Vec2n'est pas ambigu car Vec2 est implicitement converti en a Vector3puis affecté au Vec3 initial. Donc, toute l'opération est vraiment Vector3 = Vector3sans que vous ayez à transtyper Vec2 Vector3manuellement.


la source
Donc, Unity suppose que je veux que mes x et y de Vector3 soient attribués à partir de x et y de Vector2 et que mon z soit défini sur 0f. Droite?
SteakOverflow
Oui, imaginez que Vec3 = Vec2 soit équivalent à Vec3 = (Vector3) Vec2. Vous n'avez pas besoin de lancer manuellement car il ne peut pas être autre chose que cela dans ce cas.
Oui, en fait ma question pourrait être intitulée quelque chose comme "Pourquoi n'ai-je pas besoin de caster en Vector3 lors de l'attribution d'un Vector2". Je ne suis pas le meilleur pour titrer et créer des questions parfaites: / Merci Alex. Ma curiosité a été (trop) satisfaite.
SteakOverflow
3

Permettez-moi de renommer les vars (pour plus de clarté):

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

Réponse

C'est à cause de la section pos3d + pos2dde la ligne. Cette partie est vraiment ambiguë alors que ce +=n'est pas le cas. Permettez-moi de clarifier pourquoi l'un et pourquoi l'autre.

Analyse 1

Dans cette ligne

transform.position = pos3d + pos2d;

le compilateur essaie d'abord d'évaluer l'expression pos3d + pos2davant de continuer, quel que soit l'endroit où le résultat va être placé.

Pour ce faire, le système essaie d'abord de trouver toute fonction statique publique qui ajoute un Vector3 plus un Vector2, par exemple cette signature possible:

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

ou par exemple cette signature possible:

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

Néanmoins, il n'y a aucune de ces signatures dans l'API, donc le compilateur essaie de «transtyper» les paramètres en signatures connues.

Ensuite, le compilateur trouve ces deux signatures potentielles:

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

Ceux-ci sont documentés ici: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html et ici: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Il y a donc deux possibilités:

Donc, comme les deux castings sont possibles, pos2d peut être casté en un Vector3 et pos3d est castabale en un Vector2, le compilateur trouve ensuite des façons possibles de compiler le même code source (à condition que des castings cachés automatiques soient en place).

Il est possible de transposer pos3d dans Vector2 et de procéder à la deuxième signature, ou de transposer pos2d dans Vector3 et de procéder à la première signature.

Comme l'expression pos3d + pos2dest évaluée en premier, avant de prendre en considération "où le résultat sera appliqué", alors le compilateur ne sait pas quel casting souhaitez-vous, en tant que codeur, qu'il souhaite effectuer.

Si vous voulez vous diriger vers la 3D, vous pouvez écrire ceci:

transform.position = pos3d + ( Vector3 )pos2d;

et le problème a disparu, comme maintenant il est clair: déplacez d'abord pos2d dans un autre objet de type Vector3, puis faites la somme de Vector3 + Vector3. Pourvu qu'il y ait cette signature statique

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

disponible, celui-ci sera utilisé sans aucune ambiguïté.

Analyse 2

D'un autre côté, quand vous faites

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

il n'y a pas d'ambiguïté: la première ligne assigne un Vector3 à un Vector3 (pas de doute).

La deuxième ligne équivaut à

transform.position = transform.position + pos2d;

avec la particularité que transform.position n'est évalué qu'une seule fois, et donc le type est pris en considération, comme vous pouvez le voir dans cette page Microsoft sur l' +=opérateur:

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

Il indique en outre "L'opérateur + = ne peut pas être surchargé directement, mais les types définis par l'utilisateur peuvent surcharger l'opérateur + (voir opérateur)." nous devons donc penser que le Vector3l » +=opérateur agit comme décrit par Microsoft où il est dit:

x += y

est équivalent à

x = x + y

sauf que x n'est évalué qu'une seule fois. La signification de l'opérateur + dépend des types de x et y (ajout pour les opérandes numériques, concaténation pour les opérandes de chaîne, etc.).

nous pouvons donc être sûrs que la deuxième approche invoque l'opérande + de la Vector3classe, qui a la signature:

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

il n'y a donc pas d'autre moyen d'y parvenir que de convertir le pos2d en un Vector3 grâce à une distribution cachée implicite qui ne peut pas être d'une autre forme.

Au plaisir d'aider !!


Éditer

En Unity 5.0.1f1 Personalavec MonoDevelop-Unit 4.0.1, comme Alex M. dit, les lignes:

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

jette toujours l'erreur "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)'"

donc vraiment le + = utilise les deux signatures

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

indépendamment du fait de savoir déjà "où" le résultat doit être placé (je suppose que la sortie d'un Vector2 peut être casté vers la destination (Vector3) et si ce cast n'était pas possible probablement, peut-être, le compilateur choisirait celui avec le bon le type de sortie).

Merci pour le point Alex M.

Xavi Montero
la source
+=ne fonctionne pas non plus, c'est toujours un Vector3+ Vector2. Voir ma réponse.
À droite, le vôtre a voté, modifiera le mien.
Xavi Montero
Juste édité pour incorporer votre commentaire.
Xavi Montero
transform.position + = pos2d est en cours de compilation. Je serai plus précis demain (peut-être juste un bug de version)
SteakOverflow
Après les modifications, je me suis perdu dans la séquence ... alors ... pos3d += pos2d(selon votre question modifiée) échoue mais transform.position += pos2dcompile (selon votre commentaire ci-dessus) ?? Semble bizarre que .positionest Vector3- ne peut pas voir clairement si c'est ce que vous sens.
Xavi Montero