No Unity, por que adicionar um Vector2 e um Vector3 é ambíguo, mas atribuir não é?

11

Dados os dois vetores a seguir:

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

Esta linha é ambígua:

v3 += v2; // Unity reports dimension ambiguity

embora esta tarefa não seja:

v3 = v2; // Unity assigns despite different dimensions

Por que é isso?

SteakOverflow
fonte
Então, muito obrigado a Anko e Xavi Montero pelas ótimas respostas. Tentando reproduzir o problema, percebi que minha pergunta deveria ser alterada. O fato está acontecendo ao atribuir um Vector2 a transform.position para que transform.position = a + b; onde AMB e A são Vector2 compila corretamente e atribui x e y! Em vez disso, ele não funciona quando altero a linha para transform.position + = a; // ou b Estou usando o Unity 5.0.0f e o script é anexado a um elemento da interface do usuário (Imagem) que não afeta o compilador, mas pode ser uma informação importante para você reproduzir o cenário.
SteakOverflow
Então vocês me dizem o que fazer. Devemos mudar a pergunta e suas respostas de acordo ou começaremos uma nova?
SteakOverflow
Vetor3 + Vetor2 e Vetor3 + = Vetor2 nunca funcionarão, não importa o que você queira, porque ambos podem ser implicitamente convertidos no outro e você precisa converter explicitamente de acordo com o que deseja fazer. Vector3 = Vector2 funciona porque não há ambiguidade. Não vejo a necessidade de alterar ou postar uma nova pergunta.
Estou dizendo para mudar a pergunta porque o caso é um pouco diferente do que descrevi, o que pode impedir o fluxo da sua resposta.
SteakOverflow
Nah não se preocupe, nada quebra.

Respostas:

12

Mensagem completa:

erro CS0121: A chamada é ambígua entre os seguintes métodos ou propriedades: UnityEngine.Vector2.operator +(UnityEngine.Vector2, UnityEngine.Vector2)' andUnityEngine.Vector3.operator + (UnityEngine.Vector3, UnityEngine.Vector3) '

A unidade forneceu uma maneira de converter implicitamente a Vector3para a Vector2e vice-versa. Isso causa uma ambiguidade no seu caso, porque os dois operadores podem ser aplicados.

Elenco sua Vector2a um Vector3explicitamente nessa operação, de modo que o compilador sabe usar UnityEngine.Vector3.operator +(UnityEngine.Vector3, UnityEngine.Vector3).

Se você estiver curioso, os documentos da Microsoft para esse erro específico estão aqui .


Edite após sua edição:

Vec3 += Vec2é ambígua pelo mesmo motivo descrito acima. Imagine Vec3 += Vec2estar de fato Vec3 = Vec3 + Vec2. Vec3 + Vec2pode render tanto Vector2e Vector3como resposta devido a conversões implícitas, é por isso que você precisa especificar o que deseja.

Vec3 = Vec2não é ambíguo porque o Vec2 é implicitamente convertido em a Vector3e depois atribuído ao Vec3 inicial. Portanto, toda a operação é realmente Vector3 = Vector3sem que você precise converter o Vec2 Vector3manualmente.


fonte
Portanto, o Unity assume que eu quero que os x e y do meu Vector3 sejam atribuídos a partir dos x e y do meu Vector2 e meu z seja definido como 0f. Direita?
SteakOverflow
Sim, imagine Vec3 = Vec2 sendo equivalente a Vec3 = (Vetor3) Vec2. Você não precisa transmitir manualmente, porque, nesse caso, não pode ser outra coisa além disso.
Sim, na verdade minha pergunta poderia ser intitulada algo como "Por que não preciso transmitir para o Vector3 ao atribuir um Vector2". Não sou o melhor em titular e elaborar perguntas perfeitas: / Obrigado, Alex. Minha curiosidade foi (mais) satisfeita.
SteakOverflow
3

Deixe-me renomear os vars (para maior clareza):

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

Responda

É por causa da seção pos3d + pos2dda linha. Esta parte é realmente ambígua enquanto a +=não é. Deixe-me esclarecer por que um e por que o outro.

Análise 1

Nesta linha

transform.position = pos3d + pos2d;

