En Unity, ¿por qué agregar un Vector2 y un Vector3 es ambiguo pero la asignación no lo es?

11

Dados los siguientes dos vectores:

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

Esta línea es ambigua:

v3 += v2; // Unity reports dimension ambiguity

mientras que esta tarea no es:

v3 = v2; // Unity assigns despite different dimensions

¿Por qué es esto?

Filete
fuente
Entonces, muchas gracias a Anko y Xavi Montero por las excelentes respuestas. Tratando de reproducir el problema, me di cuenta de que mi pregunta debería cambiarse. El hecho sucede cuando se asigna un Vector2 a transform.position para que transform.position = a + b; donde AMBOS a y b son compilaciones Vector2 correctamente y asigna x e y! En cambio, no funciona cuando cambio la línea a transform.position + = a; // o b Estoy usando Unity 5.0.0f y el script está adjunto a un elemento de la interfaz de usuario (Imagen) que no afecta al compilador, pero puede ser información importante para que pueda reproducir el escenario.
SteakOverflow
Entonces, chicos, díganme qué hacer. ¿Cambiamos la pregunta y sus respuestas en consecuencia o comenzamos una nueva?
SteakOverflow
Vector3 + Vector2 y Vector3 + = Vector2 nunca funcionará sin importar lo que desee, porque ambos se pueden convertir implícitamente en el otro y debe emitir explícitamente de acuerdo con lo que desea hacer. Vector3 = Vector2 funciona porque no hay ambigüedad. No veo la necesidad de cambiar o publicar una nueva pregunta.
Estoy diciendo que cambie la pregunta porque el caso es ligeramente diferente de lo que describí, lo que podría frenar el flujo de su respuesta.
SteakOverflow
No te preocupes, nada se rompe.

Respuestas:

12

Mensaje de problema completo:

error CS0121: la llamada es ambigua entre los siguientes métodos o propiedades: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

La unidad proporcionó una forma de convertir implícitamente Vector3a a Vector2y viceversa. Esto provoca una ambigüedad en su caso porque se pueden aplicar ambos operadores +.

Transmita su Vector2a Vector3explícitamente en esa operación, para que el compilador sepa usar UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Si tiene curiosidad, los documentos de Microsoft para ese error específico están aquí .


Editar después de su edición:

Vec3 += Vec2es ambiguo por la misma razón descrita anteriormente. Imagina Vec3 += Vec2estar de hecho Vec3 = Vec3 + Vec2. Vec3 + Vec2puede producir tanto Vector2y Vector3como respuesta debido a las conversiones implícitas, es por eso que debe especificar lo que desea.

Vec3 = Vec2no es ambiguo porque Vec2 se convierte implícitamente en ay Vector3luego se asigna al Vec3 inicial. Por lo tanto, toda la operación es realmente Vector3 = Vector3sin tener que lanzar Vec2 Vector3manualmente.


fuente
Por lo tanto, Unity asume que quiero que se asignen las x e y de mi Vector3 a partir de las x e y de mi Vector2 y que mi z esté establecida en 0f. ¿Derecho?
SteakOverflow
Sí, imagine que Vec3 = Vec2 es equivalente a Vec3 = (Vector3) Vec2. No necesita emitir manualmente porque en ese caso no puede ser otra cosa que eso.
Sí, en realidad mi pregunta podría titularse algo así como "¿Por qué no necesito enviar a Vector3 cuando asigno un Vector2". No soy el mejor en titulación y elaboración de preguntas perfectas: / Gracias, Alex. Mi curiosidad ha sido (sobre) satisfecha.
SteakOverflow
3

Permítanme cambiar el nombre de los vars (para mayor claridad):

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

Responder

Es por la sección pos3d + pos2dde la línea. Esta parte es realmente ambigua mientras que la +=no lo es. Permítanme aclarar por qué uno y por qué el otro.

Análisis 1

En esta linea

transform.position = pos3d + pos2d;