o compilador primeiro tenta avaliar a expressão pos3d + pos2dantes de continuar, independentemente de onde o resultado será colocado.

Para fazer isso, o sistema primeiro tenta encontrar qualquer função estática pública que adicione um Vector3 mais um Vector2, por exemplo, esta possível assinatura:

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

ou, por exemplo, esta possível assinatura:

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

No entanto, não há nenhuma dessas assinaturas na API; portanto, o compilador tenta "converter" parâmetros em assinaturas conhecidas.

Em seguida, o compilador encontra essas duas assinaturas em potencial:

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

Eles estão documentados aqui: http://docs.unity3d.com/ScriptReference/Vector3-operator_add.html e aqui: http://docs.unity3d.com/ScriptReference/Vector2-operator_add.html

Portanto, existem duas possibilidades:

Portanto, como ambas as peças fundidas são possíveis, o pos2d pode ser fundido em um Vector3 e o pos3d é fundido em um Vector2, o compilador encontra maneiras possíveis de compilar o mesmo código fonte (desde que as fundições ocultas automáticas estejam no lugar).

É possível converter pos3d no vetor2 e prosseguir com a segunda assinatura, ou converter pos2d no vetor3 e prosseguir com a primeira assinatura.

Como a expressão pos3d + pos2dé avaliada primeiro, antes de levar em consideração "onde o resultado será aplicado", o compilador não sabe qual conversão você - como codificador - gostaria de executar.

Se você deseja avançar para o 3D, pode escrever o seguinte:

transform.position = pos3d + ( Vector3 )pos2d;

e o problema desapareceu, como agora está claro: primeiro mova pos2d para outro objeto do tipo Vector3, depois faça a soma de Vector3 + Vector3. Desde que exista essa assinatura estática

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

disponível, esse será usado sem nenhuma ambiguidade.

Análise 2

Por outro lado, quando você faz

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

não há ambiguidade: a primeira linha atribui um Vector3 a um Vector3 (sem dúvida).

A segunda linha é equivalente a

transform.position = transform.position + pos2d;

com a particularidade, o transform.position é avaliado apenas uma vez e, portanto, o tipo é levado em consideração, como você pode ver nesta página da Microsoft sobre o +=operador:

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

Além disso, diz "O operador + = não pode ser sobrecarregado diretamente, mas os tipos definidos pelo usuário podem sobrecarregar o operador + (consulte operador)". por isso, devemos pensar que o Vector3's +=operador atua como descrito pela Microsoft, onde ele diz:

x += y

é equivalente a

x = x + y

exceto que x é avaliado apenas uma vez. O significado do operador + depende dos tipos de xey (adição para operandos numéricos, concatenação para operandos de cadeia de caracteres e assim por diante).

para ter certeza de que a segunda abordagem chama o operando + da Vector3classe, que tem a assinatura:

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

portanto, não há outra maneira de conseguir isso além da conversão do pos2d em um Vector3, graças a uma conversão oculta implícita que não pode ter outra forma.

Espero ajudar !!


Editar

Em Unity 5.0.1f1 Personalcom MonoDevelop-Unit 4.0.1, como Alex M. diz, as linhas:

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

ainda lança o erro "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)'"

então realmente o + = está usando as duas assinaturas

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

independentemente do fato de já saber "onde" o resultado deve ser colocado (acho que porque a saída de um Vector2 é passível de conversão para o destino (Vector3)) e se essa conversão não foi possível, provavelmente, talvez, o compilador escolheria aquele com a devida tipo de saída).

Obrigado pelo ponto Alex M.

Xavi Montero
fonte
+=também não funciona, ainda é um Vector3+ Vector2. Veja minha resposta.
Certo, com o seu voto positivo, deve editar o meu.
Xavi Montero
Apenas editado para incorporar seu comentário.
Xavi Montero
transform.position + = pos2d está compilando. Eu estarei amanhã mais preciso (pode ser apenas um bug versão)
SteakOverflow
Após as edições, eu me perdi na sequência ... então ... pos3d += pos2d(conforme sua pergunta editada) falha, mas transform.position += pos2dcompila (conforme seu comentário acima) ?? Parece estranho como .positioné Vector3- Não é possível ver claramente se é isso que você está querendo dizer.
Xavi Montero