el compilador primero intenta evaluar la expresión pos3d + pos2dantes de continuar, independientemente de dónde se colocará el resultado.

Para hacerlo, el sistema primero intenta encontrar cualquier función estática pública que agregue un Vector3 más un Vector2, por ejemplo, esta posible firma:

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

o por ejemplo esta posible firma:

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

Sin embargo, no hay ninguna de esas firmas en la API, por lo que el compilador intenta "transmitir" parámetros a firmas conocidas.

Luego, el compilador encuentra esas dos firmas potenciales:

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

Estos están documentados aquí: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html y aquí: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Entonces hay dos posibilidades:

Por lo tanto, dado que ambas versiones son posibles, pos2d se puede convertir en un Vector3 y pos3d se puede convertir en un Vector2, el compilador busca posibles formas de compilar el mismo código fuente (siempre y cuando se instalen automáticamente las versiones ocultas).

Es posible convertir pos3d en Vector2 y continuar con la segunda firma, o bien transmitir pos2d en Vector3 y continuar con la primera firma.

Como la expresión pos3d + pos2dse evalúa primero, antes de tomar en cuenta "dónde se aplicará el resultado", entonces el compilador no sabe qué conversión le gustaría, como codificador, realizar.

Si quieres moverte hacia 3D, puedes escribir esto:

transform.position = pos3d + ( Vector3 )pos2d;

y el problema desapareció, como ahora está claro: primero mueva pos2d a otro objeto de tipo Vector3, luego haga la suma de Vector3 + Vector3. Siempre que exista esta firma estática

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

disponible, ese será usado sin ambigüedad alguna.

Análisis 2

Por otro lado, cuando lo haces

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

no hay ambigüedad: la primera línea asigna un Vector3 a un Vector3 (sin dudas).

La segunda línea es equivalente a

transform.position = transform.position + pos2d;

Con la particularidad, transform.position solo se evalúa una vez y, por lo tanto, el tipo se tiene en cuenta, como puede ver en esta página de Microsoft sobre el +=operador:

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

Además, dice "El operador + = no se puede sobrecargar directamente, pero los tipos definidos por el usuario pueden sobrecargar el operador + (ver operador)". entonces deberíamos pensar que el operador del Vector3s +=actúa como lo describe microsoft donde dice:

x += y

es equivalente a

x = x + y

excepto que x solo se evalúa una vez. El significado del operador + depende de los tipos de x e y (suma para operandos numéricos, concatenación para operandos de cadena, etc.).

así que podemos estar seguros de que el segundo enfoque invoca el operando + de la Vector3clase, que tiene la firma:

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

así que no hay otra forma de lograr esto que no sea convertir la pos2d en un Vector3 gracias a un elenco oculto implícito que no puede ser de ninguna otra forma.

Espero ayudar!


Editar

En Unity 5.0.1f1 Personalcon MonoDevelop-Unit 4.0.1, como dice Alex M., las líneas:

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

todavía emite el error "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)'"

entonces realmente el + = está usando ambas firmas

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

independientemente del hecho de saber "dónde" se colocará el resultado (supongo que la salida de un Vector2 se puede convertir al destino (Vector3) y si ese lanzamiento no es posible, tal vez, el compilador elegiría el que tenga el adecuado Tipo de salida).

Gracias por el punto Alex M.

Xavi Montero
fuente
+=tampoco funciona, sigue siendo un Vector3+ Vector2. Mira mi respuesta.
Correcto, votó el suyo, editará el mío.
Xavi Montero
Recién editado para incorporar su comentario.
Xavi Montero
transform.position + = pos2d está compilando. Seré más preciso mañana (podría ser solo un error de versión)
SteakOverflow
Después de las ediciones, me perdí en la secuencia ... entonces ... pos3d += pos2d(según su pregunta editada) falla pero se transform.position += pos2dcompila (según su comentario anterior) ?? Parece extraño como .positiones Vector3: no puedo ver claramente si eso es lo que quieres decir.
Xavi Montero